import React, { useState, useMemo, useEffect } from 'react'; import { createPortal } from 'react-dom'; import { Event } from '../types'; import { uploadToSupabase, supabase } from '../supabase'; interface StatusTrackerViewProps { event: Event; registration?: any; onBack: () => void; onUploadCertificate: (data: string) => Promise; onShowCreateTeam?: () => void; onShowJoinTeam?: () => void; } const SuccessPopup: React.FC<{ onClose: () => void }> = ({ onClose }) => (

File Captured

Proof uploaded successfully

); const StatusTrackerView: React.FC = ({ event, registration, onBack, onUploadCertificate, onShowCreateTeam, onShowJoinTeam }) => { const fileInputRef = React.useRef(null); const [isUploading, setIsUploading] = useState(false); const [showSuccess, setShowSuccess] = useState(false); const [now, setNow] = useState(new Date()); const [attendanceRecords, setAttendanceRecords] = useState([]); const fetchAttendance = async () => { if (!registration?.id) return; const { data, error } = await supabase .from('attendance_records') .select('*') .eq('registration_id', registration.id); if (!error && data) { setAttendanceRecords(data); } }; const odUrl = registration?.od_url || registration?.od; const certUrl = registration?.certification_url || registration?.certifications; const certStatus = registration?.certification_status || registration?.certification_approval; const [liveOdUrl, setLiveOdUrl] = useState(odUrl); const [liveCertUrl, setLiveCertUrl] = useState(certUrl); const [liveCertStatus, setLiveCertStatus] = useState(certStatus); useEffect(() => { // Dynamic refetch to catch real-time faculty OD uploads without full page reload if (registration?.id) { supabase.from('registrations').select('*').eq('id', registration.id).single().then(({ data }) => { if (data) { setLiveOdUrl(data.od_url || data.od); setLiveCertUrl(data.certification_url || data.certifications); setLiveCertStatus(data.certification_status || data.certification_approval); } }); } if (registration?.id) { fetchAttendance(); // Real-time subscription for attendance const channel = supabase .channel(`attendance-${registration.id}`) .on( 'postgres_changes', { event: '*', schema: 'public', table: 'attendance_records', filter: `registration_id=eq.${registration.id}` }, () => { fetchAttendance(); } ) .subscribe(); return () => { supabase.removeChannel(channel); }; } const timer = setInterval(() => setNow(new Date()), 30000); return () => clearInterval(timer); }, [registration?.id, event.id]); const isEventEnded = event.status === 'Completed'; const progressSteps = useMemo(() => { const isFree = event.pricingType === 'FREE'; const isPaidVerified = registration?.payment_status === 'COMPLETED'; const isManuallyEnded = event.status === 'Completed'; const isManuallyOngoing = event.status === 'Event Ongoing'; const isEnded = isManuallyEnded; const isOngoing = isManuallyOngoing; const hasUploaded = !!liveCertUrl; const isApproved = liveCertStatus === 'APPROVED'; const hasUploadedOd = !!liveOdUrl; return [ { label: 'Registered', status: 'completed', icon: 'fa-user-check', color: 'bg-emerald-500', detail: 'Identity Secured' }, { label: 'TEAM', status: !event.isTeamEvent || registration?.team_code ? 'completed' : 'active', icon: 'fa-users', color: 'bg-orange-500', detail: !event.isTeamEvent ? 'Solo Mode' : (registration?.team_code ? `Team: ${registration.team_name || 'Joined'}` : 'Wait for Team') }, { label: 'Payment', status: isFree || isPaidVerified ? 'completed' : 'active', icon: 'fa-credit-card', color: 'bg-blue-400', detail: isFree ? 'Waiver Applied' : (isPaidVerified ? 'Funds Verified' : 'Awaiting Payment') }, { label: 'Ticket', status: isFree || isPaidVerified ? 'completed' : 'pending', icon: 'fa-ticket-alt', color: 'bg-amber-500', detail: isFree || isPaidVerified ? 'Access Granted' : 'Locked' }, { label: 'Ongoing', status: isEnded ? 'completed' : (isOngoing ? 'active' : 'pending'), icon: 'fa-play-circle', color: 'bg-purple-500', detail: isOngoing ? 'Live Session' : (isEnded ? 'Session Ended' : 'Scheduled') }, { label: 'Ended', status: isEnded ? 'completed' : 'pending', icon: 'fa-calendar-check', color: 'bg-rose-500', detail: isEnded ? 'Archived' : 'Wait for Admin' }, { label: 'Certification', status: isApproved ? 'completed' : (isEnded ? 'active' : 'pending'), icon: isApproved ? 'fa-check-double' : (hasUploaded ? 'fa-spinner fa-spin' : 'fa-award'), color: isApproved ? 'bg-emerald-600' : (isEnded ? 'bg-amber-500' : 'bg-indigo-600'), detail: isApproved ? 'Verified by Faculty' : (hasUploaded ? 'In Review' : (isEnded ? 'Upload Proof' : 'Wait for End')) }, { label: 'OD', status: hasUploadedOd ? 'completed' : (isApproved ? 'active' : 'pending'), icon: 'fa-file-signature', color: 'bg-teal-500', detail: hasUploadedOd ? 'OD Provided' : (isApproved ? 'Ready for Download' : 'Wait for Approval') }, ]; }, [event, registration, now, liveOdUrl, liveCertUrl, liveCertStatus]); const handleOdDownload = async () => { if (!liveOdUrl) return; try { const response = await fetch(liveOdUrl); const blob = await response.blob(); const isPdf = liveOdUrl.toLowerCase().endsWith('.pdf') || blob.type === 'application/pdf'; const extension = isPdf ? 'pdf' : 'jpg'; const blobUrl = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = blobUrl; link.download = `OD_${event.title.replace(/\s+/g, '_')}.${extension}`; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(blobUrl); } catch (err) { console.error("OD Download failed:", err); // Fallback: just open the URL directly if local fetch somehow fails window.open(liveOdUrl, '_blank'); } }; const handleFileChange = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; const { data: { user } } = await supabase.auth.getUser(); if (file && user && registration) { setIsUploading(true); const reader = new FileReader(); reader.onloadend = async () => { try { const base64 = reader.result as string; const fileName = `Cert_${user.id}_${event.id}_${Date.now()}.jpg`; // STORE IN 'Certifications' BUCKET AS REQUESTED const publicUrl = await uploadToSupabase(base64, fileName, 'Certifications'); await supabase.from('registrations').update({ certification_url: publicUrl, certification_status: 'PENDING_APPROVAL' }).eq('id', registration.id); setShowSuccess(true); } catch (err) { console.error("Upload failed:", err); alert("Upload failed. Please check your connection or bucket permissions."); } finally { setIsUploading(false); } }; reader.readAsDataURL(file); } }; return (
{showSuccess && { setShowSuccess(false); window.location.reload(); }} />}

REAL-TIME PROGRESS

Tracking Node: {event.title}

{/* Continuous Line Background */}
{/* Active Line Foreground */}
s.status === 'active') !== -1 ? progressSteps.findIndex(s => s.status === 'active') : Math.max(0, progressSteps.filter(s => s.status === 'completed').length - 1)) / (progressSteps.length - 1) } * (100% - ${100 / progressSteps.length}%))` }} >
{/* Steps Container */}
{progressSteps.map((step, idx) => (
{/* Dot */}
{/* Icon */}
{/* Text */}
{step.label}

{step.detail}

))}
{/* Attendance Tracker Redesign (Node-based) */}
Attendance Milestones
{(() => { const allSessions: { label: string, status: string, day: string, batch: string }[] = []; if (event.schedule && event.schedule.length > 0) { // Group by day_idx const dayMap = new Map(); event.schedule.forEach(s => { if (!dayMap.has(s.day_idx)) dayMap.set(s.day_idx, []); dayMap.get(s.day_idx)!.push(s); }); const sortedDays = Array.from(dayMap.entries()).sort((a, b) => a[0] - b[0]); sortedDays.forEach(([dayIdx, slots]) => { slots!.forEach((slot) => { const dLabel = `Day ${dayIdx}`; const bLabel = `Batch ${slot.batch_idx}`; const record = attendanceRecords.find(r => r.day_label === dLabel && r.batch_label === bLabel); allSessions.push({ label: `D${dayIdx} B${slot.batch_idx}`, day: dLabel, batch: bLabel, status: record?.is_present ? 'completed' : (record?.is_present === false ? 'absent' : 'pending') }); }); }); } else { const record = attendanceRecords.find(r => r.day_label === 'Day 1'); allSessions.push({ label: 'Day 1', day: 'Day 1', batch: '', status: record?.is_present ? 'completed' : (record?.is_present === false ? 'absent' : 'pending') }); } return (
{/* Connecting Line Background */}
{/* Connecting Line Foreground */}
s.status === 'pending') !== -1 ? Math.max(0, allSessions.findIndex(s => s.status === 'pending') - 1) : Math.max(0, allSessions.filter(s => s.status === 'completed').length - 1)) / Math.max(1, allSessions.length - 1) } * (100% - ${100 / allSessions.length}%))` }} >
{/* Nodes */}
{allSessions.map((session, sIdx) => (
{/* Dot on line */}
{/* Large Circle Shaped Indicator */}
{/* Text */}
{session.label}

{session.status === 'completed' ? 'Attended' : session.status === 'absent' ? 'Absent' : 'Upcoming'}

))}
); })()}

{attendanceRecords.filter(r => r.is_present).length} / {Math.max(1, event.schedule?.length || 1)} Sessions Attended

{/* Team Management Buttons - Relocated from RegistrationsView */} {event.isTeamEvent && !registration?.team_code && (
Team Management

This is a team event. Form your own team or join an existing alliance to participate in this competition.

)}
{/* OD Document Download Section */} {liveOdUrl && (

Official On-Duty Document

Authorized by Faculty Coordinator

Inspect
)}

Certification Portal

Provide valid proof of attendance or task completion to finalize your official event participation.

{!isEventEnded ? (

Upload unlocks once admin marks event as Ended

) : ( <> {liveCertStatus === 'PENDING_APPROVAL' && (

Awaiting Faculty Review

)} )}
{liveCertUrl ? ( Proof ) : (

Preview Area

)}

Event Info

Conducting Club {event.club || 'N/A'}
Enrollment Status {registration?.payment_status || 'PENDING'}
{event.durationDays && (
Duration {event.durationDays} Days
)} {event.schedule && event.schedule.length > 0 && (
Sessions {event.schedule.length} Total
)}
Attendance Progress {attendanceRecords.filter(r => r.is_present).length} Marked
Certification {liveCertStatus?.replace('_', ' ') || 'NOT SUBMITTED'}
Verification Status {liveCertStatus === 'APPROVED' ? 'Finalized' : 'Pending'}
); }; export default StatusTrackerView;