feat: Implement task editing functionality and improve UI components
- Added EditTaskModal component for editing tasks. - Integrated EditTaskModal into TaskTab for task editing. - Refactored AddInternsDialog for better UI and functionality. - Created AddInternsToProjects component for adding interns to projects. - Enhanced CreateProjectDialog and CreateTaskDialog with improved styling. - Introduced EditSubmissionTask component for editing submission tasks. - Added ProtectedRoutes for route protection based on user roles. - Implemented API utility for handling requests with authorization. - Removed obsolete InternRoute and MentorRoute files. - Updated global CSS styles for better responsiveness and aesthetics.
This commit is contained in:
@@ -1,18 +0,0 @@
|
||||
// App.tsx / router.tsx
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
import HomeInternPage from "../internify/intern/HomeInternPage";
|
||||
import {InternLayout} from "../internify/mentor/layout";
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "/",
|
||||
element: <InternLayout />,
|
||||
children: [
|
||||
{ path: "home", element: <HomeInternPage /> },
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
export default function App() {
|
||||
return <RouterProvider router={router} />;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// App.tsx / router.tsx
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
import HomeMentorPage from "../internify/mentor/HomePage";
|
||||
import {MentorLayout} from "../internify/mentor/layout";
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "/",
|
||||
element: <MentorLayout />,
|
||||
children: [
|
||||
{ path: "home", element: <HomeMentorPage /> },
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
export default function App() {
|
||||
return <RouterProvider router={router} />;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { Outlet, Navigate } from "react-router-dom";
|
||||
|
||||
interface PrivateRouteProps {
|
||||
allowedRoles?: ("admin" | "intern" | "mentor")[];
|
||||
}
|
||||
|
||||
// Helper function untuk decode payload JWT tanpa library external
|
||||
const decodeJWT = (token: string) => {
|
||||
try {
|
||||
const base64Url = token.split(".")[1]; // Ambil bagian payload (segmen kedua)
|
||||
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
||||
const jsonPayload = decodeURIComponent(
|
||||
window
|
||||
.atob(base64)
|
||||
.split("")
|
||||
.map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
|
||||
.join("")
|
||||
);
|
||||
return JSON.parse(jsonPayload);
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const ProtectedRoutes = ({ allowedRoles }: PrivateRouteProps) => {
|
||||
// 1. Ambil token dari cookie
|
||||
const token = document.cookie
|
||||
.split("; ")
|
||||
.find((row) => row.startsWith("token="))
|
||||
?.split("=")[1];
|
||||
|
||||
// Jika tidak punya token, tendang ke login admin awal
|
||||
if (!token) {
|
||||
return <Navigate to="/login-admin" replace />;
|
||||
}
|
||||
|
||||
// 2. Decode token untuk mendapatkan role asli dari Backend
|
||||
const decoded = decodeJWT(token);
|
||||
const userRole = decoded?.role as "admin" | "intern" | "mentor" | undefined;
|
||||
|
||||
// Jika token corrupt atau tidak bisa di-decode, hanguskan dan tendang ke login
|
||||
if (!userRole) {
|
||||
return <Navigate to="/login-admin" replace />;
|
||||
}
|
||||
|
||||
// 3. Periksa hak akses role terhadap halaman yang dituju
|
||||
if (allowedRoles && !allowedRoles.includes(userRole)) {
|
||||
// Jika role tidak diizinkan, kembalikan ke base dashboard masing-masing role
|
||||
if (userRole === "admin") return <Navigate to="/dashboard" replace />;
|
||||
if (userRole === "mentor") return <Navigate to="/mentor" replace />;
|
||||
if (userRole === "intern") return <Navigate to="/intern" replace />;
|
||||
}
|
||||
|
||||
// Jika lolos seleksi, render komponen di dalamnya
|
||||
return <Outlet />;
|
||||
};
|
||||
|
||||
export default ProtectedRoutes;
|
||||
@@ -0,0 +1,20 @@
|
||||
import axios from "axios";
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL,
|
||||
});
|
||||
|
||||
// Otomatis tempel Token Bearer di setiap request ke BE
|
||||
api.interceptors.request.use((config) => {
|
||||
const token = document.cookie
|
||||
.split("; ")
|
||||
.find((row) => row.startsWith("token="))
|
||||
?.split("=")[1];
|
||||
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
export default api;
|
||||
Reference in New Issue
Block a user