diff --git a/src/App.tsx b/src/App.tsx index 811b90b..03cdb3a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -109,7 +109,7 @@ function App() { {/* Intern only */} }> - }> + }> } /> } /> } /> diff --git a/src/Pages/internify/Breadcumbs.tsx b/src/Pages/internify/Breadcumbs.tsx index 7495af1..761fae3 100644 --- a/src/Pages/internify/Breadcumbs.tsx +++ b/src/Pages/internify/Breadcumbs.tsx @@ -42,15 +42,15 @@ const NameInternBreadcrumb = ({ match }: BreadcrumbMatch) => { const breadcrumbRoutes = [ // --- AREA INTERN --- - { path: '/intern', breadcrumb: 'Home' }, - { path: '/intern/projects', breadcrumb: 'Projects' }, - { path: '/intern/projects/:slug', breadcrumb: ProjectBreadcrumb }, - { path: '/intern/projects/:slug/:taskSlug', breadcrumb: TaskBreadcrumb }, - { path: '/intern/certificates', breadcrumb: 'Certificates' }, - { path: '/intern/certificates/:slug', breadcrumb: CertBreadcrumb }, - { path: '/intern/faq', breadcrumb: 'FAQ' }, - { path: '/intern/notifications', breadcrumb: 'Notifications' }, - { path: '/intern/settings', breadcrumb: 'Settings' }, + { path: '/internship', breadcrumb: 'Home' }, + { path: '/internship/projects', breadcrumb: 'Projects' }, + { path: '/internship/projects/:slug', breadcrumb: ProjectBreadcrumb }, + { path: '/internship/projects/:slug/:taskSlug', breadcrumb: TaskBreadcrumb }, + { path: '/internship/certificates', breadcrumb: 'Certificates' }, + { path: '/internship/certificates/:slug', breadcrumb: CertBreadcrumb }, + { path: '/internship/faq', breadcrumb: 'FAQ' }, + { path: '/internship/notifications', breadcrumb: 'Notifications' }, + { path: '/internship/settings', breadcrumb: 'Settings' }, // --- AREA MENTOR / ADMIN --- { path: '/mentor', breadcrumb: 'Home' }, @@ -71,7 +71,7 @@ export default function Breadcrumbs(){ const breadcrumbs = useBreadcrumbs(breadcrumbRoutes); const location = useLocation(); - const rootPaths = ['/intern', '/mentor']; + const rootPaths = ['/internship', '/mentor']; const isOnRootPath = rootPaths.includes(location.pathname); const fixbreadcumbs = breadcrumbs.filter(({ match }) => { if (match.pathname === '/') return false; diff --git a/src/Pages/internify/LoginInternify.tsx b/src/Pages/internify/LoginInternify.tsx index 9e860b5..5b79567 100644 --- a/src/Pages/internify/LoginInternify.tsx +++ b/src/Pages/internify/LoginInternify.tsx @@ -1,20 +1,11 @@ import { useState, useEffect } from "react"; -import { decodeJWT } from "../utils/decodeJWT"; import logo from "../../assets/logo.png"; import { useNavigate } from "react-router-dom"; import { Mail, Lock, Eye, EyeOff } from 'lucide-react'; import { useLogin } from "../../hooks/useUser"; import { customToast } from "../utils/showToast"; import { CircleQuestionMark } from 'lucide-react'; - -interface JwtPayload { - id: string; - email: string; - role: "intern" | "mentor" | "admin"; - signature?: string | null; - iat: number; - exp: number; -} +import { decodeJWT } from "../utils/decodeJWT"; export default function InternifyLogin() { const navigate = useNavigate(); @@ -40,28 +31,18 @@ export default function InternifyLogin() { } const data = await login(email, password); + if (!data) return; - if (!data?.token) { - setError("Token login tidak ditemukan."); - return; - } + const { token } = data; + document.cookie = `token=${token}; path=/; SameSite=Strict`; - const decoded = decodeJWT(data.token); + const decoded = decodeJWT(token); const role = decoded?.role; - - if (!role) { - setError("Token login tidak valid."); - return; - } - - sessionStorage.setItem("token", data.token); - if (role === "intern") { - navigate("/intern", { replace: true }); + navigate("/internship"); } else if (role === "mentor" || role === "admin") { - navigate("/mentor", { replace: true }); + navigate("/mentor"); } else { - sessionStorage.removeItem("token"); setError("Role user tidak dikenali."); } }; diff --git a/src/Pages/internify/intern/ProjectsPage.tsx b/src/Pages/internify/intern/ProjectsPage.tsx index 0ade3f1..1136e05 100644 --- a/src/Pages/internify/intern/ProjectsPage.tsx +++ b/src/Pages/internify/intern/ProjectsPage.tsx @@ -22,7 +22,7 @@ export default function ProjectsPage() { if (projects.length === 0) { return ( -
+

Kamu belum tergabung ke projek apapun

diff --git a/src/Pages/internify/intern/components/SidebarIntern.tsx b/src/Pages/internify/intern/components/SidebarIntern.tsx index 04a8194..e5aab80 100644 --- a/src/Pages/internify/intern/components/SidebarIntern.tsx +++ b/src/Pages/internify/intern/components/SidebarIntern.tsx @@ -5,14 +5,14 @@ import { MdOutlineAssignment, MdLogout } from "react-icons/md"; import { HiUser } from "react-icons/hi2"; const navItems = [ - { label: "Home", icon: GrHomeRounded, path: "/intern" }, - { label: "List Projects", icon: MdOutlineAssignment, path: "/intern/projects" }, - { label: "Certificates", icon: Award, path: "/intern/certificates" }, + { label: "Home", icon: GrHomeRounded, path: "/internship" }, + { label: "List Projects", icon: MdOutlineAssignment, path: "/internship/projects" }, + { label: "Certificates", icon: Award, path: "/internship/certificates" }, ]; const prefItems = [ - { label: "Settings", icon: Settings, path: "/intern/settings" }, - { label: "FAQ", icon: HelpCircle, path: "/intern/faq" }, + { label: "Settings", icon: Settings, path: "/internship/settings" }, + { label: "FAQ", icon: HelpCircle, path: "/internship/faq" }, { label: "Logout", icon: MdLogout, path: "/login-internify", danger: true, isLogout: true }, ]; @@ -31,7 +31,7 @@ export default function SidebarIntern({ isOpen, closeSidebar }: SidebarProps) { }; const handleLogout = () => { - document.cookie = "token=; path=/; max-age=86400; SameSite=Strict"; + document.cookie = "token=; Max-Age=0; path=/; SameSite=Strict"; closeSidebar(); navigate("/login-internify", { replace: true }); diff --git a/src/Pages/internify/mentor/components/SidebarMentor.tsx b/src/Pages/internify/mentor/components/SidebarMentor.tsx index e246b4d..5630ffd 100644 --- a/src/Pages/internify/mentor/components/SidebarMentor.tsx +++ b/src/Pages/internify/mentor/components/SidebarMentor.tsx @@ -30,7 +30,7 @@ export default function SidebarMentor({ isOpen, closeSidebar }: SidebarProps) { }; const handleLogout = () => { - document.cookie = "token=; path=/; max-age=86400; SameSite=Strict"; + document.cookie = "token=; Max-Age=0; path=/; SameSite=Strict"; closeSidebar(); navigate("/login-internify", { replace: true }); diff --git a/src/Pages/utils/PrivateRoute.tsx b/src/Pages/utils/PrivateRoute.tsx index f10f5a5..5073ec7 100644 --- a/src/Pages/utils/PrivateRoute.tsx +++ b/src/Pages/utils/PrivateRoute.tsx @@ -10,7 +10,7 @@ const PrivateRoute = () => { useEffect(() => { if (!token) { - navigate("/humic-20242025-2"); + navigate("/login-admin"); } }, [navigate, token]); diff --git a/src/Pages/utils/ProtectedRoute.tsx b/src/Pages/utils/ProtectedRoute.tsx index 084f6af..4613231 100644 --- a/src/Pages/utils/ProtectedRoute.tsx +++ b/src/Pages/utils/ProtectedRoute.tsx @@ -1,42 +1,30 @@ import { Outlet, Navigate } from "react-router-dom"; -import { decodeJWT } from "./decodeJWT"; +import { decodeJWT } from "../utils/decodeJWT"; -type Role = "intern" | "admin" | "mentor"; -interface RouteProps { - allowedRoles?: Role[]; +interface PrivateRouteProps { + allowedRoles?: ("intern" | "admin" | "mentor")[]; } -interface JwtPayload { - id: string; - email: string; - role: "intern" | "mentor" | "admin"; - signature?: string | null; - iat: number; - exp: number; -} - -const ProtectedRoutes = ({ allowedRoles }: RouteProps) => { - const token = sessionStorage.getItem("token"); +const ProtectedRoutes = ({ allowedRoles }: PrivateRouteProps) => { + const token = document.cookie + .split("; ") + .find((row) => row.startsWith("token=")) + ?.split("=")[1]; if (!token) { return ; } - const decoded = decodeJWT(token); - const userRole = decoded?.role as Role | undefined; + const decoded = decodeJWT(token); + const userRole = decoded?.role as "intern" | "admin" | "mentor" | undefined; if (!userRole) { - sessionStorage.removeItem("token"); return ; } if (allowedRoles && !allowedRoles.includes(userRole)) { - return ( - - ); + if (userRole === "admin" || userRole === "mentor") return ; + if (userRole === "intern") return ; } return ; diff --git a/src/lib/api.ts b/src/lib/api.ts index fb099f1..83150f3 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -1,18 +1,20 @@ import axios from "axios"; -export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL; +export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL as string; const api = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, }); api.interceptors.request.use((config) => { - const token = sessionStorage.getItem("token"); + const token = document.cookie + .split("; ") + .find((row) => row.startsWith("token=")) + ?.split("=")[1]; if (token) { config.headers.Authorization = `Bearer ${token}`; } - return config; });