import { FC, ReactElement, useState, useEffect } from 'react'; import { ControlledInputField } from '@imphnen-frontend-service/ui/organisms'; import { Button, Textarea } from '@imphnen-frontend-service/ui/atoms'; import { useNavigate, useParams } from 'react-router'; import { useForm, Controller } from 'react-hook-form'; import { projectSubmissionSchema, TProjectSubmissionForm, useSubmitProject, useTeamById, useTeamSubmission, useUploadFile, useAuthStore, } from '@imphnen-frontend-service/service'; import { zodResolver } from '@hookform/resolvers/zod'; import { toast } from 'sonner'; import { Icon } from '@iconify/react'; const MIN_TEAM_MEMBERS = 2; // Minimum members required to submit (including leader) const MAX_FILE_SIZE = 2 * 1024 * 1024; // 2MB // Submission deadline: 2025-12-07 23:59:00 WIB (UTC+7) const SUBMISSION_DEADLINE = new Date('2025-12-07T16:59:00Z'); const SubmitProjectPage: FC = (): ReactElement => { const { teamId } = useParams<{ teamId: string }>(); const navigate = useNavigate(); const { session } = useAuthStore(); const [showConfirmModal, setShowConfirmModal] = useState(false); const [confirmText, setConfirmText] = useState(''); const [screenshots, setScreenshots] = useState([]); const [timeLeft, setTimeLeft] = useState<{ days: number; hours: number; minutes: number; seconds: number; } | null>(null); // Check if deadline passed const isDeadlinePassed = new Date() >= SUBMISSION_DEADLINE; // Countdown timer useEffect(() => { if (isDeadlinePassed) return; const calculateTimeLeft = () => { const now = new Date(); const difference = SUBMISSION_DEADLINE.getTime() - now.getTime(); if (difference <= 0) { setTimeLeft(null); return; } const days = Math.floor(difference / (1000 * 60 * 60 * 24)); const hours = Math.floor((difference / (1000 * 60 * 60)) % 24); const minutes = Math.floor((difference / 1000 / 60) % 60); const seconds = Math.floor((difference / 1000) % 60); setTimeLeft({ days, hours, minutes, seconds }); }; calculateTimeLeft(); const timer = setInterval(calculateTimeLeft, 1000); return () => clearInterval(timer); }, [isDeadlinePassed]); const { data: teamData } = useTeamById(teamId || ''); const { data: submissionData } = useTeamSubmission(teamId || '', !!teamId); const { mutateAsync: submitProject, isPending: isSubmitting } = useSubmitProject(teamId || ''); const { mutateAsync: uploadFile, isPending: isUploading } = useUploadFile(); const team = teamData?.data; const currentUserId = session?.user?.id; const isLeader = currentUserId === team?.leader_id; const hasSubmission = !!submissionData?.data; const memberCount = team?.members?.length || 0; const hasEnoughMembers = memberCount >= MIN_TEAM_MEMBERS; const form = useForm({ resolver: zodResolver(projectSubmissionSchema), mode: 'all', }); if (!isLeader) { return (

Access Denied

Only the team leader can submit projects

); } if (hasSubmission) { return (

Project Already Submitted

Your team has already submitted a project

); } // Show deadline passed screen if (isDeadlinePassed) { return (

Submission Closed

Project submissions are no longer accepted.

The submission deadline was December 7, 2025 at 23:59 WIB.

); } const handleScreenshotUpload = async ( e: React.ChangeEvent ) => { const files = e.target.files; if (!files) return; // Validate file sizes const oversizedFiles = Array.from(files).filter(file => file.size > MAX_FILE_SIZE); if (oversizedFiles.length > 0) { toast.error(`${oversizedFiles.length} file(s) are too large. Maximum size is 2MB per file.`); e.target.value = ''; return; } try { const uploadPromises = Array.from(files).map((file) => uploadFile(file)); const results = await Promise.all(uploadPromises); const urls = results.map((r) => r.data.url); setScreenshots([...screenshots, ...urls]); } catch (error) { console.error('Failed to upload screenshots:', error); toast.error('Failed to upload screenshots. Please try again.'); } }; const removeScreenshot = (index: number) => { setScreenshots(screenshots.filter((_, i) => i !== index)); }; const onSubmit = form.handleSubmit(async (data) => { try { await submitProject({ ...data, screenshots, }); navigate(`/teams/${teamId}/submission`); } catch (error) { console.error('Failed to submit project:', error); } }); return (

Submit Project

{team?.name}

{/* Countdown Timer */} {timeLeft && (

Submission Deadline

Submissions close on December 7, 2025 at 23:59 WIB

{timeLeft.days}
Days
{timeLeft.hours.toString().padStart(2, '0')}
Hours
{timeLeft.minutes.toString().padStart(2, '0')}
Minutes
{timeLeft.seconds.toString().padStart(2, '0')}
Seconds
)} {/* Minimum Members Warning */} {!hasEnoughMembers && (
👥

Team Members Required

Your team needs at least {MIN_TEAM_MEMBERS} members to submit a project. Currently you have {memberCount} member{memberCount !== 1 ? 's' : ''}. Please invite more members to your team before submitting.

)} {/* Warning Banner */}
⚠️

IMPORTANT WARNING

  • • You can only submit your project ONCE
  • • After submission, you CANNOT edit or change anything
  • • Make sure all information is correct before submitting
  • • Review your project details carefully
{ e.preventDefault(); setShowConfirmModal(true); }} className="space-y-6" > {/* Project Name */} {/* Description */}

Describe your project, its features, and what problem it solves. You can also paste your demo video link here.

(