Hari 21: Deploy Netlify

Hari 21: Deploy Netlify

30 Hari Javascript

·

6 min read

Persiapan Deploy

Setelah latihan kesegaran otak mari kita lanjut materi kembali, kita akan melakukan deploy ke https://www.netlify.com (tau kenapa?, iya benar GRATISSSSSS).

Sedikit kita lengkapi, untuk halaman login, silahkan buat file page/Login.js yang isinya seperti berikut.

import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { loginUser } from "../actions/user.action";

const Login = (props) => {
  const dispatch = useDispatch();
  const [user, updateUser] = useState({});

  const submitForm = (e) => {
    e.preventDefault();
    dispatch(loginUser(user));
  };

  return (
    <div className="page">
      <h1 className="page-title">Login 30 Hari Js</h1>

      <form className="login" onSubmit={(e) => submitForm(e)}>
        <label>Email</label>
        <input
          type="email"
          autoComplete={"false"}
          placeholder="email"
          onChange={(e) => {
            updateUser({ ...user, email: e.target.value });
          }}
        />

        <label>Password</label>
        <input
          type="password"
          autoComplete={"false"}
          placeholder="rahasia"
          onChange={(e) => {
            updateUser({ ...user, password: e.target.value });
          }}
        />

        <button type="submit" onClick={(e) => submitForm(e)}>
          Login
        </button>
      </form>
    </div>
  );
};

export default Login;

Ubah sedikit file user.action.js menjadi seperti berikut.

import axios from "axios";

const baseUrl = `https://warm-refuge-26108.herokuapp.com`;

export const getUsers = () => {
  return async (dispatch) => {
    dispatch({
      type: "GET_USER_REQUEST",
    });
    try {
      const result = await axios.get(baseUrl + `/users`);
      dispatch({
        type: "GET_USER_DONE",
        payload: result.data,
      });
    } catch (error) {
      dispatch({
        type: "GET_USER_ERROR",
      });
    }
  };
};

export const createUser = (data) => {
  return async (dispatch) => {
    try {
      const result = await axios.post(baseUrl + `/users`, data);
      return result;
    } catch (error) {
      dispatch({
        type: "GET_USER_ERROR",
      });
    }
  };
};

export const loginUser = (data) => {
  return async (dispatch) => {
    try {
      const result = await axios.post(baseUrl + `/users/login`, data);
      window.localStorage.setItem("token", result.data.token);

      if (result.data.token) {
        window.location.href = "/profile";
      }
      return result;
    } catch (error) {
      dispatch({
        type: "GET_USER_ERROR",
      });
    }
  };
};

export const profileUser = () => {
  return async (dispatch) => {
    dispatch({
      type: "GET_USER_REQUEST",
    });
    try {
      const result = await axios.get(baseUrl + `/users/profile`, {
        headers: { token: window.localStorage.getItem("token") },
      });
      dispatch({
        type: "GET_USER_DETAIL_DONE",
        payload: result.data,
      });
    } catch (error) {
      dispatch({
        type: "GET_USER_ERROR",
      });
    }
  };
};

Ubah juga file user.reducer.js, dan menjadi seperti berikut.

const initialState = {
  data: [],
  isError: false,
  isLoading: false,
  detail: null,
};

export default (state = initialState, action) => {
  switch (action.type) {
    case "GET_USER_REQUEST":
      return {
        ...state,
        isError: false,
        isLoading: true,
      };
    case "GET_USER_DONE":
      return {
        ...state,
        data: action.payload,
        isError: false,
        isLoading: false,
      };
    case "GET_USER_DETAIL_DONE":
      return {
        ...state,
        detail: action.payload,
        isError: false,
        isLoading: false,
      };
    case "GET_USER_ERROR":
      return {
        ...state,
        isError: true,
        isLoading: false,
      };
    default:
      return state;
  }
};

Tambahkan file page/Profile.js, yang isinya seperti berikut.

import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { profileUser } from "../actions/user.action";

const Profile = (props) => {
  const dispatch = useDispatch();
  const usersData = useSelector((state) => state.users);

  useEffect(() => {
    dispatch(profileUser());
  }, []);

  if (usersData.detail === null) {
    return <h1>Loading...</h1>;
  }

  return (
    <div className="page">
      <h1 className="page-title">My Profile</h1>

      <div className="profile">
        <div className="avatar">
          <img src={usersData.detail.picture} />
        </div>
        <div className="profile-detail">
          <div>
            <h3> {usersData.detail.name} </h3>
            <hr />
            <span> {usersData.detail.label} </span>

            <p style={{ marginTop: "3rem" }}> {usersData.detail.phone} </p>
            <p style={{ marginTop: "1rem" }}> {usersData.detail.email} </p>
            <p style={{ marginTop: "1rem" }}> {usersData.detail.website} </p>

            <p style={{ marginTop: "3rem" }}>
              Summary: {usersData.detail.summary}{" "}
            </p>
          </div>
        </div>
      </div>
    </div>
  );
};

export default Profile;

Ubah file RouterApp.js untuk mengubah menu sehingga kode menjadi seperti berikut.

import React, { Component, Fragment } from "react";
import { BrowserRouter, Switch, Route, Link } from "react-router-dom";

import Home from "./pages/Home";
import About from "./pages/About";
import Profile from "./pages/Profile";
import Register from "./pages/Register";
import Login from "./pages/Login";

class RouterApp extends Component {
  state = {
    token: null,
  };

  componentDidMount() {
    const token = window.localStorage.getItem("token");
    this.setState({ token });
  }

  render() {
    return (
      <BrowserRouter>
        <Fragment>
          <nav>
            <li>
              {" "}
              <Link to="/"> Home </Link>{" "}
            </li>
            <li>
              {" "}
              <Link to="/about"> About </Link>{" "}
            </li>
            {this.state.token === null && (
              <>
                <li>
                  {" "}
                  <Link to="/register"> Register </Link>{" "}
                </li>
                <li>
                  {" "}
                  <Link to="/login"> Login </Link>{" "}
                </li>
              </>
            )}
            {this.state.token !== null && (
              <>
                <li>
                  {" "}
                  <Link to="/profile"> Profile </Link>{" "}
                </li>
                <li>
                  {" "}
                  <a
                    href="#"
                    onClick={() => {
                      window.localStorage.removeItem("token");
                      window.location.href = "/";
                    }}
                  >
                    {" "}
                    Logout{" "}
                  </a>{" "}
                </li>
              </>
            )}
          </nav>

          <main>
            <Switch>
              <Route path="/" exact component={Home} />
              <Route path="/about" exact component={About} />
              {this.state.token !== null && (
                <Route path="/profile" exact component={Profile} />
              )}

              {this.state.token === null && (
                <>
                  <Route path="/register" exact component={Register} />
                  <Route path="/login" exact component={Login} />
                </>
              )}
            </Switch>
          </main>
        </Fragment>
      </BrowserRouter>
    );
  }
}

export default RouterApp;

Agar terlihat elegan tambahkan css pada file App.css yang isinya seperti berikut.

* {
  margin: 0;
  padding: 0;
  text-decoration: none;
  list-style: none;
}

body {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
  min-height: 100vh;
}

body nav {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: horizontal;
  -webkit-box-direction: normal;
  -ms-flex-direction: row;
  flex-direction: row;
  -webkit-box-pack: end;
  -ms-flex-pack: end;
  justify-content: flex-end;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  background: green;
  width: 100%;
  height: 40px;
}

body nav li {
  margin-right: 2rem;
}

body nav li a {
  color: white;
}

body nav li a:hover {
  color: yellow;
}

body main {
  padding: 3rem;
  color: gray;
}

.page {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
}

.page .page-title {
  color: black;
  text-align: center;
  margin-bottom: 1rem;
}

.page .users {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: start;
  -ms-flex-pack: start;
  justify-content: flex-start;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
}

.page .users .user {
  width: calc(calc(100% / 4) - 1rem);
  border: 1px green solid;
  margin-right: 1rem;
  margin-bottom: 1rem;
}

.page .users .user:nth-child(4n) {
  margin-right: 0;
}

.page .users .user .user-img-container img {
  width: 100%;
  -o-object-fit: cover;
  object-fit: cover;
}

.page .users .user .user-detail h3 {
  text-align: center;
  margin-top: 0.5rem;
  margin-bottom: 0.5rem;
}

.page .register,
.page .login {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
  min-width: 80%;
  margin: auto;
}

.page .register input,
.page .register textarea,
.page .login input,
.page .login textarea {
  margin-bottom: 1rem;
  padding: 0.5rem;
  outline: none;
}

.page .register input:focus,
.page .register textarea:focus,
.page .login input:focus,
.page .login textarea:focus {
  border: 1px solid green;
}

.page .register button,
.page .login button {
  color: #ffffff;
  background: green;
  padding: 0.5rem;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.page .register button:hover,
.page .login button:hover {
  background: #ffffff;
  color: green;
  border: 1px solid green;
}

.page .profile {
  width: 800px;
  min-width: 800px;
  max-width: 800px;
  padding: 2rem;
  border: 1px dotted black;
  margin: auto;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
}

.page .profile .avatar {
  margin-right: 1rem;
}

.page .profile .avatar img {
  width: 200px;
  border-radius: 50%;
  border: 1px solid red;
}

Source cek disini

Deploy

Pertama sekali, silahkan login ke netlify atau jika belum memiliki akun silahkan daftar terlebih dahulu.

https://raw.githubusercontent.com/AsrulLove/img-db/master/netlify.png

Kemudian pada proyek react build untuk di upload ke hosting dengan perintah berikut.

npm run build

Maka akan menghasilkan file compress dari proyek react tersebut.

https://raw.githubusercontent.com/AsrulLove/img-db/master/npm-run-build.png

Selanjutnya folder build drag ke netlify seperti berikut.

https://raw.githubusercontent.com/AsrulLove/img-db/master/dnd-netlify.png

Setelah di drag, maka netlify memberikan url yang dapat kita gunakan sebagai alamat web kita.

https://raw.githubusercontent.com/AsrulLove/img-db/master/url-netlify.png

Jika ingin mengubah url, netlify menyediakannya melalui custom domain.

https://raw.githubusercontent.com/AsrulLove/img-db/master/custom-url.png