From 9e058e6ad7f4672d2e146915c5e2decacfd4f871 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 9 Jun 2026 15:21:08 +0200 Subject: [PATCH] feat(final-docs): finalist upload banner on applicant dashboard --- src/app/(applicant)/applicant/page.tsx | 4 ++ .../applicant/final-documents-banner.tsx | 61 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/components/applicant/final-documents-banner.tsx diff --git a/src/app/(applicant)/applicant/page.tsx b/src/app/(applicant)/applicant/page.tsx index 76e17d4..9660ff2 100644 --- a/src/app/(applicant)/applicant/page.tsx +++ b/src/app/(applicant)/applicant/page.tsx @@ -20,6 +20,7 @@ import { MentoringRequestCard } from '@/components/applicant/mentoring-request-c import { MentorConversationCard } from '@/components/applicant/mentor-conversation-card' import { AttendingMembersCard } from '@/components/applicant/attending-members-card' import { MyLogisticsCard } from '@/components/applicant/my-logistics-card' +import { FinalDocumentsBanner } from '@/components/applicant/final-documents-banner' import { LunchBanner } from '@/components/applicant/lunch-banner' import { ExternalAttendeesStrip } from '@/components/applicant/external-attendees-strip' import { AnimatedCard } from '@/components/shared/animated-container' @@ -206,6 +207,9 @@ export default function ApplicantDashboardPage() { + {/* Grand Final document upload banner (auto-hides for non-finalists) */} + + {/* Active round deadline banner */} {!isRejected && openRounds.length > 0 && (() => { const submissionTypes = new Set(['INTAKE', 'SUBMISSION', 'MENTORING']) diff --git a/src/components/applicant/final-documents-banner.tsx b/src/components/applicant/final-documents-banner.tsx new file mode 100644 index 0000000..614be06 --- /dev/null +++ b/src/components/applicant/final-documents-banner.tsx @@ -0,0 +1,61 @@ +'use client' + +import Link from 'next/link' +import { trpc } from '@/lib/trpc/client' +import { Card, CardContent } from '@/components/ui/card' +import { Button } from '@/components/ui/button' +import { FileText, Video, CheckCircle2, Circle, Clock, Upload } from 'lucide-react' + +export function FinalDocumentsBanner() { + const { data: status } = trpc.applicant.getFinalDocumentStatus.useQuery() + if (!status) return null + + const fmt = new Intl.DateTimeFormat(undefined, { dateStyle: 'long', timeStyle: 'short' }) + const zone = new Intl.DateTimeFormat(undefined, { timeZoneName: 'short' }) + .formatToParts(new Date()).find((p) => p.type === 'timeZoneName')?.value + const uploadedCount = status.requirements.filter((r) => r.uploaded).length + const total = status.requirements.length + const done = status.allRequiredUploaded + + return ( + + +
+
+ {done ? : } + + {done ? 'Grand Final documents submitted' : 'Upload your Grand Final documents'} + + ({uploadedCount} of {total}) +
+ {status.deadline && ( + + + {status.deadlinePassed ? 'Deadline passed' : 'Due'}: {fmt.format(new Date(status.deadline))} + {zone ? ` (${zone})` : ''} + + )} +
+
+ {status.requirements.map((r) => { + const Icon = r.acceptedMimeTypes.some((m) => m.startsWith('video/')) ? Video : FileText + return ( + + {r.uploaded ? : } + + {r.name} + + ) + })} +
+ {!done && ( + + )} +
+
+ ) +}