From 41349e5303d8a030d26611a2983b106ce13013a0 Mon Sep 17 00:00:00 2001
From: "Kemas M. Aryadary Rasyad"
<112590882+aryadary0706@users.noreply.github.com>
Date: Wed, 29 Jul 2026 01:29:16 +0700
Subject: [PATCH] feat: implement certificate history, intern submission views,
and task management hooks
---
src/Pages/Landing.tsx | 6 -
.../internify/intern/InternCertDetail.tsx | 14 ++-
.../intern/components/CertificateAvailabe.tsx | 21 ++--
.../intern/components/CertificateHistory.tsx | 5 +-
.../components/CertificateNotAvailable.tsx | 17 ++-
.../internify/mentor/ViewInternSubmission.tsx | 6 +-
.../mentor/components/EditSubmissionTask.tsx | 21 +++-
.../mentor/components/EditTaskDialog.tsx | 2 -
src/Pages/utils/testlayout.html | 108 ------------------
src/assets/template.png | Bin 228883 -> 0 bytes
src/hooks/useTasks.ts | 3 +-
11 files changed, 56 insertions(+), 147 deletions(-)
delete mode 100644 src/Pages/utils/testlayout.html
delete mode 100644 src/assets/template.png
diff --git a/src/Pages/Landing.tsx b/src/Pages/Landing.tsx
index b7a5d27..0880609 100644
--- a/src/Pages/Landing.tsx
+++ b/src/Pages/Landing.tsx
@@ -58,12 +58,6 @@ const Landing = () => {
return feedbacks[displayIndex];
}, [feedbacks, displayIndex]);
- // Gambar statis: selalu pakai foto dari feedback pertama
- const staticImgUrl = useMemo(() => {
- if (feedbacks.length === 0) return "";
- return getFeedbackImageUrl(feedbacks[0].image_path);
- }, [feedbacks]);
-
useEffect(() => {
// Fetch internships
fetch(`${import.meta.env.VITE_API_BASE_URL}/lowongan-magang-api/get`)
diff --git a/src/Pages/internify/intern/InternCertDetail.tsx b/src/Pages/internify/intern/InternCertDetail.tsx
index de7f6ad..bfaa0f4 100644
--- a/src/Pages/internify/intern/InternCertDetail.tsx
+++ b/src/Pages/internify/intern/InternCertDetail.tsx
@@ -32,7 +32,12 @@ export default function InternCertificateDetail() {
};
}, [projectDetail, projectFromList]);
- const allTasksDone = !projectLoading && !!project && project.task_done >= project.total_tasks;
+
+ const allTasksDone =
+ !projectLoading &&
+ !!project &&
+ (project.total_tasks ?? 0) > 0 &&
+ project.task_done >= project.total_tasks;
const progress =
project && project.total_tasks > 0
@@ -50,10 +55,8 @@ export default function InternCertificateDetail() {
- {myCertificateForProject ? (
+ {myCertificateForProject && (project?.total_tasks ?? 0) > 0 ? (
@@ -79,6 +82,7 @@ export default function InternCertificateDetail() {
progress={progress}
remainingTasks={remainingTasks}
allTasksDone={allTasksDone}
+ noTasks={(project?.total_tasks ?? 0) === 0}
/>
)}
diff --git a/src/Pages/internify/intern/components/CertificateAvailabe.tsx b/src/Pages/internify/intern/components/CertificateAvailabe.tsx
index fbceb0d..aea9320 100644
--- a/src/Pages/internify/intern/components/CertificateAvailabe.tsx
+++ b/src/Pages/internify/intern/components/CertificateAvailabe.tsx
@@ -123,7 +123,7 @@ export default function CertificateAvailable({ project, certificate, templateUrl
{/* Program Summary */}
-
+
Ringkasan Program
@@ -138,13 +138,13 @@ export default function CertificateAvailable({ project, certificate, templateUrl
key={row.label}
className="flex justify-between items-center text-sm border-b border-card-outline pb-2 last:border-0"
>
- {row.label}
- {row.value}
+ {row.label}
+ {row.value}
))}
-
+ {/* End Program Summary */}
{/* Unduh Sertifikat */}
@@ -174,20 +174,19 @@ export default function CertificateAvailable({ project, certificate, templateUrl
diff --git a/src/Pages/internify/intern/components/CertificateHistory.tsx b/src/Pages/internify/intern/components/CertificateHistory.tsx
index 5cea127..235380d 100644
--- a/src/Pages/internify/intern/components/CertificateHistory.tsx
+++ b/src/Pages/internify/intern/components/CertificateHistory.tsx
@@ -35,11 +35,12 @@ export default function SertificateHistory() {
{displayed.map((item: Certificate) => (
{new Date(item.issued_at).toLocaleDateString("id-ID", {
+ day: "numeric",
year: "numeric",
month: "long",
})}
@@ -47,7 +48,7 @@ export default function SertificateHistory() {
{item.project.project_name}
-
{item.certificate_no}
+
{item.certificate_no}
))}
diff --git a/src/Pages/internify/intern/components/CertificateNotAvailable.tsx b/src/Pages/internify/intern/components/CertificateNotAvailable.tsx
index c1e9faa..0fde6c9 100644
--- a/src/Pages/internify/intern/components/CertificateNotAvailable.tsx
+++ b/src/Pages/internify/intern/components/CertificateNotAvailable.tsx
@@ -1,16 +1,19 @@
import { Clock, Lock } from "lucide-react";
import { FaAward } from "react-icons/fa";
+import { ListTodo } from "lucide-react";
interface CertificateNotAvailableProps {
progress: number;
remainingTasks: number;
allTasksDone?: boolean;
+ noTasks?: boolean;
}
export default function CertificateNotAvailable({
progress,
remainingTasks,
allTasksDone = false,
+ noTasks = false,
}: CertificateNotAvailableProps) {
return (
@@ -18,7 +21,9 @@ export default function CertificateNotAvailable({
- {allTasksDone ? (
+ {noTasks ? (
+
+ ) : allTasksDone ? (
) : (
@@ -30,7 +35,15 @@ export default function CertificateNotAvailable({
- {allTasksDone ? (
+ {noTasks ? (
+ <>
+
Sertifikat Belum Tersedia
+
+ Proyek ini belum memiliki tugas yang ditetapkan.
+ Sertifikat akan tersedia setelah semua tugas proyek diselesaikan.
+
+ >
+ ) : allTasksDone ? (
<>
Selamat!
diff --git a/src/Pages/internify/mentor/ViewInternSubmission.tsx b/src/Pages/internify/mentor/ViewInternSubmission.tsx
index e43778e..c3cf86e 100644
--- a/src/Pages/internify/mentor/ViewInternSubmission.tsx
+++ b/src/Pages/internify/mentor/ViewInternSubmission.tsx
@@ -1,5 +1,5 @@
import { useParams, useLocation } from "react-router-dom";
-import { Download, Clock, AlertCircle } from "lucide-react";
+import { Download, AlertCircle, User2 } from "lucide-react";
import { useTaskSubmissions } from "../../../hooks/useTasks";
import type { DisplayStatus } from "../../../types/task.types";
import { StatusTable } from "./components/StatusSubmissionTable";
@@ -50,8 +50,8 @@ export default function ViewInternSubmission() {
{task.title}
-
- {internSubmission.full_name} — {internSubmission.email}
+
+ {internSubmission.full_name}
diff --git a/src/Pages/internify/mentor/components/EditSubmissionTask.tsx b/src/Pages/internify/mentor/components/EditSubmissionTask.tsx
index 886c0fc..44d0c51 100644
--- a/src/Pages/internify/mentor/components/EditSubmissionTask.tsx
+++ b/src/Pages/internify/mentor/components/EditSubmissionTask.tsx
@@ -20,8 +20,6 @@ export default function EditSubmissionModal({
}: EditTaskModalProps) {
const dialogRef = useRef
(null);
const { update, loading, error } = useUpdateTask();
-
- // Form States — diinisialisasi dari props task
const [taskTitle, setTaskTitle] = useState(task.title);
const [description, setDescription] = useState(task.description);
const [deadlineDate, setDeadlineDate] = useState(
@@ -32,7 +30,9 @@ export default function EditSubmissionModal({
);
const [submissionType, setSubmissionType] = useState(task.submission_type);
- // Sync form ketika task berubah (misal modal dibuka untuk task berbeda)
+ const today = new Date().toISOString().split("T")[0];
+ const isDeadlinePast = !!deadlineDate && deadlineDate < today;
+
useEffect(() => {
setTaskTitle(task.title);
setDescription(task.description);
@@ -108,7 +108,7 @@ export default function EditSubmissionModal({
{/* Error Message */}
{error && (
-
+
{error}
)}
@@ -148,9 +148,18 @@ export default function EditSubmissionModal({
required
value={deadlineDate}
onChange={(e) => setDeadlineDate(e.target.value)}
- className="w-full p-3 py-2.5 bg-white border border-gray-200 rounded-lg text-sm font-medium text-gray-800 focus:outline-none focus:border-[#B30000] focus:ring-1 focus:ring-[#B30000] appearance-none"
+ className={`w-full p-3 py-2.5 bg-white border rounded-lg text-sm font-medium text-gray-800 focus:outline-none appearance-none ${
+ isDeadlinePast
+ ? "border-red-400 focus:border-red-500 focus:ring-1 focus:ring-red-400"
+ : "border-gray-200 focus:border-[#B30000] focus:ring-1 focus:ring-[#B30000]"
+ }`}
/>
+ {isDeadlinePast && (
+
+ Tenggat waktu tidak boleh sebelum hari ini.
+
+ )}