diff --git a/src/App.tsx b/src/App.tsx index 35c8ea7..a6b06fc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -33,7 +33,7 @@ import { InternLayout, MentorLayout } from "./Pages/Internify/layout"; import ProjectsPage from "./Pages/Internify/intern/ProjectsPage"; import SertificatePage from "./Pages/Internify/intern/SertificatePage"; import ProjectDetailPage from "./Pages/Internify/intern/ProjectDetailPage"; -import HomeMentorPage from "./Pages/Internify/mentor/HomePage"; +import HomeMentorPage from "./Pages/Internify/mentor/HomeMentorPage"; import MentorProjectsPage from "./Pages/Internify/mentor/BaseProjectsPage"; import MentorCertificatePage from "./Pages/Internify/mentor/CertificatePage"; import MentorInternPage from "./Pages/Internify/mentor/InternsPage"; @@ -88,30 +88,37 @@ function App() { } /> - }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + {/* Intern only */} + }> + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + - }> - } /> - } /> - } /> - } /> - } /> - } /> - }/> - } /> - } /> - } /> + {/* Mentor only */} + }> + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + ); diff --git a/src/Layout/Header-internify.tsx b/src/Layout/Header-internify.tsx index f17c057..553e2f7 100644 --- a/src/Layout/Header-internify.tsx +++ b/src/Layout/Header-internify.tsx @@ -9,7 +9,7 @@ export default function Header({ toggleSidebar }: { toggleSidebar: () => void })
Quick answers to common questions about the Internify LMS platform. @@ -28,22 +36,25 @@ export default function FAQPage() {
- {faq.answer} -
Memuat FAQ...
+ {item.jawaban} +
HUMIC LMS PORTAL @@ -112,6 +129,7 @@ export default function InternifyLogin() { Sign In diff --git a/src/Pages/internify/SettingsPage.tsx b/src/Pages/internify/SettingsPage.tsx index 1eab2a1..01284d1 100644 --- a/src/Pages/internify/SettingsPage.tsx +++ b/src/Pages/internify/SettingsPage.tsx @@ -1,30 +1,72 @@ -import { useState } from "react"; - -// Mock Data Profile awal -const mockProfileData = { - fullName: "JonathanKristina", - email: "JonathanKristina@gmail.com", - bio: "UIUX holic" -}; +import { useState, useEffect } from "react"; +import api from "../../lib/api"; export default function SettingsContent() { - const [formData, setFormData] = useState(mockProfileData); + const [formData, setFormData] = useState({ + fullName: "", + email: "", + bio: "" + }); + + const [loading, setLoading] = useState(true); + const [saving, setSaving] = useState(false); + const [successMsg, setSuccessMsg] = useState(""); + const [errorMsg, setErrorMsg] = useState(""); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await api.patch("/auth-api/update-profile"); + const data = response.data.data; + setFormData({ + fullName: data.full_name || "", + email: data.email || "", + bio: data.professional_bio || "", + }); + } catch (err) { + console.error("Failed to fetch profile:", err) + } finally { + setLoading(false); + } + }; + fetchData(); + }, []); const handleChange = (e: React.ChangeEvent) => { const { name, value } = e.target; setFormData((prev) => ({ ...prev, [name]: value })); }; - const handleSaveChanges = (e: React.FormEvent) => { + const handleSaveChanges = async (e: React.FormEvent) => { e.preventDefault(); - // Simulasi penyimpanan data sukses - alert("Changes saved successfully!"); - console.log("Saved Data:", formData); + setSuccessMsg(""); + setErrorMsg(""); + setSaving(true); + + try { + await api.patch("/auth-api/update-profile", { + full_name: formData.fullName, + email: formData.email, + professional_bio: formData.bio, + }); + setSuccessMsg("Profile updated successfully!"); + } catch (err: any) { + setErrorMsg(err?.response?.data?.message || "Failed to save changes."); + } finally { + setSaving(false); + } }; - // Mendapatkan inisial huruf pertama untuk avatar profile gambar const initialLetter = formData.fullName ? formData.fullName.charAt(1).toUpperCase() : "U"; + if (loading) { + return ( + + Loading profile... + + ); + } + return ( @@ -38,7 +80,7 @@ export default function SettingsContent() { {/* White Card Container */} - + {/* Card Header */} Profile Information @@ -49,7 +91,7 @@ export default function SettingsContent() { {/* Card Body & Form */} - + {/* Profile Photo Display Row */} @@ -67,7 +109,7 @@ export default function SettingsContent() { {/* Grid Inputs (Full Name & Email Address) */} - + {/* Field: Full Name */} @@ -114,13 +156,25 @@ export default function SettingsContent() { + {successMsg && ( + + {successMsg} + + )} + {errorMsg && ( + + {errorMsg} + + )} + {/* Form Action Footer Row */} - Save Changes + {saving ? "Saving..." : "Save Changes"} diff --git a/src/Pages/internify/intern/ForumTab.tsx b/src/Pages/internify/intern/ForumTab.tsx index 4ee64c1..ace03e0 100644 --- a/src/Pages/internify/intern/ForumTab.tsx +++ b/src/Pages/internify/intern/ForumTab.tsx @@ -1,24 +1,43 @@ -import type { Project } from '../../../lib/mockProjects'; +import { useParams } from 'react-router-dom'; import ProjectTimeline from './components/ProjectTimeline'; import TaskCard from './components/ProjectTaskCard'; import HeroProject from './components/Hero-project'; +import { useProjectTasks } from '../../../hooks/useTasks'; +import type { Project } from '../../../types/project.types'; export default function ForumTab({ project }: { project: Project }) { + const { slug } = useParams<{ slug: string }>(); + const { tasks, loading, error } = useProjectTasks(slug ?? ""); return ( {/* Hero banner */} - + + + {/* Loading */} + {loading && ( + + {[...Array(3)].map((_, i) => ( + + ))} + + )} + + {/* Error */} + {error && {error}} {/* Timeline + Task list */} - - - + + + - - - {project.tasks.map((task, idx) => ( - - ))} + + {tasks.length === 0 ? ( + Belum ada task. + ) : ( + tasks.map((task) => ( + + )) + )} diff --git a/src/Pages/internify/intern/HomeInternPage.tsx b/src/Pages/internify/intern/HomeInternPage.tsx index 082f9ca..8212928 100644 --- a/src/Pages/internify/intern/HomeInternPage.tsx +++ b/src/Pages/internify/intern/HomeInternPage.tsx @@ -9,14 +9,14 @@ export default function HomeInternPage() { - + - + - + diff --git a/src/Pages/internify/intern/ParticipantTab.tsx b/src/Pages/internify/intern/ParticipantTab.tsx index b7d13dd..d851ac6 100644 --- a/src/Pages/internify/intern/ParticipantTab.tsx +++ b/src/Pages/internify/intern/ParticipantTab.tsx @@ -1,44 +1,75 @@ -import type { Project, Intern } from '../../../lib/mockData'; +import { useParams } from 'react-router-dom'; +import { } from '../../../hooks/useProjects'; +import type { Project } from '../../../types/project.types'; export default function ParticipantsTab({ project }: { project: Project }) { + const { slug } = useParams<{ slug: string }>(); + const { interns, loading, error } = useProjectInterns(slug ?? ""); + return ( {/* Mentor */} - - Mentor - - + Mentor + - - {project.mentor} - + {project.admin.profile_picture ? ( + + ) : ( + + )} + {project.admin.full_name} {/* Members */} - - Members - - {project.interns.map((intern: Intern, idx: number) => ( + Members + + {loading && ( + + {[...Array(3)].map((_, i) => ( + + ))} + + )} + + {error && {error}} + + {!loading && !error && interns.map((intern, idx) => ( - - {intern.name} - + {intern.avatar ? ( + + ) : ( + + )} + + {intern.full_name} + {intern.email} + - - {intern.role} - + {intern.kelompok_peminatan} ))} + + {!loading && !error && interns.length === 0 && ( + Belum ada members. + )} ); diff --git a/src/Pages/internify/intern/ProjectDetailPage.tsx b/src/Pages/internify/intern/ProjectDetailPage.tsx index 9d21cc0..7b97d40 100644 --- a/src/Pages/internify/intern/ProjectDetailPage.tsx +++ b/src/Pages/internify/intern/ProjectDetailPage.tsx @@ -1,24 +1,19 @@ import { useState } from 'react'; import { useParams } from 'react-router-dom'; -import { mockProjects } from '../../../lib/mockProjects'; +// import { useProjectDetail } from '../../../hooks/useProjectDetail'; +import { useProjectDetail } from '../../../hooks/useProjects'; import ForumTab from './ForumTab'; import ParticipantsTab from './ParticipantTab'; -const toSlug = (name: string) => name.toLowerCase().replace(/\s+/g, '-'); - export default function ProjectDetailPage() { - const { slug } = useParams<{ slug: string }>(); + const { slug } = useParams<{ slug: string }>(); + const { project, loading, error } = useProjectDetail(slug ?? ""); const [activeTab, setActiveTab] = useState<'forum' | 'participants'>('forum'); - const project = mockProjects.find((p) => toSlug(p.name) === slug); - - if (!project) { - return ( - - Project tidak ditemukan. - - ); - } + // Fallback sederhana + if (loading) return Memuat project...; + if (error) return {error}; + if (!project) return Project tidak ditemukan.; const tabClass = (tab: string) => `pr-0 py-2.5 mr-7 text-sm bg-transparent border-0 cursor-pointer transition-colors duration-150 border-b-2 ${activeTab === tab @@ -30,7 +25,7 @@ export default function ProjectDetailPage() { {/* Tabs */} - + setActiveTab('forum')}> Forum diff --git a/src/Pages/internify/intern/ProjectsPage.tsx b/src/Pages/internify/intern/ProjectsPage.tsx index ebdb018..7733cf0 100644 --- a/src/Pages/internify/intern/ProjectsPage.tsx +++ b/src/Pages/internify/intern/ProjectsPage.tsx @@ -1,7 +1,19 @@ import ProjectCard from './components/ProjectsCard' -import { mockProjects } from '../../../lib/mockData' +import { useMyProjects } from '../../../hooks/useProjects'; export default function ProjectsPage() { + const { projects, loading, error } = useMyProjects(); + + if (loading) return ( + + {[...Array(3)].map((_, i) => ( + + ))} + + ); + + if (error) return {error}; + return ( @@ -10,8 +22,8 @@ export default function ProjectsPage() { {/* Grid card */} - - {mockProjects.map(project => ( + + {projects.map(project => ( ))} diff --git a/src/Pages/internify/intern/TaskSubmission.tsx b/src/Pages/internify/intern/TaskSubmission.tsx index 9bd5b76..f149654 100644 --- a/src/Pages/internify/intern/TaskSubmission.tsx +++ b/src/Pages/internify/intern/TaskSubmission.tsx @@ -2,71 +2,68 @@ import { useParams, useSearchParams } from "react-router-dom"; import { FileText, Info } from "lucide-react"; import TaskFormFile from "./components/TaskForm-file"; import TaskFormLink from "./components/TaskForm-link"; -import { mockProjects } from "../../../lib/mockProjects"; - -const toSlug = (name: string) => name.toLowerCase().replace(/\s+/g, '-'); +import { useTaskDetail } from "../../../hooks/useTasks"; export default function TaskSubmission() { const [searchParams] = useSearchParams(); - const { slug, TaskSlug } = useParams<{ slug: string; TaskSlug: string }>(); + const { slug, taskSlug } = useParams<{ slug: string; taskSlug: string }>(); + const submissionType = (searchParams.get("type") ?? "file") as "file_upload" | "url_link"; + const { task, loading, error } = useTaskDetail(taskSlug!, slug); - const submissionType = (searchParams.get("type") ?? "file") as "file" | "link"; + const formatDeadline = (dateStr: string) => + new Date(dateStr).toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" }); + const formatTime = (dateStr: string) => + new Date(dateStr).toLocaleTimeString("id-ID", { hour: "2-digit", minute: "2-digit" }); - const project = mockProjects.find((p) => toSlug(p.name) === slug); - const task = project?.tasks.find((t) => toSlug(t.title) === TaskSlug); - const handleFileSubmit = (files: File[]) => { - const fileNames = files.map(f => f.name).join(', '); - console.log(`Submitting Files for Project ${slug}:`, fileNames); - alert(`File ${fileNames} berhasil dikirim!`); - }; - - const handleLinkSubmit = (link: string) => { - console.log(`Submitting Link for Project ${slug}:`, link); - alert(`Link berhasil dikirim!`); - }; + if (loading) return ( + + {[...Array(3)].map((_, i) => ( + + ))} + + ); + if (error) return {error}; + if (!task) return null; return ( - - {/* Header Card */} - - - - - {task?.title} - - - Due {task?.deadline.label} at {task?.deadline.time} - - + + + + {task.title} + + Due {formatDeadline(task.deadline_at)} at {formatTime(task.deadline_at)} + - {/* Task Description Card */} - Task Description - - {task?.description} - + Task Description + {task.description} - {/* Submit Area Card */} - - - Save Changes + + + Submit Task - {/* Render form sesuai tipe dari query param */} - {submissionType === "file" ? ( - + {submissionType === "file_upload" ? ( + ) : ( - + )} - {/* Info Box */} - - + + Once submitted, your work will be locked for mentor review. You can request a re-submission if needed. diff --git a/src/Pages/internify/intern/components/CertificateAvailabe.tsx b/src/Pages/internify/intern/components/CertificateAvailabe.tsx index 983f4c3..028f62d 100644 --- a/src/Pages/internify/intern/components/CertificateAvailabe.tsx +++ b/src/Pages/internify/intern/components/CertificateAvailabe.tsx @@ -34,19 +34,11 @@ export default function CertificateAvailable({ data }: { data: CertificateData } {[ { label: "Nama Program", value: certificate.programName }, { label: "Durasi", value: certificate.duration }, - { - label: "Nilai Akhir", - value: ( - - {certificate.finalScore}/100 ({certificate.grade}) - - ), - }, { label: "Status", value: ( - {certificate.status} + VERIFIED ), }, diff --git a/src/Pages/internify/intern/components/HomeCalendar.tsx b/src/Pages/internify/intern/components/HomeCalendar.tsx index f629998..5ac0110 100644 --- a/src/Pages/internify/intern/components/HomeCalendar.tsx +++ b/src/Pages/internify/intern/components/HomeCalendar.tsx @@ -1,7 +1,6 @@ import { useState, useEffect } from 'react' import { ChevronLeft, ChevronRight } from 'lucide-react' -import { DEADLINES } from '../../../../lib/mockDeadline' - +import { useMyTasks } from '../../../../hooks/useProjects'; const DAY_LABELS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] const MONTH_NAMES = [ @@ -18,7 +17,13 @@ function getFirstDayOfMonth(year: number, month: number) { } const HomeCalendar = () => { - const [today, setToday] = useState(new Date()) + const [today, setToday] = useState(new Date()); + const { tasks } = useMyTasks(); + + const DEADLINES = tasks.map(task => ({ + date: new Date(task.deadline_at), + label: task.title, + })); useEffect(() => { const interval = setInterval(() => { @@ -89,13 +94,13 @@ const HomeCalendar = () => { } return ( - + {/* Header */} - + {MONTH_NAMES[currentMonth]} {currentYear} - + { {/* Divider */} - + {/* Upcoming Deadlines */} - + Upcoming Deadlines {upcomingDeadlines.length > 0 ? ( @@ -172,12 +177,12 @@ const HomeCalendar = () => { {upcomingDeadlines.map((d, i) => ( - {d.label} + {d.label} ))} ) : ( - No upcoming deadlines this month. + No upcoming deadlines this month. )} diff --git a/src/Pages/internify/intern/components/HomeHeader.tsx b/src/Pages/internify/intern/components/HomeHeader.tsx index 97c8483..d709627 100644 --- a/src/Pages/internify/intern/components/HomeHeader.tsx +++ b/src/Pages/internify/intern/components/HomeHeader.tsx @@ -1,12 +1,26 @@ +import { useState, useEffect } from "react"; +import api from "../../../../lib/api"; + const HomeHeader = () => { - const name = "Karina"; + const [name, setName] = useState(""); + + useEffect(() => { + api.get("/auth-api/me") + .then((res) => { + setName(res.data.data.full_name || res.data.data.nama_depan); + }) + .catch((err) => { + console.error("Failed to fetch user:", err); + }); +}, []); + return ( - Hi, {name}! + Hi, {name || "..."}! - ) -} + ); +}; -export default HomeHeader +export default HomeHeader; \ No newline at end of file diff --git a/src/Pages/internify/intern/components/HomeProjectList.tsx b/src/Pages/internify/intern/components/HomeProjectList.tsx index 3f7ca94..ebbdfd2 100644 --- a/src/Pages/internify/intern/components/HomeProjectList.tsx +++ b/src/Pages/internify/intern/components/HomeProjectList.tsx @@ -1,31 +1,42 @@ -import { useNavigate } from 'react-router-dom' -import { mockProjects } from '../../../../lib/mockProjects' +import { useNavigate } from 'react-router-dom'; +import { useProjects } from '../../../../hooks/useProjects'; const toSlug = (name: string) => name.toLowerCase().replace(/\s+/g, '-'); const HomeProjectList = () => { const navigate = useNavigate(); + const { projects, loading, error } = useProjects(); + + if (loading) return ( + + {[...Array(3)].map((_, i) => ( + + ))} + + ); + + if (error) return {error}; + return ( - Projects + Projects - {mockProjects.map((project, index) => { - return ( - navigate(`/intern/projects/${toSlug(project.name)}`)} - className="flex items-center gap-4 border border-gray-200 rounded-lg px-4 py-3 hover:bg-gray-50 cursor-pointer transition-colors duration-150" - > - - - {project.name} - + {projects.map((project) => ( + navigate(`/intern/projects/${toSlug(project.project_name)}`)} + className="flex items-center gap-4 border border-card-outline rounded-lg px-4 py-3 hover:bg-gray-50 cursor-pointer transition-colors duration-150" + > + + + {project.project_name} + {project.status} - ) - })} + + ))} - ) -} + ); +}; -export default HomeProjectList \ No newline at end of file +export default HomeProjectList; \ No newline at end of file diff --git a/src/Pages/internify/intern/components/ProjectTaskCard.tsx b/src/Pages/internify/intern/components/ProjectTaskCard.tsx index 56a6bf6..299dd57 100644 --- a/src/Pages/internify/intern/components/ProjectTaskCard.tsx +++ b/src/Pages/internify/intern/components/ProjectTaskCard.tsx @@ -1,41 +1,43 @@ -import type { Task } from "../../../../lib/mockProjects"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; +import type { ProjectTask } from "../../../../types/task.types"; -const formatDate = (date: Date) => - new Date(date).toLocaleDateString('id-ID', { day: 'numeric', month: 'short', year: 'numeric' }); +const formatDate = (dateStr: string) => + new Date(dateStr).toLocaleDateString('id-ID', { day: 'numeric', month: 'short', year: 'numeric' }); -const toSlug = (name: string) => name.toLowerCase().replace(/\s+/g, '-'); +const formatTime = (dateStr: string) => + new Date(dateStr).toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit' }); -export default function TaskCard({ task, projectName }: { task: Task; projectName: string }) { +export default function TaskCard({ task }: { task: ProjectTask }) { const navigate = useNavigate(); - const toTaskSlug = (title: string) => title.toLowerCase().replace(/\s+/g, '-'); + const { slug } = useParams<{ slug: string }>(); return ( - + navigate(`/intern/projects/${slug}/${task.slug}?type=${task.submission_type}`)} + > - - Deadline : {formatDate(task.deadline.date)} at {task.deadline.time} + + Deadline : {formatDate(task.deadline_at)} at {formatTime(task.deadline_at)} {task.title} - + {task.description} - - Tipe Submission : {task.type === 'file' ? "File" : "Link"} + + Tipe Submission : {task.submission_type === 'file_upload' ? "File" : "Link"} - - {task.isSubmitted ? ( - - DONE - - ) : ( - navigate(`/intern/projects/${toSlug(projectName)}/${toTaskSlug(task.title)}?type=${task.type}`)}> - Add Submission - - )} + + + + + Add Submission + ); diff --git a/src/Pages/internify/intern/components/ProjectTimeline.tsx b/src/Pages/internify/intern/components/ProjectTimeline.tsx index a22313a..a2b0225 100644 --- a/src/Pages/internify/intern/components/ProjectTimeline.tsx +++ b/src/Pages/internify/intern/components/ProjectTimeline.tsx @@ -1,50 +1,43 @@ -import type { Task } from "../../../../lib/mockProjects"; -import { ArrowDownNarrowWide } from "lucide-react"; +import type { ProjectTask } from "../../../../types/project.types"; -const formatDate = (date: Date) => - new Date(date).toLocaleDateString('id-ID', { day: 'numeric', month: 'short', year: 'numeric' }); +const formatDate = (dateStr: string) => + new Date(dateStr).toLocaleDateString('id-ID', { day: 'numeric', month: 'short' }); -export default function ProjectTimeline({ tasks }: { tasks: Task[] }) { - const today = new Date(); - today.setHours(0, 0, 0, 0); +export default function ProjectTimeline({ tasks }: { tasks: ProjectTask[] }) { + const today = new Date(); + today.setHours(0, 0, 0, 0); - return ( - - - - Timeline - - - + return ( + + + Timeline + + + {tasks.map((task) => { + const d = new Date(task.deadline_at); + d.setHours(0, 0, 0, 0); + const isToday = d.getTime() === today.getTime(); + const isPast = d < today; + const active = isToday || isPast; - - {tasks.map((task, idx) => { - const d = new Date(task.deadline.date); - d.setHours(0, 0, 0, 0); - const isToday = d.getTime() === today.getTime(); - const isPast = d < today; - const active = isToday || isPast; - - return ( - - {/* Dot */} - - - {isToday ? 'Hari ini' : formatDate(task.deadline.date)} - - - {task.title} - - - ); - })} - - - ); + return ( + + {/* Dot */} + + + {isToday ? 'Hari ini' : formatDate(task.deadline_at)} {/* ← format ISO string */} + + + {task.title} + + + ); + })} + + + ); } \ No newline at end of file diff --git a/src/Pages/internify/intern/components/ProjectsCard.tsx b/src/Pages/internify/intern/components/ProjectsCard.tsx index f028575..2cbea7c 100644 --- a/src/Pages/internify/intern/components/ProjectsCard.tsx +++ b/src/Pages/internify/intern/components/ProjectsCard.tsx @@ -1,53 +1,54 @@ -import { useNavigate } from 'react-router-dom' +import { useNavigate } from 'react-router-dom'; +import * as LucideIcons from 'lucide-react'; +import type { LucideProps } from 'lucide-react'; +import type { Project } from '../../../../types/project.types'; -const toSlug = (name: string) => name.toLowerCase().replace(/\s+/g, '-'); +const getDynamicIcon = (iconName: string) => { + const formatted = iconName.charAt(0).toUpperCase() + iconName.slice(1); + const Icon = (LucideIcons as unknown as Record>)[formatted]; + return Icon ?? LucideIcons.FolderOpen; +}; -interface ProjectCardProps { - id: number | string - name: string - mentor: string - avatarUrl?: string - thumbnailUrl?: string - progress: number - tasksDone: number - tasksTotal: number -} +const ProjectCard = (project: Project) => { + const navigate = useNavigate(); + const Icon = getDynamicIcon(project.project_icon); -const ProjectCard = ({ - name, - mentor, - avatarUrl, - thumbnailUrl, - progress, - tasksDone, - tasksTotal, -}: ProjectCardProps) => { - const navigate = useNavigate() + + const tasksDone = -1; + const tasksTotal = project.total_tasks; return ( - + navigate(`/intern/projects/${project.slug}`)} + className=" rounded-xl overflow-hidden shadow-sm border border-gray-100 w-full flex flex-col cursor-pointer hover:shadow-md transition-shadow duration-200" + > {/* Thumbnail */} - - {thumbnailUrl && ( - - )} + + {/* Content */} - + - {name} + {/* Project Name */} + + {project.project_name} + {/* Mentor */} - {avatarUrl ? ( - + {project.admin.profile_picture ? ( + ) : ( )} - {mentor} + {project.admin.email} {/* Progress bar */} @@ -55,18 +56,18 @@ const ProjectCard = ({ 0 ? `${(tasksDone / tasksTotal) * 100}%` : '0%' }} /> - + {tasksDone}/{tasksTotal} + {/* Button */} navigate(`/intern/projects/${toSlug(name)}`)} className="bg-red-600 hover:bg-red-700 text-white text-xs font-medium py-1.5 px-3 rounded-xl transition-colors" > View Project @@ -74,7 +75,7 @@ const ProjectCard = ({ - ) -} + ); +}; -export default ProjectCard \ No newline at end of file +export default ProjectCard; \ No newline at end of file diff --git a/src/Pages/internify/intern/components/SidebarIntern.tsx b/src/Pages/internify/intern/components/SidebarIntern.tsx index 4517631..6f1c2f6 100644 --- a/src/Pages/internify/intern/components/SidebarIntern.tsx +++ b/src/Pages/internify/intern/components/SidebarIntern.tsx @@ -1,16 +1,18 @@ import { useNavigate, useLocation } from 'react-router-dom'; -import { Home, FolderKanban, Award, Settings, HelpCircle, LogOut, ChevronRight, X } from 'lucide-react'; +import { Award, Settings, HelpCircle, X } from 'lucide-react'; +import { GrHomeRounded } from "react-icons/gr"; +import { MdOutlineAssignment, MdLogout } from "react-icons/md"; const navItems = [ - { label: "Home", icon: Home, path: "/intern" }, - { label: "List Projects", icon: FolderKanban, path: "/intern/projects" }, + { label: "Home", icon: GrHomeRounded, path: "/intern" }, + { label: "List Projects", icon: MdOutlineAssignment, path: "/intern/projects" }, { label: "Certificates", icon: Award, path: "/intern/certificates" }, ]; const prefItems = [ { label: "Settings", icon: Settings, path: "/intern/settings" }, { label: "FAQ", icon: HelpCircle, path: "/intern/faq" }, - { label: "Logout", icon: LogOut, path: "/login-internify", danger: true }, + { label: "Logout", icon: MdLogout, path: "/login-internify", danger: true, isLogout: true }, ]; interface SidebarProps { @@ -24,11 +26,18 @@ export default function SidebarIntern({ isOpen, closeSidebar }: SidebarProps) { const handleNav = (path: string) => { navigate(path); - closeSidebar(); // Otomatis tutup sidebar setelah klik menu di HP + closeSidebar(); + }; + + const handleLogout = () => { + document.cookie = "token=; path=/; max-age=86400; SameSite=Strict"; + + closeSidebar(); + navigate("/login-internify", { replace: true }); }; return ( -
+ {successMsg} +
+ {errorMsg} +
{error}
Belum ada task.
Belum ada members.
Memuat project...
Project tidak ditemukan.
- {task?.description} -
{task.description}
+ +
Once submitted, your work will be locked for mentor review. You can request a re-submission if needed.
+
Upcoming Deadlines
No upcoming deadlines this month.
{project.name}
{project.project_name}
{project.status}
{name}
+ {project.project_name} +