import React, { useState } from 'react'; import { createPortal } from 'react-dom'; import { Event, Announcement } from '../types'; interface AdminEventStatusViewProps { events: Event[]; announcements: Announcement[]; onAddAnnouncement: (ann: Announcement) => Promise; onUpdateAnnouncement?: (ann: Announcement) => Promise; onDeleteAnnouncement: (id: string) => Promise; onUpdateEvent: (event: Event) => void; onBack: () => void; currentUserId?: string; localRegistrations?: any[]; } type ExpiryOption = '1H' | '6H' | '24H' | 'NEVER' | 'CUSTOM'; const AdminEventStatusView: React.FC = ({ events, announcements, onAddAnnouncement, onUpdateAnnouncement, onDeleteAnnouncement, onUpdateEvent, onBack, currentUserId, localRegistrations = [] }) => { const [selectedEventId, setSelectedEventId] = useState(''); const [message, setMessage] = useState(''); const [type, setType] = useState('INFO'); const [expiryOption, setExpiryOption] = useState('NEVER'); const [customExpiry, setCustomExpiry] = useState(''); const [isSubmitting, setIsSubmitting] = useState(false); const [deletingId, setDeletingId] = useState(null); const [editingId, setEditingId] = useState(null); const [showOverwriteConfirm, setShowOverwriteConfirm] = useState(null); const [confirmDeleteId, setConfirmDeleteId] = useState(null); const calculateExpiry = (): string | null => { const now = new Date(); switch (expiryOption) { case '1H': return new Date(now.getTime() + 60 * 60 * 1000).toISOString(); case '6H': return new Date(now.getTime() + 6 * 60 * 60 * 1000).toISOString(); case '24H': return new Date(now.getTime() + 24 * 60 * 60 * 1000).toISOString(); case 'CUSTOM': return customExpiry ? new Date(customExpiry).toISOString() : null; default: return null; } }; const handleEdit = (ann: Announcement) => { setEditingId(ann.id); setSelectedEventId(ann.eventId || ''); const cleanMessage = ann.message.includes(']') ? ann.message.split(']').slice(1).join(']').trim() : ann.message; setMessage(cleanMessage); setType(ann.type); setExpiryOption(ann.expiresAt ? 'CUSTOM' : 'NEVER'); if (ann.expiresAt) setCustomExpiry(new Date(ann.expiresAt).toISOString().slice(0, 16)); window.scrollTo({ top: 0, behavior: 'smooth' }); }; const cancelEdit = () => { setEditingId(null); setMessage(''); setSelectedEventId(''); setExpiryOption('NEVER'); setCustomExpiry(''); }; const processDelete = async () => { if (!confirmDeleteId) return; const id = confirmDeleteId; setConfirmDeleteId(null); setDeletingId(id); try { await onDeleteAnnouncement(id); } catch (err: any) { console.error("UI Delete Trigger Error:", err); alert("Database failed to delete. Check console for error."); } finally { setDeletingId(null); } }; const executeSubmit = async (overrideId?: string) => { setIsSubmitting(true); try { const selectedEvent = events.find(ev => ev.id === selectedEventId); const expiresAt = calculateExpiry(); const targetId = overrideId || editingId; const announcementPayload: Announcement = { id: targetId || '', title: type === 'DELAY' ? 'DELAY ALERT' : type === 'URGENT' ? 'URGENT' : type === 'ENDED' ? 'CONCLUDED' : type === 'ONGOING' ? 'LIVE NOW' : 'NOTICE', message: selectedEvent ? `[${selectedEvent.title}] ${message}` : message, type, timestamp: new Date().toISOString(), expiresAt: expiresAt, eventId: selectedEventId || undefined }; if (targetId && onUpdateAnnouncement) { await onUpdateAnnouncement(announcementPayload); } else { await onAddAnnouncement(announcementPayload); } if (type === 'ENDED' && selectedEvent) { onUpdateEvent({ ...selectedEvent, status: 'Completed' }); } else if (type === 'ONGOING' && selectedEvent) { onUpdateEvent({ ...selectedEvent, status: 'Event Ongoing' }); } cancelEdit(); setShowOverwriteConfirm(null); } catch (err) { console.error("Broadcast operation failed:", err); } finally { setIsSubmitting(false); } }; const handleDownloadExcel = () => { if (!selectedEventId || selectedEventId === 'GENERAL') return; const event = events.find(e => e.id === selectedEventId); if (!event) return; const filteredRegs = localRegistrations.filter(reg => String(reg.event_id) === String(selectedEventId)); if (filteredRegs.length === 0) { alert("No participants found for this event."); return; } const headers = ['Name', 'Registration No', 'Department', 'Year', 'Email', 'Phone', 'College']; const rows = filteredRegs.map(r => [ r.user_name || 'N/A', `\t${r.reg_no || 'N/A'}`, r.dept || 'N/A', r.year || 'N/A', r.email || 'N/A', r.phone || 'N/A', r.college || 'RAJALAKSHMI INSTITUTE OF TECHNOLOGY' ]); const csvContent = [ [`EVENT: ${event.title}`].join(','), [`EXPORTED AT: ${new Date().toLocaleString()}`].join(','), [''], headers.join(','), ...rows.map(row => row.map(cell => `"${cell}"`).join(',')) ].join('\n'); const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `${event.title.replace(/[^a-z0-9]/gi, '_').toLowerCase()}_participants.csv`); document.body.appendChild(link); link.click(); document.body.removeChild(link); }; const handlePublish = async () => { if (!message.trim() || !selectedEventId) return; if (selectedEventId !== 'GENERAL') { const event = events.find(e => e.id === selectedEventId); if (!event || event.created_by !== currentUserId) { alert("Unauthorized: Only the creator can broadcast for this event."); return; } } executeSubmit(); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!message) return; if ((type === 'ENDED' || type === 'ONGOING') && selectedEventId && !editingId) { const existingStatusNotice = announcements.find(a => a.eventId === selectedEventId && a.type === type); if (existingStatusNotice) { setShowOverwriteConfirm(existingStatusNotice); return; } } handlePublish(); }; const getStatusColor = (t: Announcement['type']) => { switch (t) { case 'URGENT': return 'border-rose-500/30 text-rose-500 bg-rose-500/5'; case 'DELAY': return 'border-amber-500/30 text-amber-500 bg-amber-500/5'; case 'ENDED': return 'border-emerald-500/30 text-emerald-500 bg-emerald-500/5'; case 'ONGOING': return 'border-purple-500/30 text-purple-500 bg-purple-500/5'; default: return 'border-blue-500/30 text-blue-500 bg-blue-500/5'; } }; return (
{/* Overwrite Confirmation Modal */} {showOverwriteConfirm && createPortal(

Replace Previous Log?

A conclusion log already exists for this scope.
Replacing it will overwrite the history entry.

, document.body )} {/* Delete Confirmation Modal */} {confirmDeleteId && createPortal(

Remove Broadcast?

This action is permanent and cannot be reversed.

, document.body )}

ADMIN PULSE

Live Management of System Notifications

{/* Left Side: Creation Form */}

{editingId ? 'Refining Broadcast' : 'New Broadcast'}

{editingId && ( )}
{selectedEventId && selectedEventId !== 'GENERAL' && ( )}
{(['DELAY', 'INFO', 'URGENT', 'ENDED', 'ONGOING'] as Announcement['type'][]).map(t => ( ))}
{(['1H', 'NEVER', 'CUSTOM'] as ExpiryOption[]).map(opt => ( ))}
{expiryOption === 'CUSTOM' && ( setCustomExpiry(e.target.value)} required /> )}