import React, { useState, useMemo, useEffect } from 'react'; import { createPortal } from 'react-dom'; import { Event } from '../types'; import { CATEGORIES, DOMAIN_MAP } from '../constants'; import { supabase } from '../supabase'; import * as XLSX from 'xlsx-js-style'; type ParticipantsSubView = 'CATEGORIES' | 'DOMAINS' | 'EVENTS' | 'STUDENTS'; interface FacultyParticipantsViewProps { events: Event[]; localRegistrations?: any[]; currentUserId?: string; } const FacultyParticipantsView: React.FC = ({ events, localRegistrations = [], currentUserId }) => { const [currentView, setCurrentView] = useState('STUDENTS'); const [selectedCategory, setSelectedCategory] = useState(null); const [selectedDomain, setSelectedDomain] = useState(null); const [selectedEventId, setSelectedEventId] = useState(null); const [searchTerm, setSearchTerm] = useState(''); const [showEventFilter, setShowEventFilter] = useState(false); const [showSideFilter, setShowSideFilter] = useState(false); const [selectedDepts, setSelectedDepts] = useState([]); const [selectedYears, setSelectedYears] = useState([]); const [activeFilterTab, setActiveFilterTab] = useState<'DEPT' | 'YEAR'>('DEPT'); const [registrations, setRegistrations] = useState(localRegistrations); const [isLoading, setIsLoading] = useState(true); const [selectedStudentIds, setSelectedStudentIds] = useState>(new Set()); const [studentTypeFilter, setStudentTypeFilter] = useState<'INTERNAL' | 'EXTERNAL'>('INTERNAL'); const [externalUserIds, setExternalUserIds] = useState>(new Set()); // Fetch registrations directly from Supabase for reliability useEffect(() => { const fetchRegistrations = async () => { setIsLoading(true); let { data, error } = await supabase .from('participants') .select('*') .order('created_at', { ascending: false }); if (error) { // Fallback to registrations if participants table doesn't exist yet const fallback = await supabase .from('registrations') .select('*') .order('registered_at', { ascending: false }); data = fallback.data; error = fallback.error; } if (data && !error) { setRegistrations(data); } else if (localRegistrations.length > 0) { setRegistrations(localRegistrations); } const { data: extUsers } = await supabase.from('externalusers').select('id'); if (extUsers) { setExternalUserIds(new Set(extUsers.map(u => u.id))); } setIsLoading(false); }; fetchRegistrations(); }, []); const departments = ['CSBS', 'AIDS', 'AIML', 'ECE', 'VLSI', 'H&S', 'CCE', 'CSE', 'MECH', 'BIO-TECH', 'Information Technology (IT)', 'Electrical & Electronics Engineering (EEE)', 'Civil Engineering', 'Biomedical Engineering', 'Chemical Engineering', 'Aeronautical / Aerospace Engineering', 'Mechatronics Engineering', 'Others']; const years = ['1st Year', '2nd Year', '3rd Year', '4th Year', '5th Year']; const handleCategorySelect = (id: string) => { setSelectedCategory(id); setCurrentView('DOMAINS'); }; const handleDomainSelect = (id: string) => { setSelectedDomain(id); setCurrentView('EVENTS'); }; const handleEventSelect = (id: string) => { setSelectedEventId(id); setCurrentView('STUDENTS'); }; const handleBack = () => { if (currentView === 'STUDENTS') { setSelectedEventId(null); setCurrentView('EVENTS'); } else if (currentView === 'EVENTS') { setSelectedDomain(null); setCurrentView('DOMAINS'); } else if (currentView === 'DOMAINS') { setSelectedCategory(null); setCurrentView('CATEGORIES'); } }; const filteredParticipants = useMemo(() => { return registrations.filter(r => { const userName = r.user_name || ''; const regNo = r.reg_no || ''; const searchLower = searchTerm.toLowerCase(); const matchesSearch = !searchTerm || userName.toLowerCase().includes(searchLower) || regNo.toLowerCase().includes(searchLower); const matchesEvent = !selectedEventId || String(r.event_id) === String(selectedEventId); const matchesDept = selectedDepts.length === 0 || (r.dept && selectedDepts.includes(r.dept)); const matchesYear = selectedYears.length === 0 || (r.year && selectedYears.includes(r.year)); const isExternal = r.college && r.college !== 'RAJALAKSHMI INSTITUTE OF TECHNOLOGY' && r.college !== 'Rajalakshmi Institute of Technology'; const matchesType = studentTypeFilter === 'EXTERNAL' ? isExternal : !isExternal; return matchesSearch && matchesEvent && matchesDept && matchesYear && matchesType; }); }, [registrations, selectedEventId, searchTerm, selectedDepts, selectedYears, studentTypeFilter, externalUserIds]); const getEventTitle = (eventId: string) => { return events.find(e => e.id === eventId)?.title || 'Unknown Event'; }; const handleExportSelected = () => { if (selectedStudentIds.size === 0) return; const selectedData = filteredParticipants.filter(p => selectedStudentIds.has(p.id)); // Formatting data for Excel const formattedData = selectedData.map(p => ({ 'Student Name': p.user_name || 'N/A', 'Reg No': String(p.reg_no || 'N/A'), 'Gender': p.gender || 'N/A', 'College': p.college || 'RIT', 'Department': p.dept || 'N/A', 'Section': p.section || 'N/A', 'Year': p.year || 'N/A', 'Email': p.user_id?.includes('@') ? p.user_id : (p.user_email || 'N/A'), 'Phone': String(p.phone || 'N/A'), 'Event': p.event_name || getEventTitle(String(p.event_id)), 'Team': p.team_name || 'N/A', 'Payment Status': p.payment_status || 'PENDING', 'Cert Status': p.certification_status === 'APPROVED' ? 'VERIFIED' : (p.certification_url ? 'PENDING' : 'NO CERT'), 'OD Status': p.od_url ? 'OD READY' : 'NO OD' })); // Create worksheet const worksheet = XLSX.utils.json_to_sheet(formattedData); // Auto-fit columns if (formattedData.length > 0) { const keys = Object.keys(formattedData[0]); const wscols = keys.map(key => ({ wch: Math.max( key.length, ...formattedData.map(row => String(row[key as keyof typeof row] || '').length) ) + 2 })); worksheet['!cols'] = wscols; } // Create workbook and export const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, worksheet, 'Participants'); XLSX.writeFile(workbook, `Participants_Export_${new Date().getTime()}.xlsx`); }; return (

SYSTEM REGISTRY

Live Database Dossier Sync

{currentView !== 'CATEGORIES' && ( )}
setSearchTerm(e.target.value)} />
{showEventFilter && (
{events.map(event => ( ))}
)}
{currentView === 'CATEGORIES' && !searchTerm && (
{CATEGORIES.map((cat) => (
handleCategorySelect(cat.id)} className="group relative h-[400px] rounded-[3rem] overflow-hidden cursor-pointer bg-slate-100 border border-slate-200 hover:border-blue-300 hover:shadow-xl transition-all shadow-sm"> {cat.name}

{cat.name}

))}
)} {currentView === 'DOMAINS' && (
{(DOMAIN_MAP[selectedCategory!] || []).map((domain) => (
handleDomainSelect(domain.id)} className="group relative h-[350px] rounded-[2.5rem] overflow-hidden cursor-pointer bg-slate-100 border border-slate-200 hover:border-blue-300 hover:shadow-xl transition-all shadow-sm"> {domain.name}

{domain.name}

))}
)} {currentView === 'EVENTS' && (
{events.filter(e => (!selectedCategory || selectedCategory === 'ALL' || e.category === selectedCategory) && (!selectedDomain || selectedDomain === 'ALL' || e.domain === selectedDomain)).map((event) => (
handleEventSelect(event.id)} className="bg-white border border-slate-200 rounded-[2.5rem] p-8 cursor-pointer hover:border-blue-300 hover:shadow-md transition-all flex flex-col h-full shadow-sm">

{event.title}

{registrations.filter(r => String(r.event_id) === String(event.id)).length} Enrolled

))}
)} setShowSideFilter(false)} activeTab={activeFilterTab} setActiveTab={setActiveFilterTab} departments={departments} years={years} selectedDepts={selectedDepts} setSelectedDepts={setSelectedDepts} selectedYears={selectedYears} setSelectedYears={setSelectedYears} /> {(currentView === 'STUDENTS' || searchTerm) && (
{isLoading ? (

Loading Registrations...

) : (
{filteredParticipants.length > 0 ? filteredParticipants.map((p) => ( )) : ( )}
0 && filteredParticipants.every(p => selectedStudentIds.has(p.id))} onChange={(e) => { if (e.target.checked) { setSelectedStudentIds(new Set(filteredParticipants.map(p => p.id))); } else { setSelectedStudentIds(new Set()); } }} /> Student Event Info Academic Contact Status
{ const newSet = new Set(selectedStudentIds); if (e.target.checked) newSet.add(p.id); else newSet.delete(p.id); setSelectedStudentIds(newSet); }} />
{(p.user_name || 'N').charAt(0).toUpperCase()}

{p.user_name || 'N/A'}

{(externalUserIds.has(p.user_id) || !!p.college) && ( External )}

{p.reg_no || 'N/A'}

{p.college && (

{p.college}

)}

{p.event_name || getEventTitle(String(p.event_id))}

{p.dept || 'N/A'} {p.section ? `• SEC ${p.section}` : ''}

{p.year || 'N/A'}

{p.user_id?.includes('@') ? p.user_id : (p.user_email || 'N/A')}

{p.payment_status || 'PENDING'} {p.certification_status === 'APPROVED' ? 'VERIFIED' : (p.certification_url ? 'PENDING' : 'NO CERT')} {p.od_url ? 'OD READY' : 'NO OD'}

No active registrations for this scope

Try adjusting your search or filters

)} {selectedStudentIds.size > 0 && (
{selectedStudentIds.size} Selected
)}
)}
); }; const FilterDrawer: React.FC<{ isOpen: boolean; onClose: () => void; activeTab: 'DEPT' | 'YEAR'; setActiveTab: (tab: 'DEPT' | 'YEAR') => void; departments: string[]; years: string[]; selectedDepts: string[]; setSelectedDepts: (depts: string[]) => void; selectedYears: string[]; setSelectedYears: (years: string[]) => void; }> = ({ isOpen, onClose, activeTab, setActiveTab, departments, years, selectedDepts, setSelectedDepts, selectedYears, setSelectedYears }) => { if (!isOpen) return null; const toggleDept = (dept: string) => { if (selectedDepts.includes(dept)) { setSelectedDepts(selectedDepts.filter(d => d !== dept)); } else { setSelectedDepts([...selectedDepts, dept]); } }; const toggleYear = (year: string) => { if (selectedYears.includes(year)) { setSelectedYears(selectedYears.filter(y => y !== year)); } else { setSelectedYears([...selectedYears, year]); } }; const clearAll = () => { setSelectedDepts([]); setSelectedYears([]); }; return createPortal(

Refine Results

Select multiple filters

{/* Sidebar Tabs */}
{/* Options Content */}
{activeTab === 'DEPT' ? (
{departments.map(dept => ( ))}
) : (
{years.map(year => ( ))}
)}
, document.body ); }; export default FacultyParticipantsView;