feat: add CertificateForm and CertificateResult components for managing intern certificates

- Implemented CertificateForm for uploading certificate templates and displaying project details.
- Created CertificateResult to show generated certificates with pagination and search functionality.
- Added EligibleInternTable component to display eligible interns and their progress.
- Updated CertificateListPage to reflect changes in project listing styles.
- Enhanced MentorProjectCard with dynamic icon rendering.
- Introduced useProjectInternProgress hook for fetching intern progress data.
- Modified ProjectService to include task details in project responses.
- Updated project types to accommodate new task structures.
This commit is contained in:
Kemas M. Aryadary Rasyad
2026-06-28 22:22:03 +07:00
parent 37e21a1f39
commit 732684200f
17 changed files with 612 additions and 371 deletions
@@ -3,7 +3,7 @@ import type { Project } from "../../../../types/project.types";
// ─── StatusBadge ─────────────────────────────────────────────────────────────
function StatusBadge({ status }: { status: string }) {
const isCompleted = status === "COMPLETED";
const isCompleted = status === "archived";
return (
<span
className={`text-[10px] font-extrabold tracking-wider px-2.5 py-1 rounded-full border ${
@@ -17,6 +17,19 @@ function StatusBadge({ status }: { status: string }) {
);
}
function formatDateRange(start: string, end: string): string {
const options: Intl.DateTimeFormatOptions = {
day: "numeric",
month: "long",
year: "numeric",
};
const startDate = new Date(start).toLocaleDateString("id-ID", options);
const endDate = new Date(end).toLocaleDateString("id-ID", options);
return `${startDate} – ${endDate}`;
}
// ─── ProjectCard ──────────────────────────────────────────────────────────────
export default function CertificateProjectCard({
project,
@@ -28,7 +41,7 @@ export default function CertificateProjectCard({
return (
<div
onClick={onClick}
className="bg-white border border-gray-200 rounded-2xl p-5 cursor-pointer hover:shadow-md hover:border-gray-300 transition-all duration-200 flex flex-col gap-4"
className="bg-white border border-card-outline rounded-2xl p-5 cursor-pointer hover:shadow-md hover:border-gray-300 transition-all duration-200 flex flex-col gap-4"
>
{/* Top: status badge */}
<div className="flex items-start justify-between">
@@ -37,21 +50,21 @@ export default function CertificateProjectCard({
{/* Title + period */}
<div>
<h3 className="text-sm font-bold text-gray-900 leading-snug mb-1.5">
<h3 className="text-sm font-bold text-font-shade leading-snug mb-1.5">
{project.project_name}
</h3>
<div className="flex items-center gap-1.5 text-[11px] text-gray-400 font-medium">
<div className="flex items-center gap-1.5 text-[11px] text-font font-medium">
<CalendarDays className="w-3.5 h-3.5 flex-shrink-0" />
<span>{project.start_date} - {project.end_date}</span>
<span>{formatDateRange(project.start_date, project.end_date)}</span>
</div>
</div>
<hr className="border-gray-100" />
<hr className="border-card-outline" />
{/* Intern count */}
<div className="flex items-center justify-between">
<div>
<p className="text-[10px] text-gray-400 font-medium mb-0.5">Interns</p>
<p className="text-[10px] text-font font-medium mb-0.5">Interns</p>
<p className="text-sm font-extrabold text-[#B30000]">
{project.total_members} interns
</p>