Skip to content

Commit 74a220f

Browse files
committed
Add Authentication and show profile
1 parent 2947a9e commit 74a220f

File tree

15 files changed

+889
-408
lines changed

15 files changed

+889
-408
lines changed

frontend/index.html

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,13 @@
4242
<script src="src/assets/stisla/js/stisla.js"></script>
4343
<script src="src/assets/stisla/js/scripts.js"></script>
4444
<script>
45-
window.onbeforeunload = function () {
46-
window.scrollTo(5, 75);
47-
};
45+
pathname = window.location.pathname;
46+
if (pathname == "/login" || pathname == "/register") {
47+
} else {
48+
window.onbeforeunload = function () {
49+
window.scrollTo(5, 75);
50+
};
51+
}
4852
</script>
4953
<script src="src/assets/stisla/js/custom.js"></script>
5054
</body>

frontend/src/App.jsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,7 @@ import Footer from "./components/Footer";
66
export default function App() {
77
return (
88
<>
9-
<div className="main-wrapper container">
10-
<div className="navbar-bg"></div>
11-
<Navbar />
12-
<Sidebar />
13-
<Router />
14-
<Footer />
15-
</div>
9+
<Router />
1610
</>
1711
);
1812
}

frontend/src/components/Footer.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React from "react";
2-
import { Link } from "react-router-dom";
32

43
export default function Footer() {
54
return (

frontend/src/components/Navbar.jsx

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,40 @@
11
import React from "react";
2-
import Case from "./Case";
3-
import NavLink from "./NavLink";
4-
import { Link } from "react-router-dom";
2+
import { Link, useNavigate } from "react-router-dom";
3+
import { useEffect, useState } from "react";
4+
5+
import axios from "axios";
56

67
export default function Navbar() {
8+
const [user, setUser] = useState({});
9+
const baseURL = "http://127.0.0.1:8000/api";
10+
11+
const navigate = useNavigate();
12+
13+
useEffect(() => {
14+
document.title = "Dashboard";
15+
if (!token) {
16+
navigate("/");
17+
}
18+
fetchData();
19+
}, []);
20+
21+
const token = localStorage.getItem("token");
22+
23+
const fetchData = async () => {
24+
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
25+
await axios.get(`${baseURL}/user`).then((response) => {
26+
setUser(response.data);
27+
});
28+
};
29+
30+
const logoutHandler = async () => {
31+
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
32+
await axios.post(`${baseURL}/logout`).then(() => {
33+
localStorage.removeItem("token");
34+
navigate("/");
35+
});
36+
};
37+
738
return (
839
<nav className="navbar navbar-expand-lg main-navbar">
940
<Link to="/" className="navbar-brand sidebar-gone-hide">
@@ -27,7 +58,7 @@ export default function Navbar() {
2758
className="nav-link dropdown-toggle nav-link-lg nav-link-user"
2859
>
2960
<div className="d-sm-none d-lg-inline-block">
30-
Hi, Fahmi Ibrahim
61+
Hi, {user.name}
3162
</div>
3263
</a>
3364
<div className="dropdown-menu dropdown-menu-right">
@@ -40,20 +71,9 @@ export default function Navbar() {
4071
>
4172
<i className="far fa-user"></i> Profile
4273
</a>
43-
<a
44-
href="features-activities.html"
45-
className="dropdown-item has-icon"
46-
>
47-
<i className="fas fa-bolt"></i> Activities
48-
</a>
49-
<a
50-
href="features-settings.html"
51-
className="dropdown-item has-icon"
52-
>
53-
<i className="fas fa-cog"></i> Settings
54-
</a>
5574
<div className="dropdown-divider"></div>
5675
<a
76+
onClick={logoutHandler}
5777
href="#"
5878
className="dropdown-item has-icon text-danger"
5979
>

frontend/src/components/Router.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ import Dashboard from "../pages/Dashboard";
44
import AdvancedFeature from "../pages/AdvancedFeature";
55
import GeneralFeature from "../pages/GeneralFeature";
66
import Product from "../pages/products/Product";
7+
import Login from "../pages/Auth/Login";
8+
import Register from "../pages/Auth/Register";
79
export default function Router() {
810
return (
911
<Routes>
10-
<Route path="/" element={<Dashboard />} exact />
12+
<Route path="/" element={<Login />} exact />
13+
<Route path="/register" element={<Register />} exact />
14+
<Route path="/dashboard" element={<Dashboard />} exact />
1115
<Route path="/general-feature" element={<GeneralFeature />} exact />
1216
<Route
1317
path="/advanced-feature"

frontend/src/components/Sidebar.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ export default function Sidebar() {
3636
<ul className="navbar-nav">
3737
<li
3838
className={`nav-item ${
39-
location.pathname === "/" ? "active" : ""
39+
location.pathname === "/dashboard" ? "active" : ""
4040
}`}
4141
>
42-
<NavLink href="/">
42+
<NavLink href="/dashboard">
4343
<i className="far fa-home"></i>
4444
<span>Dashboard</span>
4545
</NavLink>
Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,39 @@
11
import React from "react";
22
import Case from "../components/Case";
33
import { useEffect } from "react";
4+
import MainLayout from "./Layout/MainLayout";
45

56
export default function AdvancedFeature() {
67
useEffect(() => {
78
document.title = "Advanced Feature";
89
}, []);
910

1011
return (
11-
<Case>
12-
<div className="section-header px-4 tw-rounded-none tw-shadow-md tw-shadow-gray-200 lg:tw-rounded-lg">
13-
<h1 className="mb-1 tw-text-lg">Advanced Feature</h1>
14-
</div>
12+
<MainLayout>
13+
<Case>
14+
<div className="section-header px-4 tw-rounded-none tw-shadow-md tw-shadow-gray-200 lg:tw-rounded-lg">
15+
<h1 className="mb-1 tw-text-lg">Advanced Feature</h1>
16+
</div>
1517

16-
<div className="section-body">
17-
<div className="card">
18-
<div className="card-body px-0">
19-
<h3>Tabel Advanced Feature</h3>
20-
<p className="px-4">
21-
Lorem ipsum dolor, sit amet consectetur adipisicing
22-
elit. Tenetur at asperiores earum officiis
23-
reiciendis necessitatibus eos! Nam harum tempore
24-
molestias aliquam, qui excepturi similique expedita
25-
vitae perferendis voluptatum laudantium vero
26-
deleniti laboriosam assumenda impedit repellendus
27-
eum, commodi totam! Molestiae ducimus placeat totam
28-
nesciunt, perspiciatis dolor mollitia ut saepe cum
29-
sunt?
30-
</p>
18+
<div className="section-body">
19+
<div className="card">
20+
<div className="card-body px-0">
21+
<h3>Tabel Advanced Feature</h3>
22+
<p className="px-4">
23+
Lorem ipsum dolor, sit amet consectetur
24+
adipisicing elit. Tenetur at asperiores earum
25+
officiis reiciendis necessitatibus eos! Nam
26+
harum tempore molestias aliquam, qui excepturi
27+
similique expedita vitae perferendis voluptatum
28+
laudantium vero deleniti laboriosam assumenda
29+
impedit repellendus eum, commodi totam!
30+
Molestiae ducimus placeat totam nesciunt,
31+
perspiciatis dolor mollitia ut saepe cum sunt?
32+
</p>
33+
</div>
3134
</div>
3235
</div>
33-
</div>
34-
</Case>
36+
</Case>
37+
</MainLayout>
3538
);
3639
}

frontend/src/pages/Auth/Login.jsx

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import React, { useEffect, useState } from "react";
2+
3+
import { Link, useNavigate } from "react-router-dom";
4+
import Swal from "sweetalert2";
5+
import withReactContent from "sweetalert2-react-content";
6+
7+
import axios from "axios";
8+
9+
export default function Register() {
10+
const baseURL = "http://127.0.0.1:8000/api";
11+
12+
const navigate = useNavigate();
13+
const MySwal = withReactContent(Swal);
14+
15+
useEffect(() => {
16+
document.title = "Login";
17+
if (localStorage.getItem("token")) {
18+
//redirect page dashboard
19+
navigate("/dashboard");
20+
}
21+
}, []);
22+
23+
const [formData, setFormData] = useState({
24+
email: "",
25+
password: "",
26+
});
27+
28+
const initialFormData = {
29+
email: "",
30+
password: "",
31+
};
32+
33+
const [formErrors, setFormErrors] = useState({
34+
email: "",
35+
password: "",
36+
});
37+
38+
const validateForm = () => {
39+
let errors = {};
40+
let formIsValid = true;
41+
42+
// Validate input description
43+
if (!formData.email) {
44+
formIsValid = false;
45+
errors.email = "Email is required";
46+
}
47+
48+
// Validate input description
49+
if (!formData.password) {
50+
formIsValid = false;
51+
errors.password = "Password is required";
52+
}
53+
54+
setFormErrors(errors);
55+
return formIsValid;
56+
};
57+
58+
const handleInputChange = (event) => {
59+
const { name, value } = event.target;
60+
setFormData({ ...formData, [name]: value });
61+
};
62+
63+
const loginHandler = (e) => {
64+
e.preventDefault();
65+
66+
if (validateForm()) {
67+
axios
68+
.post(`${baseURL}/login`, formData, {
69+
headers: {
70+
"Content-Type": "application/json",
71+
},
72+
})
73+
.then((response) => {
74+
if (response.status === 200) {
75+
localStorage.setItem("token", response.data.token);
76+
MySwal.fire({
77+
title: "Success!",
78+
text: "Login successfully",
79+
icon: "success",
80+
timer: 1500,
81+
}).then(() => {
82+
navigate("/dashboard");
83+
});
84+
} else {
85+
throw new Error("Network response was not ok");
86+
}
87+
})
88+
.catch((error) => {
89+
console.error("Error:", error);
90+
});
91+
}
92+
};
93+
94+
return (
95+
<div className="row">
96+
<div className="col-12 col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-6 offset-lg-3 col-xl-4 offset-xl-4 tw-mt-10">
97+
<div className="card card-primary">
98+
<div className="card-header">
99+
<h4>Login</h4>
100+
</div>
101+
102+
<div className="card-body">
103+
<form onSubmit={loginHandler}>
104+
<div className="form-group">
105+
<label htmlFor="email">Email</label>
106+
<input
107+
type="email"
108+
name="email"
109+
id="email"
110+
className={`form-control ${
111+
formErrors.email ? "is-invalid" : ""
112+
}`}
113+
value={formData.email || ""}
114+
onChange={handleInputChange}
115+
/>
116+
{formErrors.email && (
117+
<div className="invalid-feedback">
118+
{formErrors.email}
119+
</div>
120+
)}
121+
</div>
122+
123+
<div className="form-group">
124+
<label htmlFor="password">Password</label>
125+
<input
126+
type="password"
127+
name="password"
128+
id="password"
129+
className={`form-control ${
130+
formErrors.password ? "is-invalid" : ""
131+
}`}
132+
value={formData.password || ""}
133+
onChange={handleInputChange}
134+
/>
135+
{formErrors.password && (
136+
<div className="invalid-feedback">
137+
{formErrors.password}
138+
</div>
139+
)}
140+
</div>
141+
<div className="form-group">
142+
<button
143+
type="submit"
144+
className="btn btn-lg btn-block tw-bg-blue-500"
145+
>
146+
Login
147+
</button>
148+
</div>
149+
</form>
150+
</div>
151+
</div>
152+
<div className="mt-5 text-muted text-center">
153+
Don't have an account?{" "}
154+
<Link to="/register">Create One</Link>
155+
</div>
156+
<div className="simple-footer">
157+
Copyright &copy; Stisla 2023
158+
</div>
159+
</div>
160+
</div>
161+
);
162+
}

0 commit comments

Comments
 (0)