import { FC, ReactElement, useEffect, useMemo, useState } from 'react'; import { Link, useNavigate } from 'react-router'; import { useMyTeams, useMyInvitations, useRespondToInvitation, useAuthStore, useWinners, } from '@imphnen-frontend-service/service'; import { toast } from 'sonner'; import { Button } from '@imphnen-frontend-service/ui/atoms'; import { Icon } from '@iconify/react'; import ProfilePage from '../profile/page'; import { encodeWinnerCertificateId } from '../../utils/certificate'; // Team features deadline: 2025-11-30 23:59:00 WIB (UTC+7) const TEAM_FEATURES_DEADLINE = new Date('2025-11-30T16:59:00Z'); // Submission deadline: 2025-12-07 23:59:00 WIB (UTC+7) const SUBMISSION_DEADLINE = new Date('2025-12-07T16:59:00Z'); type Invitation = { id: string; team: { id?: string; name?: string; logo?: string; banner?: string; description?: string; city?: string; visibility?: string; leader_id?: string; }; inviter: { id?: string; fullname?: string; email?: string; avatar?: string; }; }; const DashboardPage: FC = (): ReactElement => { const { session } = useAuthStore(); const navigate = useNavigate(); const [showProfileModal, setShowProfileModal] = useState(false); const [timeLeft, setTimeLeft] = useState<{ days: number; hours: number; minutes: number; seconds: number; } | null>(null); // Check if team features are closed const isTeamFeaturesClosed = new Date() >= TEAM_FEATURES_DEADLINE; // Check if submission deadline passed const isSubmissionDeadlinePassed = new Date() >= SUBMISSION_DEADLINE; // Countdown timer useEffect(() => { if (isSubmissionDeadlinePassed) 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); }, [isSubmissionDeadlinePassed]); // Lock background scroll when profile modal is open useEffect(() => { if (showProfileModal) { const originalOverflow = document.body.style.overflow; document.body.style.overflow = 'hidden'; return () => { document.body.style.overflow = originalOverflow || ''; }; } }, [showProfileModal]); const { data: teamsData } = useMyTeams(); const { data: winnersResponse } = useWinners(); const { data: invitationsData } = useMyInvitations(); const { mutateAsync: respondToInvitation } = useRespondToInvitation(); const user = session?.user; const myTeams = teamsData?.data || []; const invitations: Invitation[] = (invitationsData?.data || []) as Invitation[]; const winnerEntry = useMemo(() => { const team = (myTeams[0] as { id?: string } | null | undefined) || null; const winners = winnersResponse?.data || []; if (!team?.id) return null; return winners.find((w) => w.team_id === team.id) || null; }, [myTeams, winnersResponse?.data]); const handleAcceptInvitation = async (invitationId: string) => { try { await respondToInvitation({ invitationId, action: 'accept' }); toast.success('Invitation accepted! You are now a team member.'); } catch (error) { console.error('Failed to accept invitation:', error); toast.error('Failed to accept invitation'); } }; const handleRejectInvitation = async (invitationId: string) => { try { await respondToInvitation({ invitationId, action: 'reject' }); toast.success('Invitation declined'); } catch (error) { console.error('Failed to reject invitation:', error); toast.error('Failed to decline invitation'); } }; return ( <>

Welcome, {user?.fullname || user?.email?.split('@')[0] || 'User'}!

{user?.location && (

{user.location}

)}
{/* Winner Banner */} {winnerEntry && myTeams.length > 0 && (
🏆

Selamat! Tim Anda meraih JUARA {winnerEntry.rank}

Anda dapat generate sertifikat penghargaan dan membagikannya.

)} {/* Countdown Timer */} {timeLeft && !isSubmissionDeadlinePassed && (

Submission Deadline

Project 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
)} {invitations.length > 0 && (

Team Invitations ({invitations.length})

{isTeamFeaturesClosed && (

Team features are closed. You can no longer accept invitations.

)}
{invitations.map((invitation) => (

{invitation.team?.name ?? 'Unnamed Team'}

Invited by{' '} {invitation.inviter?.fullname ?? 'Unknown User'}

{!isTeamFeaturesClosed && (
)}
))}
)} {myTeams.length > 0 ? ( (() => { const team = myTeams[0] as any; return (

My Team

{team.name}
{team.logo ? ( {team.name} ) : (
)}

{team.name}

{team.has_submission && ( Submitted )} {team.city && ( {team.city} )} {team.member_count || team.members?.length || 0}{' '} member {(team.member_count || team.members?.length || 0) !== 1 ? 's' : ''}
{team.description && (

{team.description}

)}
); })() ) : (
👋

You are not in a team yet

Use the sidebar to browse teams or create your own

)}
{user?.avatar ? ( {user.fullname ) : (
U
)}

{user?.fullname || user?.email?.split('@')[0] || 'Unnamed User'}

{user?.location ? (

{user.location}

) : ( Complete your profile )}
{user?.location && ( )}
{user?.bio && (

About

{user.bio}

)}

Contact

{user?.email}
{user?.skills && user.skills.length > 0 && (

Skills

{user.skills.map((skill: string) => ( {skill} ))}
)}
setShowProfileModal(false)} /> ); }; export default DashboardPage;