diff --git a/src/App.tsx b/src/App.tsx index 64e3914..d11a380 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -135,7 +135,7 @@ function App() { } /> } /> } /> - } /> + } /> diff --git a/src/Layout/Faq.tsx b/src/Layout/Faq.tsx index 20375ef..aaa4429 100644 --- a/src/Layout/Faq.tsx +++ b/src/Layout/Faq.tsx @@ -70,17 +70,13 @@ const Faq = () => { fetchFaq(); }, []); - // Auto-scroll ke section FAQ kalau ada #faq useEffect(() => { if (location.hash === "#faq") { - // wrapper ada di Landing:
- // ini memastikan scroll halus const el = document.getElementById("faq"); el?.scrollIntoView({ behavior: "smooth", block: "start" }); } }, [location.hash]); - // Auto-open FAQ tertentu kalau ?faq=ID ada dan data sudah ke-load useEffect(() => { if (!faqIdFromUrl) return; if (faqData.length === 0) return; @@ -88,8 +84,6 @@ const Faq = () => { const idx = faqData.findIndex((f) => f.id === faqIdFromUrl); if (idx !== -1) { setOpenIndex(idx); - - // Optional: setelah open, pastikan tetap terlihat setTimeout(() => { const el = document.getElementById("faq"); el?.scrollIntoView({ behavior: "smooth", block: "start" }); @@ -99,7 +93,6 @@ const Faq = () => { return (
- {/* UI tetap sama persis */}

Frequently Asked Questions @@ -117,7 +110,7 @@ const Faq = () => {
{!loading && !error && faqData.length === 0 && ( -
+

Belum ada FAQ.

)} @@ -125,7 +118,7 @@ const Faq = () => { {faqData.map((faq, index) => (
+ }
+ + {/* Info & Action Buttons */} + {!isIntern && +
+

Profile Photo

+

+ JPG, GIF or PNG. Recommended size 800x800px. Max size of 800K. +

+ {photoFile && ( +

+ 📎 {photoFile.name} +

+ )} +
+ + +
+
+ } + + {/* Hidden file input */} +
-
+
- {/* Grid Inputs (Full Name & Email Address) */} + {/* Grid Inputs */}
- - {/* Field: Full Name */}
- - {/* Field: Email Address */}
- {/* Field: Professional Bio */} + {/* Professional Bio */}
- {/* Form Action Footer Row */} + {/* Feedback Messages + {successMsg && ( +

+ {successMsg} +

+ )} + {errorMsg && ( +

+ {errorMsg} +

+ )} */} + + {/* Footer Action */}
diff --git a/src/Pages/internify/intern/components/TaskForm-file.tsx b/src/Pages/internify/intern/components/TaskForm-file.tsx index 19b44c1..4588d6f 100644 --- a/src/Pages/internify/intern/components/TaskForm-file.tsx +++ b/src/Pages/internify/intern/components/TaskForm-file.tsx @@ -4,6 +4,7 @@ import { LuSendHorizontal } from "react-icons/lu"; import SubmitStatusTable from "./SubmissionStatusTable"; import { useSubmission } from "../../../../hooks/useTasks"; import type { TaskSubmissionData } from "../../../../types/task.types"; +import { customToast } from "../../../utils/showToast"; interface TaskFormFileProps { taskId: string; @@ -25,10 +26,7 @@ export default function TaskFormFile({ taskId, projectId, deadline, initialSubmi selectedFiles.forEach((file) => { const ext = file.name.split(".").pop()?.toLowerCase(); if (ext && allowedExtensions.includes(ext)) { - if (file.size <= 10 * 1024 * 1024) validFiles.push(file); - else alert(`Ukuran file ${file.name} melebihi 10MB.`); - } else { - alert(`Format ${file.name} tidak didukung. Gunakan PDF.`); + if (file.size <= 5 * 1024 * 1024) validFiles.push(file); } }); if (validFiles.length > 0) setFiles((prev) => [...prev, ...validFiles]); @@ -52,17 +50,59 @@ export default function TaskFormFile({ taskId, projectId, deadline, initialSubmi const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - if (files.length === 0) { alert("Pilih file terlebih dahulu."); return; } - const res = isEditing - ? await updateFile(submission!.id, files) - : await submitFile(files); - if (res) { setIsEditing(false); setFiles([]); } + if (files.length === 0) { + customToast.error( + "File belum dipilih!", + "Silakan pilih file terlebih dahulu sebelum mengirim." + ); + return; + } + + const res = await customToast.promise( + isEditing ? updateFile(submission!.id, files) : submitFile(files), + { + loading: isEditing ? "Memperbarui file..." : "Mengirim file...", + success: () => ({ + title: isEditing ? "File berhasil diperbarui!" : "File berhasil dikirim!", + description: isEditing + ? "Perubahan submission Anda telah disimpan." + : "Submission Anda telah berhasil dikirim.", + }), + error: (err) => ({ + title: isEditing ? "Gagal memperbarui file!" : "Gagal mengirim file!", + description: + err?.response?.data?.message || + err?.message || + "Terjadi kesalahan saat memproses file Anda.", + }), + } + ); + + if (res) { + setIsEditing(false); + setFiles([]); + } }; const handleDelete = async () => { if (!confirm("Yakin ingin menghapus submission ini?")) return; - const ok = await remove(submission!.id); - if (ok) { setFiles([]); setIsEditing(false); } + + try { + const ok = await remove(submission!.id); + if (ok) { + setFiles([]); + setIsEditing(false); + customToast.success( + "Submission berhasil dihapus!", + "Anda dapat mengirim submission baru kapan saja." + ); + } + } catch (err: any) { + customToast.error( + "Gagal menghapus submission!", + err?.response?.data?.message || "Terjadi kesalahan saat menghapus submission." + ); + } }; const handleCancelEdit = () => { @@ -83,8 +123,6 @@ export default function TaskFormFile({ taskId, projectId, deadline, initialSubmi ); } - // const currentFileName = submission?.file_path?.split("/").pop(); - return ( ) : isEditing && submission?.files && submission.files.length > 0 ? (
- -

File saat ini:

{submission.files.map((f) => ( -

+

+ {f.original_name} -

+
))}
-

- Klik atau drag & drop untuk mengganti file +

+ Upload ulang files yang akan diganti ke dalam submissions, atau klik batal

) : (

Click to upload or drag & drop

-

PDF, DOCX, or ZIP (Max. 10MB)

+

PDF, DOCX, or ZIP (Max.5MB)

)}
diff --git a/src/Pages/internify/intern/components/TaskForm-link.tsx b/src/Pages/internify/intern/components/TaskForm-link.tsx index ae12080..2967480 100644 --- a/src/Pages/internify/intern/components/TaskForm-link.tsx +++ b/src/Pages/internify/intern/components/TaskForm-link.tsx @@ -4,6 +4,7 @@ import { LuSendHorizontal } from "react-icons/lu"; import SubmitStatusTable from "./SubmissionStatusTable"; import { useSubmission } from "../../../../hooks/useTasks"; import type { TaskSubmissionData } from "../../../../types/task.types"; +import { customToast } from "../../../utils/showToast"; interface TaskFormLinkProps { taskId: string; @@ -19,18 +20,54 @@ export default function TaskFormLink({ taskId, projectId, deadline, initialSubmi const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - if (!inputLink.trim()) return; - const res = isEditing - ? await updateLink(submission!.id, inputLink) - : await submitLink(inputLink); - if (res) { setIsEditing(false); } + if (!inputLink.trim()) { + customToast.error( + "Link belum dibuat", + "Masukkan link untuk mengirim submission" + ); + return; + } + + await customToast.promise( + isEditing ? updateLink(submission!.id, inputLink) : submitLink(inputLink), + { + loading: isEditing ? "Memperbarui Link..." : "Mengirim Link...", + success: () => ({ + title: isEditing ? "Link diperbaharui" : "Link berhasil dikirim", + description: isEditing + ? "Perubahan submission Anda telah disimpan." + : "Submission Anda telah berhasil dikirim.", + }), + error: (err) => ({ + title: isEditing ? "Gagal memperbarui link!" : "Gagal mengirim link!", + description: + err?.response?.data?.message || + err?.message || + "Link yang anda submit gagal dikirim", + }), + } + ); }; const handleDelete = async () => { - if (!confirm("Yakin ingin menghapus submission ini?")) return; - const ok = await remove(submission!.id); - if (ok) setInputLink(""); -}; + if (!confirm("Yakin ingin menghapus submission ini?")) return; + try { + const ok = await remove(submission!.id); + if (ok) { + setInputLink(""); + setIsEditing(false); + customToast.success( + "Submission berhasil dihapus!", + "Anda dapat mengirim submission baru kapan saja." + ); + } + } catch (err: any) { + customToast.error( + "Gagal menghapus submission!", + err?.response?.data?.message || "Terjadi kesalahan saat menghapus submission." + ); + } + }; if (submission && !isEditing) { return ( diff --git a/src/Pages/internify/mentor/BaseProjectsPage.tsx b/src/Pages/internify/mentor/BaseProjectsPage.tsx index 8304de2..1dcbfd8 100644 --- a/src/Pages/internify/mentor/BaseProjectsPage.tsx +++ b/src/Pages/internify/mentor/BaseProjectsPage.tsx @@ -2,9 +2,9 @@ import MentorProjectCard from './components/MentorProjectCard'; import { Plus } from 'lucide-react'; import { useState } from 'react'; import CreateProjectModal from './components/CreateProjectDialog'; +import { customToast } from '../../utils/showToast'; import { useProjectsByRole } from '../../../hooks/useListProjects'; - export default function MentorProjectsPage() { const [isModalOpen, setIsModalOpen] = useState(false); const { projects, loading, error, refetch } = useProjectsByRole(); @@ -38,7 +38,6 @@ export default function MentorProjectsPage() {

Create, manage, and monitor ongoing projects and assignments.

- {/* Tombol pemicu buka modal */}
- {/* Feedback Messages */} + {/* Feedback Messages {successMsg && (

{successMsg} @@ -233,7 +242,7 @@ export default function MentorSettingsPage() {

{errorMsg}

- )} + )} */} {/* Footer Action */}
diff --git a/src/Pages/internify/mentor/ProjectsInternTab.tsx b/src/Pages/internify/mentor/ProjectsInternTab.tsx index 006cd8e..a684847 100644 --- a/src/Pages/internify/mentor/ProjectsInternTab.tsx +++ b/src/Pages/internify/mentor/ProjectsInternTab.tsx @@ -3,18 +3,20 @@ import { Plus } from 'lucide-react'; import ManageInternsModal from './components/AddInternsDialog'; import type { ProjectDetail, ProjectMember } from '../../../types/project.types'; import { useRemoveMember } from '../../../hooks/useProjects'; +import { customToast } from '../../utils/showToast'; export default function InternsTab({ project }: { project: ProjectDetail }) { const [isModalOpen, setIsModalOpen] = useState(false); + const [members, setMembers] = useState(project.members); const { remove, loading } = useRemoveMember(); const handleRemove = async (id_user: number) => { - if (window.confirm('Are you sure you want to remove this member?')) { - const res = await remove({ id_project: project.id, id_user }); - if (res !== null) { - alert('Member removed successfully'); - window.location.reload(); - } + const res = await remove({ id_project: project.id, id_user }); + if (res !== null) { + setMembers(prev => prev.filter(m => m.id !== id_user)); + customToast.success('Member removed', 'The intern has been successfully removed from this project.'); + } else { + customToast.error('Failed to remove', 'An error occurred while removing the member. Please try again.'); } }; @@ -51,32 +53,32 @@ export default function InternsTab({ project }: { project: ProjectDetail }) {

- {project.members.map((member: ProjectMember, idx) => ( + {members.map((member: ProjectMember, idx) => (
- + {member.email}
- + {member.position}
@@ -88,7 +90,8 @@ export default function InternsTab({ project }: { project: ProjectDetail }) { isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} projectId={project.id} - initialMembers={project.members} + initialMembers={members} + onMembersChange={(updated) => setMembers(updated)} />}
); diff --git a/src/Pages/internify/mentor/TaskTab.tsx b/src/Pages/internify/mentor/TaskTab.tsx index 2c6d73b..d882675 100644 --- a/src/Pages/internify/mentor/TaskTab.tsx +++ b/src/Pages/internify/mentor/TaskTab.tsx @@ -1,21 +1,30 @@ -import { useProjectTasks, useCreateTask, useDeleteTask } from '../../../hooks/useTasks'; +import { useProjectTasks, useDeleteTask } from '../../../hooks/useTasks'; import type { ProjectDetail } from '../../../types/project.types'; import type { ProjectTask } from '../../../types/task.types'; import { ClipboardList, Pencil, Trash2 } from 'lucide-react'; import { useState } from 'react'; import CreateTaskModal from './components/CreateTaskDialog'; import EditTaskModal from './components/EditTaskDialog'; +import { customToast } from '../../utils/showToast'; export default function TaskTab({ project }: { project: ProjectDetail }) { - const { tasks, loading, error, refetch } = useProjectTasks(String(project.id)); + const { tasks, loading, error, refetch } = useProjectTasks(project.id); const { remove } = useDeleteTask(); const [isModalOpen, setIsModalOpen] = useState(false); const [editModalOpen, setEditModalOpen] = useState(false); const [selectedTask, setSelectedTask] = useState(null); - const handleDeleteTask = async (taskId: number) => { - const ok = await remove(taskId, String(project.id)); - if (ok) refetch(); + const handleDeleteTask = async (taskId: number,taskTitle: string) => { + const del = await remove(taskId, String(project.id)); + if (del) { + try { + customToast.success("Berhasil", `Task ${taskTitle} berhasil dihapus`) + } catch (error) { + customToast.error("Gagal", `Task ${taskTitle} gagal dihapus`) + } finally { + refetch(); + } + } }; if (loading) return ( @@ -61,7 +70,7 @@ export default function TaskTab({ project }: { project: ProjectDetail }) {
- {error && -
- {error}: Sudah berada di project lain -
- } +
{/* Sudah jadi member */} @@ -97,7 +100,7 @@ export default function ManageInternsModal({ isOpen, onClose, projectId, initial
- {member.full_name.slice(0, 2).toUpperCase()} + {getInitials(member as unknown as AssignableIntern)}
{member.full_name} diff --git a/src/Pages/internify/mentor/components/AddInternsToProjects.tsx b/src/Pages/internify/mentor/components/AddInternsToProjects.tsx index 6a671bf..14bda72 100644 --- a/src/Pages/internify/mentor/components/AddInternsToProjects.tsx +++ b/src/Pages/internify/mentor/components/AddInternsToProjects.tsx @@ -3,6 +3,7 @@ import { X } from "lucide-react"; import { LuUserPlus, LuUser, LuFolderOpen } from "react-icons/lu"; import { useAssignMember, useProjects } from "../../../../hooks/useProjects"; import { useAssignableInterns } from "../../../../hooks/useProjects"; +import { customToast } from "../../../utils/showToast"; interface AddInternsModalProps { isOpen: boolean; @@ -46,8 +47,6 @@ export default function AddInternsModal({ isOpen, onClose, userId }: AddInternsM }; }, [isOpen, onClose]); - // Reset form saat modal dibuka kembali. - // Kalau userId diberikan, dropdown langsung ter-select ke intern tsb. useEffect(() => { if (isOpen) { setSelectedUserId(userId !== null ? String(userId) : ""); @@ -64,7 +63,10 @@ export default function AddInternsModal({ isOpen, onClose, userId }: AddInternsM id_user: Number(selectedUserId), }); if (res !== null) { + customToast.success('Intern assigned', 'The intern has been successfully assigned to the project.'); onClose(); + } else { + customToast.error('Failed to assign', 'An error occurred while assigning the intern. Please try again.'); } }; diff --git a/src/Pages/internify/mentor/components/CertificateProjectCard.tsx b/src/Pages/internify/mentor/components/CertificateProjectCard.tsx index 3f216bf..cbc5870 100644 --- a/src/Pages/internify/mentor/components/CertificateProjectCard.tsx +++ b/src/Pages/internify/mentor/components/CertificateProjectCard.tsx @@ -3,13 +3,13 @@ import type { Project } from "../../../../types/project.types"; // ─── StatusBadge ───────────────────────────────────────────────────────────── function StatusBadge({ status }: { status: string }) { - const isCompleted = status === "archived"; + const isCompleted = status === "active"; return ( {status} diff --git a/src/Pages/internify/mentor/components/CreateProjectDialog.tsx b/src/Pages/internify/mentor/components/CreateProjectDialog.tsx index 7492d4a..b053330 100644 --- a/src/Pages/internify/mentor/components/CreateProjectDialog.tsx +++ b/src/Pages/internify/mentor/components/CreateProjectDialog.tsx @@ -1,9 +1,11 @@ -import { useRef, useEffect, useState } from "react"; +import { useRef, useEffect, useState, useCallback } from "react"; import { X } from "lucide-react"; import { PROJECT_ICON_MAP, PROJECT_ICON_CODES } from "../../../../lib/ProjectIcons"; import { LuSendHorizontal, LuMail } from "react-icons/lu"; import { useCreateProject } from "../../../../hooks/useProjects"; import type { CreateProjectPayload } from "../../../../types/project.types"; +import { useAssignableInterns } from "../../../../hooks/useProjects"; +import { customToast } from "../../../utils/showToast"; interface CreateProjectModalProps { isOpen: boolean; @@ -21,6 +23,21 @@ export default function CreateProjectModal({ isOpen, onClose, onSuccess }: Creat const [startDate, setStartDate] = useState(""); const [endDate, setEndDate] = useState(""); const { create, loading, error } = useCreateProject(); + const { interns: assignableInterns, loading: loadingInterns } = useAssignableInterns(); + const [showDropdown, setShowDropdown] = useState(false); + const emailSectionRef = useRef(null); + + // Tutup dropdown saat klik di luar area input + const handleClickOutside = useCallback((e: MouseEvent) => { + if (emailSectionRef.current && !emailSectionRef.current.contains(e.target as Node)) { + setShowDropdown(false); + } + }, []); + + useEffect(() => { + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, [handleClickOutside]); const projectIcons = PROJECT_ICON_CODES.map((id) => ({ id, @@ -51,14 +68,20 @@ export default function CreateProjectModal({ isOpen, onClose, onSuccess }: Creat }; }, [isOpen, onClose]); - const handleAddEmail = (e: React.FormEvent) => { - e.preventDefault(); - if (emailInput.trim() && !invitedEmails.includes(emailInput.trim())) { - setInvitedEmails([...invitedEmails, emailInput.trim()]); + const handleAddEmail = (emailToAdd?: string) => { + const email = (emailToAdd ?? emailInput).trim(); + if (email && !invitedEmails.includes(email)) { + setInvitedEmails([...invitedEmails, email]); setEmailInput(""); + setShowDropdown(false); } }; + // const handleAddEmailFromForm = (e: React.FormEvent) => { + // e.preventDefault(); + // handleAddEmail(); + // }; + const handleRemoveEmail = (emailToRemove: string) => { setInvitedEmails(invitedEmails.filter(email => email !== emailToRemove)); }; @@ -79,8 +102,12 @@ export default function CreateProjectModal({ isOpen, onClose, onSuccess }: Creat const result = await create(payload); if (result) { - onSuccess?.(); // panggil refetch di parent (kalau ada) + onSuccess?.(); onClose(); + customToast.success( + "Project berhasil dibuat!", + `${projectName} sudah aktif dan siap dikelola.` + ); } }; @@ -167,30 +194,71 @@ export default function CreateProjectModal({ isOpen, onClose, onSuccess }: Creat -
- - - - setEmailInput(e.target.value)} - onKeyDown={(e) => { - if (e.key === 'Enter') { - e.preventDefault(); - handleAddEmail(e); - } - }} - className="w-full pl-10 pr-20 py-2.5 bg-white border border-gray-200 rounded-lg text-sm placeholder-gray-400 text-gray-800 focus:outline-none focus:border-red-600 focus:ring-1 focus:ring-red-600 font-medium" - /> - + {/* Input email + dropdown sugesti intern */} +
+
+ + + + { setEmailInput(e.target.value); setShowDropdown(true); }} + onFocus={() => setShowDropdown(true)} + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault(); + handleAddEmail(); + } + if (e.key === 'Escape') setShowDropdown(false); + }} + className="w-full pl-10 pr-20 py-2.5 bg-white border border-gray-200 rounded-lg text-sm placeholder-gray-400 text-gray-800 focus:outline-none focus:border-red-600 focus:ring-1 focus:ring-red-600 font-medium" + /> + +
+ + {/* Dropdown daftar intern */} + {showDropdown && ( +
+ {loadingInterns ? ( +

Memuat data intern...

+ ) : (() => { + const filtered = assignableInterns.filter( + (i) => + !invitedEmails.includes(i.email) && + (i.email.toLowerCase().includes(emailInput.toLowerCase()) || + i.full_name.toLowerCase().includes(emailInput.toLowerCase())) + ); + return filtered.length === 0 ? ( +

Tidak ada intern ditemukan.

+ ) : ( + filtered.map((intern) => ( + + )) + ); + })()} +
+ )}
{/* Badges List Email */} diff --git a/src/Pages/internify/mentor/components/CreateTaskDialog.tsx b/src/Pages/internify/mentor/components/CreateTaskDialog.tsx index d3da25b..8f7bffd 100644 --- a/src/Pages/internify/mentor/components/CreateTaskDialog.tsx +++ b/src/Pages/internify/mentor/components/CreateTaskDialog.tsx @@ -2,6 +2,7 @@ import { useRef, useEffect, useState } from "react"; import { X, FileText, Link } from "lucide-react"; import { useCreateTask } from '../../../../hooks/useTasks'; import type { SubmissionType } from '../../../../types/task.types'; +import { customToast } from '../../../utils/showToast'; interface CreateTaskModalProps { isOpen: boolean; @@ -39,7 +40,12 @@ export default function CreateTaskModal({ isOpen, onClose, projectId, onSuccess specific_time: specificTime, submission_type: submissionType, }); - if (result) onSuccess(); + if (result) { + customToast.success('Task created', `"${taskTitle}" has been successfully added to the project.`); + onSuccess(); + } else { + customToast.error('Failed to create task', 'An error occurred while saving the task. Please try again.'); + } }; return ( diff --git a/src/Pages/internify/mentor/components/EditTaskDialog.tsx b/src/Pages/internify/mentor/components/EditTaskDialog.tsx index 86eb269..b205027 100644 --- a/src/Pages/internify/mentor/components/EditTaskDialog.tsx +++ b/src/Pages/internify/mentor/components/EditTaskDialog.tsx @@ -2,6 +2,7 @@ import { useRef, useEffect, useState } from "react"; import { X, FileText, Link } from "lucide-react"; import { useUpdateTask } from '../../../../hooks/useTasks'; import type { ProjectTask, SubmissionType } from '../../../../types/task.types'; +import { customToast } from '../../../utils/showToast'; interface EditTaskModalProps { isOpen: boolean; @@ -48,7 +49,12 @@ export default function EditTaskModal({ isOpen, onClose, task, onSuccess }: Edit specific_time: specificTime, submission_type: submissionType, }, String(task.id_project)); - if (result) onSuccess(); + if (result) { + customToast.success('Task updated', `"${taskTitle}" has been successfully updated.`); + onSuccess(); + } else { + customToast.error('Failed to update task', 'An error occurred while saving changes. Please try again.'); + } }; return ( diff --git a/src/Pages/internify/mentor/components/MentorProjectCard.tsx b/src/Pages/internify/mentor/components/MentorProjectCard.tsx index 2dd044c..745a56f 100644 --- a/src/Pages/internify/mentor/components/MentorProjectCard.tsx +++ b/src/Pages/internify/mentor/components/MentorProjectCard.tsx @@ -4,6 +4,7 @@ import * as LucideIcons from 'lucide-react'; import type { LucideProps } from 'lucide-react'; import type { Project } from '../../../../types/project.types'; import { useArchiveProject } from '../../../../hooks/useProjects'; +import { customToast } from '../../../utils/showToast'; const getDynamicIcon = (iconName: string) => { const formatted = iconName.charAt(0).toUpperCase() + iconName.slice(1); @@ -11,14 +12,16 @@ const getDynamicIcon = (iconName: string) => { return Icon ?? LucideIcons.FolderOpen; }; -const toSlug = (name: string) => name.toLowerCase().replace(/\s+/g, '-'); +interface MentorProjectCardProps extends Project { + onArchived?: () => void; +} -export default function MentorProjectCard(project: Project) { +export default function MentorProjectCard({ onArchived, ...project} : MentorProjectCardProps) { const navigate = useNavigate(); const { archive, loading } = useArchiveProject(); const handleCardClick = () => { - navigate(`/mentor/projects/${toSlug(project.slug)}`) + navigate(`/mentor/projects/${project.slug}`) }; const Icon = getDynamicIcon(project.project_icon); @@ -31,12 +34,19 @@ export default function MentorProjectCard(project: Project) { const result = await archive(project.id); if (result) { - window.alert("Project berhasil diarsipkan."); - window.location.reload(); + customToast.success( + "Berhasil!", + "Projek Berhasil Diarsipkan (archived)" + ) + onArchived?.(); } else { - window.alert("Gagal mengarsipkan project."); + customToast.error( + "Gagal!", + "Projek gagal diarsipkan (archived)" + ) } }; + return (
{ +export const useProjectTasks = (projectId: number) => { const [tasks, setTasks] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -180,8 +180,9 @@ export const useSubmission = ( const res = await submitTaskFile(taskId, files, projectId); if (res) setSubmission(res); return res; - } catch { + } catch (err){ setError("Gagal submit file."); + throw error; return null; } finally { setLoading(false); @@ -195,9 +196,9 @@ export const useSubmission = ( const res = await submitTaskLink(taskId, url, projectId); if (res) setSubmission(res); return res; - } catch { + } catch (err){ setError("Gagal submit link."); - return null; + throw err; } finally { setLoading(false); } @@ -210,9 +211,9 @@ export const useSubmission = ( const res = await updateSubmissionFile(submissionId, files); if (res) setSubmission(res); return res; - } catch { + } catch (err){ setError("Gagal update submission."); - return null; + throw err; } finally { setLoading(false); } @@ -225,9 +226,9 @@ export const useSubmission = ( const res = await updateSubmissionLink(submissionId, url); if (res) setSubmission(res); return res; - } catch { + } catch (err){ setError("Gagal update submission."); - return null; + throw err; } finally { setLoading(false); } @@ -240,9 +241,9 @@ export const useSubmission = ( await deleteSubmission(submissionId); setSubmission(null); return true; - } catch { + } catch (err) { setError("Gagal hapus submission."); - return false; + throw err; } finally { setLoading(false); } diff --git a/src/lib/mockData.ts b/src/lib/mockData.ts deleted file mode 100644 index b9ad130..0000000 --- a/src/lib/mockData.ts +++ /dev/null @@ -1,330 +0,0 @@ -export interface Deadline { - date: Date; - label: string; - time: string; -} - -export const DEADLINES: Deadline[] = [ - { - date: new Date(2025, 4, 4), // May 4, 2025 - label: "Laporan Progress 1 Internify – 4 Juni", - time: "23:59 PM", - }, - { - date: new Date(2026, 5, 5), - label: "Laporan Progress 2 Internify - 5 May", - time: "23:59 PM", - }, -]; - -export const deadlineDates: Date[] = DEADLINES.map((d) => d.date); - -export interface Task { - id: number; - title: string; - description: string; - deadline: Deadline; - isSubmitted: boolean; - submittedCount: number; - totalInterns: number; -} - -export interface Intern { - name: string; - role: string; - email: string; -} - -export interface Project { - id: number; - name: string; - description: string; - tasks: Task[]; - interns: Intern[]; - mentor: string; - avatarUrl?: string; - thumbnailUrl?: string; - progress: number; - tasksDone: number; - tasksTotal: number; -} - -export const mockProjects: Project[] = [ - { - id: 1, - name: "Internify Project", - description: - "Internify merupakan website Human Capital (HUMC) yang dirancang sebagai platform pendaftaran dan pengelolaan program magang secara digital. Sistem ini dibuat untuk membantu proses rekrutmen peserta magang mulai dari pendaftaran, seleksi, hingga monitoring aktivitas peserta selama program berlangsung.\n\nFokus utama dari pengembangan Internify adalah pembuatan Learning Management System (LMS) yang digunakan untuk mendukung kegiatan pembelajaran dan pengelolaan peserta magang. LMS pada Internify menyediakan fitur seperti akses materi pembelajaran, pengumpulan tugas, monitoring progress peserta, absensi, sertifikat, hingga komunikasi antara mentor dan peserta magang.", - tasks: [ - { - id: 1, - title: "Laporan tugas", - description: "Berisi design ulux, dan user flow dari aplikasi internify", - deadline: { date: new Date(2026, 4, 1), label: "Laporan tugas – 1 Mei", time: "23:59 PM" }, - submittedCount: 6, - totalInterns: 6, - isSubmitted: true, - }, - { - id: 2, - title: "Laporan tugas 1", - description: "Berisi design ulux, dan user flow dari aplikasi internify", - deadline: { date: new Date(2026, 4, 14), label: "Laporan tugas 1 – 14 Mei", time: "23:59 PM" }, - submittedCount: 2, - totalInterns: 6, - isSubmitted: false, - }, - { - id: 3, - title: "Laporan tugas 2", - description: "Berisi design ulux, dan user flow dari aplikasi internify", - deadline: { date: new Date(2026, 4, 28), label: "Laporan tugas 2 – 28 Mei", time: "23:59 PM" }, - submittedCount: 3, - totalInterns: 6, - isSubmitted: false, - }, - { - id: 4, - title: "Laporan tugas 3", - description: "Berisi wireframe halaman dashboard aplikasi internify", - deadline: { date: new Date(2026, 5, 5), label: "Laporan tugas 3 – 5 Jun", time: "23:59 PM" }, - submittedCount: 0, - totalInterns: 6, - isSubmitted: false, - }, - ], - interns: [ - { name: "Jonathan Kristina", role: "Backend", email: "jonathankristina@gmail.com" }, - { name: "Anisa Rahmawati", role: "Backend", email: "jonathankristina@gmail.com" }, - { name: "Budi Santoso", role: "Frontend", email: "jonathankristina@gmail.com" }, - { name: "Cindy Permata", role: "Frontend", email: "jonathankristina@gmail.com" }, - { name: "Dewa Aditya", role: "UI/UX", email: "jonathankristina@gmail.com" }, - { name: "Eka Pratiwi", role: "UI/UX", email: "jonathankristina@gmail.com" }, - ], - mentor: "jonathankristina", - progress: 12, - tasksDone: 1, - tasksTotal: 8, - }, - { - id: 2, - name: "Rekrutmen Digital Platform", - description: - "Platform digital yang memudahkan proses rekrutmen karyawan baru secara end-to-end. Mulai dari posting lowongan, screening CV otomatis, penjadwalan wawancara, hingga onboarding karyawan baru.\n\nSistem ini mengintegrasikan berbagai modul HR seperti manajemen data kandidat, penilaian kompetensi berbasis AI, dan dashboard analytics untuk tim HR dalam mengambil keputusan rekrutmen yang lebih efektif dan efisien.", - tasks: [ - { - id: 1, - title: "Analisis Kebutuhan Sistem", - description: "Dokumentasi kebutuhan fungsional dan non-fungsional platform rekrutmen", - deadline: { date: new Date(2026, 4, 5), label: "Analisis Kebutuhan – 5 Mei", time: "23:59 PM" }, - submittedCount: 6, - totalInterns: 6, - isSubmitted: true, - }, - { - id: 2, - title: "Desain Database Schema", - description: "Rancangan struktur database untuk kandidat, lowongan, dan proses seleksi", - deadline: { date: new Date(2026, 4, 10), label: "Desain Database – 10 Mei", time: "23:59 PM" }, - submittedCount: 6, - totalInterns: 6, - isSubmitted: true, - }, - { - id: 3, - title: "Implementasi Auth Module", - description: "Pengembangan sistem autentikasi dan otorisasi multi-role", - deadline: { date: new Date(2026, 4, 18), label: "Auth Module – 18 Mei", time: "23:59 PM" }, - submittedCount: 3, - totalInterns: 6, - isSubmitted: true, - }, - { - id: 4, - title: "Modul Posting Lowongan", - description: "Fitur buat, edit, dan publish lowongan pekerjaan", - deadline: { date: new Date(2026, 4, 25), label: "Posting Lowongan – 25 Mei", time: "23:59 PM" }, - submittedCount: 0, - totalInterns: 6, - isSubmitted: false, - }, - ], - interns: [ - { name: "Fajar Nugroho", role: "Backend", email: "fajarnugroho@gmail.com" }, - { name: "Gita Melinda", role: "Backend", email: "gitamelinda@gmail.com" }, - { name: "Hendra Wijaya", role: "Frontend", email: "hendrawijaya@gmail.com" }, - { name: "Indira Sari", role: "Frontend", email: "indirasari@gmail.com" }, - { name: "Joko Purnomo", role: "UI/UX", email: "jokopurnomo@gmail.com" }, - { name: "Kartika Dewi", role: "QA", email: "kartikadewi@gmail.com" }, - { name: "Lukman Hakim", role: "QA", email: "lukmanhakim@gmail.com" }, - ], - mentor: "seniormHR@company.com", - progress: 37, - tasksDone: 3, - tasksTotal: 8, - }, - { - id: 3, - name: "E-Commerce Analytics Dashboard", - description: - "Dashboard analitik komprehensif untuk platform e-commerce yang menyajikan insight real-time tentang performa penjualan, perilaku pelanggan, dan efektivitas kampanye marketing.\n\nProyek ini mencakup pengembangan pipeline data dari berbagai sumber transaksi, visualisasi interaktif menggunakan chart library modern, serta fitur export laporan dalam berbagai format untuk kebutuhan manajemen bisnis.", - tasks: [ - { - id: 1, - title: "Setup Pipeline Data", - description: "Konfigurasi ETL pipeline dari database transaksi ke data warehouse", - deadline: { date: new Date(2026, 4, 3), label: "Setup Pipeline – 3 Mei", time: "23:59 PM" }, - submittedCount: 6, - totalInterns: 6, - isSubmitted: true, - }, - { - id: 2, - title: "Desain Komponen Chart", - description: "Pembuatan reusable chart component untuk berbagai tipe visualisasi data", - deadline: { date: new Date(2026, 4, 12), label: "Komponen Chart – 12 Mei", time: "23:59 PM" }, - submittedCount: 6, - totalInterns: 6, - isSubmitted: true, - }, - { - id: 3, - title: "Dashboard Overview Page", - description: "Halaman utama dengan ringkasan KPI dan metric utama bisnis", - deadline: { date: new Date(2026, 4, 20), label: "Overview Page – 20 Mei", time: "23:59 PM" }, - submittedCount: 0, - totalInterns: 6, - isSubmitted: false, - }, - { - id: 4, - title: "Laporan Penjualan", - description: "Modul analitik penjualan dengan filter periode dan kategori produk", - deadline: { date: new Date(2026, 4, 28), label: "Laporan Penjualan – 28 Mei", time: "23:59 PM" }, - submittedCount: 0, - totalInterns: 6, - isSubmitted: false, - }, - ], - interns: [ - { name: "Maya Anggraeni", role: "Backend", email: "mayaanggraeni@gmail.com" }, - { name: "Nando Pratama", role: "Backend", email: "nandopratama@gmail.com" }, - { name: "Olivia Susanto", role: "Frontend", email: "oliviasusanto@gmail.com" }, - { name: "Pandu Kusuma", role: "Frontend", email: "pandukukusuma@gmail.com" }, - { name: "Qori Ramadhan", role: "Data Analyst", email: "qoriramadhan@gmail.com" }, - { name: "Rini Handayani", role: "UI/UX", email: "rinihandayani@gmail.com" }, - ], - mentor: "leadanalyst@company.com", - progress: 50, - tasksDone: 4, - tasksTotal: 8, - }, -]; - -export interface Certificate { - id: string; - issuedDate: string; - recipientName: string; - programName: string; - duration: string; - finalScore: number; - grade: string; - status: string; -} - -export interface CertificateHistory { - id: number; - month: string; - title: string; - grade: string; -} - -export interface CertificateData { - isReceived: boolean; - projectProgress: number; - remainingTasks: number; - certificate: Certificate; - history: CertificateHistory[]; -} - -export const certificateData: CertificateData = { - isReceived: false, // ubah ke false untuk tampilan "belum tersedia" - projectProgress: 65, - remainingTasks: 3, - certificate: { - id: "INF-2024-88392", - issuedDate: "24 Oct 2024", - recipientName: "JonathanKristina", - programName: "Internify Project", - duration: "8 Minggu", - finalScore: 94, - grade: "A", - status: "VERIFIED", - }, - history: [ - { - id: 1, - month: "Juni 2023", - title: "Web Development Fundamentals", - grade: "A+", - }, - { - id: 2, - month: "Maret 2023", - title: "UI/UX Design Essentials", - grade: "A", - } - ], -}; - -// Mock Data Interns -export const mockInternsData = [ - { - id: 1, - name: "Alex Rivera", - email: "alex.rivera@internify.edu", - projectName: "Internify Project", - role: "UI/UX", - avatar: "https://images.unsplash.com/photo-1534528741775-53994a69daeb?auto=format&fit=crop&w=100&q=80" // Contoh avatar placeholder - }, - { - id: 2, - name: "Sarah Jenkins", - email: "s.jenkins@internify.edu", - projectName: "Internify Project", - role: "Frontend", - avatar: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=100&q=80" - }, - { - id: 3, - name: "Michael Chen", - email: "m.chen@internify.edu", - projectName: "MBG Project", - role: "Backend", - avatar: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=100&q=80" - }, - { - id: 4, - name: "Elena Rodriguez", - email: "e.rod@internify.edu", - projectName: "Unassigned", - role: "-", - avatar: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=crop&w=100&q=80" - }, - { - id: 5, - name: "Alex Rivera", - email: "alex.rivera@internify.edu", - projectName: "Internify Project", - role: "UI/UX", - avatar: "" // Simulasi tanpa gambar avatar (menggunakan placeholder inisial/gradient) - }, - { - id: 6, - name: "Sarah Jenkins", - email: "s.jenkins@internify.edu", - projectName: "Internify Project", - role: "Backend", - avatar: "" - } -]; \ No newline at end of file diff --git a/src/lib/mockDeadline.ts b/src/lib/mockDeadline.ts deleted file mode 100644 index dd97574..0000000 --- a/src/lib/mockDeadline.ts +++ /dev/null @@ -1,18 +0,0 @@ -export interface Deadline { - date: Date; - label: string; - time: string; -} - -export const DEADLINES: Deadline[] = [ - { - date: new Date(2026, 5, 29), - label: "Laporan Progress 1 Internify", - time: "23:59 PM", - }, - { - date: new Date(2026, 5, 30), - label: "Laporan Progress 2 Internify", - time: "23:59 PM", - }, -]; \ No newline at end of file diff --git a/src/lib/mockInterns.ts b/src/lib/mockInterns.ts deleted file mode 100644 index c96f0e9..0000000 --- a/src/lib/mockInterns.ts +++ /dev/null @@ -1,59 +0,0 @@ -export interface InternData { - id: number; - name: string; - email: string; - projectName: string; - role: string; - avatar: string; -} - -export const mockInternsData: InternData[] = [ - { - id: 1, - name: "Alex Rivera", - email: "alex.rivera@internify.edu", - projectName: "Internify Project", - role: "UI/UX", - avatar: "https://images.unsplash.com/photo-1534528741775-53994a69daeb?auto=format&fit=crop&w=100&q=80", - }, - { - id: 2, - name: "Sarah Jenkins", - email: "s.jenkins@internify.edu", - projectName: "Internify Project", - role: "Frontend", - avatar: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=100&q=80", - }, - { - id: 3, - name: "Michael Chen", - email: "m.chen@internify.edu", - projectName: "MBG Project", - role: "Backend", - avatar: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=100&q=80", - }, - { - id: 4, - name: "Elena Rodriguez", - email: "e.rod@internify.edu", - projectName: "Unassigned", - role: "-", - avatar: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?auto=format&fit=crop&w=100&q=80", - }, - { - id: 5, - name: "Alex Rivera", - email: "alex.rivera@internify.edu", - projectName: "Internify Project", - role: "UI/UX", - avatar: "", - }, - { - id: 6, - name: "Sarah Jenkins", - email: "s.jenkins@internify.edu", - projectName: "Internify Project", - role: "Backend", - avatar: "", - }, -]; \ No newline at end of file diff --git a/src/lib/mockProjects.ts b/src/lib/mockProjects.ts deleted file mode 100644 index 3150922..0000000 --- a/src/lib/mockProjects.ts +++ /dev/null @@ -1,228 +0,0 @@ -export interface Submission { - internEmail: string; - submittedAt: string; - status: "Done" | "Pending" | "Overdue"; -} - -export interface Task { - id: number; - title: string; - description: string; - type: "file" | "link"; - deadline: { date: Date; label: string; time: string }; - isSubmitted: boolean; - submittedCount: number; - totalInterns: number; - submissions: Submission[]; -} - -export interface Intern { - name: string; - role: string; - email: string; -} - -export interface Project { - id: number; - name: string; - description: string; - tasks: Task[]; - interns: Intern[]; - mentor: string; - progress: number; - tasksDone: number; - tasksTotal: number; -} - -// ─── Project 1 ──────────────────────────────────────────────────────────────── - -const project1Interns: Intern[] = [ - { name: "Jonathan Kristina", role: "Backend", email: "jonathankristina@gmail.com" }, - { name: "Anisa Rahmawati", role: "Backend", email: "anisarahmawati@gmail.com" }, - { name: "Budi Santoso", role: "Frontend", email: "budisantoso@gmail.com" }, - { name: "Cindy Permata", role: "Frontend", email: "cindypermata@gmail.com" }, - { name: "Dewa Aditya", role: "UI/UX", email: "dewaaditya@gmail.com" }, - { name: "Eka Pratiwi", role: "UI/UX", email: "ekapratiwi@gmail.com" }, -]; - -// ─── Project 2 ──────────────────────────────────────────────────────────────── - -const project2Interns: Intern[] = [ - { name: "Fajar Nugroho", role: "Backend", email: "fajarnugroho@gmail.com" }, - { name: "Gita Lestari", role: "Backend", email: "gitalestari@gmail.com" }, - { name: "Hendra Wijaya", role: "Frontend", email: "hendrawijaya@gmail.com" }, - { name: "Indah Permata", role: "Frontend", email: "indahpermata@gmail.com" }, - { name: "Joko Susilo", role: "UI/UX", email: "jokosusilo@gmail.com" }, - { name: "Kartika Dewi", role: "UI/UX", email: "kartikadewi@gmail.com" }, -]; - -// ─── Project 3 ──────────────────────────────────────────────────────────────── - -const project3Interns: Intern[] = [ - { name: "Maya Anggraeni", role: "Backend", email: "mayaanggraeni@gmail.com" }, - { name: "Nanda Pratama", role: "Backend", email: "nandapratama@gmail.com" }, - { name: "Oscar Firmansyah",role: "Frontend", email: "oscarfirmansyah@gmail.com"}, - { name: "Putri Handayani", role: "Frontend", email: "putrihandayani@gmail.com" }, - { name: "Rizky Maulana", role: "UI/UX", email: "rizkymaulana@gmail.com" }, - { name: "Sari Utami", role: "UI/UX", email: "sariutami@gmail.com" }, -]; - -// ─── mock data ──────────────────────────────────────────────────────────────── - -export const mockProjects: Project[] = [ - { - id: 1, - name: "Internify Project", - description: - "Internify merupakan website Human Capital (HUMC) yang dirancang sebagai platform pendaftaran dan pengelolaan program magang secara digital. Sistem ini dibuat untuk membantu proses rekrutmen peserta magang mulai dari pendaftaran, seleksi, hingga monitoring aktivitas peserta selama program berlangsung.\n\nFokus utama dari pengembangan Internify adalah pembuatan Learning Management System (LMS) yang digunakan untuk mendukung kegiatan pembelajaran dan pengelolaan peserta magang. LMS pada Internify menyediakan fitur seperti akses materi pembelajaran, pengumpulan tugas, monitoring progress peserta, absensi, sertifikat, hingga komunikasi antara mentor dan peserta magang.", - interns: project1Interns, - mentor: "Mas A", - progress: 12, - tasksDone: 1, - tasksTotal: 8, - tasks: [ - { - id: 2, - title: "Laporan tugas 1", - description: - "Pada tugas pertama ini, Anda diminta untuk melakukan analisis mendalam terhadap kebutuhan pengguna untuk sistem Smart Campus Utility. Analisis ini akan menjadi fondasi bagi perancangan antarmuka pada fase berikutnya.", - type: "file", - deadline: { date: new Date(2026, 4, 14), label: "May 14, 2026", time: "23:59 PM" }, - isSubmitted: false, - submittedCount: 2, - totalInterns: 6, - submissions: [ - { internEmail: "jonathankristina@gmail.com", submittedAt: "May 12, 2026", status: "Done" }, - { internEmail: "anisarahmawati@gmail.com", submittedAt: "May 13, 2026", status: "Done" }, - { internEmail: "budisantoso@gmail.com", submittedAt: "-", status: "Pending" }, - { internEmail: "cindypermata@gmail.com", submittedAt: "-", status: "Pending" }, - { internEmail: "dewaaditya@gmail.com", submittedAt: "-", status: "Pending" }, - { internEmail: "ekapratiwi@gmail.com", submittedAt: "-", status: "Overdue" }, - ], - }, - { - id: 3, - title: "Laporan tugas 2", - description: - "Berisi design UI/UX dan user flow dari aplikasi Internify. Pastikan semua link Figma dapat diakses oleh mentor dan mencakup setidaknya 15 screen utama beserta prototype interaktifnya.", - type: "link", - deadline: { date: new Date(2026, 4, 28), label: "May 28, 2026", time: "23:59 PM" }, - isSubmitted: false, - submittedCount: 3, - totalInterns: 6, - submissions: [ - { internEmail: "jonathankristina@gmail.com", submittedAt: "May 25, 2026", status: "Done" }, - { internEmail: "anisarahmawati@gmail.com", submittedAt: "-", status: "Pending" }, - { internEmail: "budisantoso@gmail.com", submittedAt: "May 26, 2026", status: "Done" }, - { internEmail: "cindypermata@gmail.com", submittedAt: "-", status: "Pending" }, - { internEmail: "dewaaditya@gmail.com", submittedAt: "-", status: "Overdue" }, - { internEmail: "ekapratiwi@gmail.com", submittedAt: "May 28, 2026", status: "Done" }, - ], - }, - ], - }, - - { - id: 2, - name: "Rekrutmen Digital Platform", - description: - "Platform digital yang memudahkan proses rekrutmen karyawan baru secara end-to-end, mulai dari posting lowongan, seleksi berkas, hingga penjadwalan wawancara.", - interns: project2Interns, - mentor: "mas B", - progress: 37, - tasksDone: 3, - tasksTotal: 8, - tasks: [ - { - id: 1, - title: "Analisis Kebutuhan Sistem", - description: - "Dokumentasikan kebutuhan fungsional dan non-fungsional platform rekrutmen. Sertakan diagram use case dan daftar fitur prioritas.", - type: "file", - deadline: { date: new Date(2026, 4, 5), label: "May 5, 2026", time: "23:59 PM" }, - isSubmitted: false, - submittedCount: 4, - totalInterns: 6, - submissions: [ - { internEmail: "fajarnugroho@gmail.com", submittedAt: "May 4, 2026", status: "Done" }, - { internEmail: "gitalestari@gmail.com", submittedAt: "May 4, 2026", status: "Done" }, - { internEmail: "hendrawijaya@gmail.com", submittedAt: "May 5, 2026", status: "Done" }, - { internEmail: "indahpermata@gmail.com", submittedAt: "May 5, 2026", status: "Done" }, - { internEmail: "jokosusilo@gmail.com", submittedAt: "-", status: "Overdue" }, - { internEmail: "kartikadewi@gmail.com", submittedAt: "-", status: "Overdue" }, - ], - }, - { - id: 2, - title: "Desain Wireframe Aplikasi", - description: - "Buat wireframe low-fidelity untuk seluruh alur utama rekrutmen menggunakan Figma. Sertakan link yang dapat diakses oleh mentor.", - type: "link", - deadline: { date: new Date(2026, 4, 15), label: "May 15, 2026", time: "23:59 PM" }, - isSubmitted: false, - submittedCount: 3, - totalInterns: 6, - submissions: [ - { internEmail: "fajarnugroho@gmail.com", submittedAt: "May 13, 2026", status: "Done" }, - { internEmail: "gitalestari@gmail.com", submittedAt: "-", status: "Pending" }, - { internEmail: "hendrawijaya@gmail.com", submittedAt: "May 14, 2026", status: "Done" }, - { internEmail: "indahpermata@gmail.com", submittedAt: "-", status: "Pending" }, - { internEmail: "jokosusilo@gmail.com", submittedAt: "May 15, 2026", status: "Done" }, - { internEmail: "kartikadewi@gmail.com", submittedAt: "-", status: "Overdue" }, - ], - }, - ], - }, - - { - id: 3, - name: "E-Commerce Analytics Dashboard", - description: - "Dashboard analitik komprehensif untuk platform e-commerce, mencakup visualisasi data penjualan, perilaku pengguna, dan performa produk secara real-time.", - interns: project3Interns, - mentor: "Mas C", - progress: 50, - tasksDone: 4, - tasksTotal: 8, - tasks: [ - { - id: 1, - title: "Setup Pipeline Data", - description: - "Konfigurasi ETL pipeline dari database transaksi ke data warehouse. Dokumentasikan arsitektur pipeline dan sertakan screenshot hasil pengujian.", - type: "link", - deadline: { date: new Date(2026, 4, 3), label: "May 3, 2026", time: "23:59 PM" }, - isSubmitted: false, - submittedCount: 5, - totalInterns: 6, - submissions: [ - { internEmail: "mayaanggraeni@gmail.com", submittedAt: "May 2, 2026", status: "Done" }, - { internEmail: "nandapratama@gmail.com", submittedAt: "May 2, 2026", status: "Done" }, - { internEmail: "oscarfirmansyah@gmail.com", submittedAt: "May 3, 2026", status: "Done" }, - { internEmail: "putrihandayani@gmail.com", submittedAt: "May 3, 2026", status: "Done" }, - { internEmail: "rizkymaulana@gmail.com", submittedAt: "May 3, 2026", status: "Done" }, - { internEmail: "sariutami@gmail.com", submittedAt: "-", status: "Overdue" }, - ], - }, - { - id: 2, - title: "Implementasi Dashboard UI", - description: - "Implementasikan tampilan dashboard menggunakan React dan library chart pilihan. Pastikan responsive di desktop dan tablet.", - type: "file", - deadline: { date: new Date(2026, 4, 20), label: "May 20, 2026", time: "23:59 PM" }, - isSubmitted: false, - submittedCount: 2, - totalInterns: 6, - submissions: [ - { internEmail: "mayaanggraeni@gmail.com", submittedAt: "May 18, 2026", status: "Done" }, - { internEmail: "nandapratama@gmail.com", submittedAt: "-", status: "Pending" }, - { internEmail: "oscarfirmansyah@gmail.com", submittedAt: "May 19, 2026", status: "Done" }, - { internEmail: "putrihandayani@gmail.com", submittedAt: "-", status: "Pending" }, - { internEmail: "rizkymaulana@gmail.com", submittedAt: "-", status: "Pending" }, - { internEmail: "sariutami@gmail.com", submittedAt: "-", status: "Overdue" }, - ], - }, - ], - }, -]; \ No newline at end of file diff --git a/src/lib/mockSertificates.ts b/src/lib/mockSertificates.ts deleted file mode 100644 index 28fc585..0000000 --- a/src/lib/mockSertificates.ts +++ /dev/null @@ -1,74 +0,0 @@ -export interface Certificate { - id: string; - issuedDate: string; - recipientName: string; - programName: string; - duration: string; - finalScore: number; - grade: string; - status: string; -} - -export interface CertificateHistory { - id: number; - month: string; - title: string; - grade: string; -} - -export interface CertificateData { - isReceived: boolean; - projectProgress: number; - remainingTasks: number; - certificate: Certificate; -} - -export const certificateData: CertificateData = { - isReceived: false, - projectProgress: 90, - remainingTasks: 0, - certificate: { - id: "INF-2024-88392", - issuedDate: "24 Oct 2024", - recipientName: "JonathanKristina", - programName: "Internify Project", - duration: "8 Minggu", - finalScore: 94, - grade: "A", - status: "VERIFIED", - }, -}; - -export const history: CertificateHistory[] = [ - { - id: 1, - month: "Juni 2023", - title: "Web Development Fundamentals", - grade: "A+", - }, - { - id: 2, - month: "Maret 2023", - title: "UI/UX Design Essentials", - grade: "A", - }, - { - id: 3, - month: "Juni 2023", - title: "Web Development Advanced", - grade: "A+", - }, - { - id: 4, - month: "Maret 2023", - title: "UI/UX Design Advanced", - grade: "A", - } -] - -export const initialHistoryData = [ - { id: 1, name: "Jonathan Kristina", email: "JonathanKristina@gmail.com", project: "Internify Project", date: "24 Oct 2024", initials: "JK" }, - { id: 2, name: "Ahmad Faisal", email: "ahmad.faisal@gmail.com", project: "Web Dev Fundamentals", date: "15 Sep 2024", initials: "AF" }, - { id: 3, name: "Siti Rahma", email: "siti.rahma@gmail.com", project: "UI/UX Essentials", date: "10 Aug 2024", initials: "SR" }, - { id: 4, name: "David Beckham", email: "david.b@gmail.com", project: "Engineering Intern 101", date: "05 Aug 2024", initials: "DB" }, -]; \ No newline at end of file diff --git a/src/lib/mockTask.ts b/src/lib/mockTask.ts deleted file mode 100644 index e69de29..0000000