import { API_BASE_URL } from '../../lib/config'; import React, { useEffect, useState, useMemo } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { CheckCircle, XCircle, Clock, User, Building2, ChevronRight, AlertCircle, ShieldCheck, MapPin, Wallet, Users, Layers, Ticket, AlertTriangle, FileText, Heart, Calendar } from 'lucide-react'; import { useAuth } from '../../context/AuthContext'; import { cn } from '../../lib/utils'; import { Pagination } from './Pagination'; interface Event { id: number; title: string; startDate: string; endDate: string; type: string; institution: string; department: string; academicYears: string[]; status: string; location: string; proposer?: { fullName: string; department: string; }; budget: number; hasRegistrationFee: boolean; registrationFee: number; category: string; targetedSections: string[]; conflictMessage?: string; description?: string; sponsors?: string[]; rejectionReason?: string; } export const ApprovalsView: React.FC = () => { const { user } = useAuth(); const [events, setEvents] = useState([]); const [isLoading, setIsLoading] = useState(true); const [processingId, setProcessingId] = useState(null); const [selectedEvent, setSelectedEvent] = useState(null); const [currentPage, setCurrentPage] = useState(1); const [itemsPerPage, setItemsPerPage] = useState(5); useEffect(() => { fetchEvents(); }, []); const fetchEvents = async () => { try { const response = await fetch(API_BASE_URL + '/api/events'); if (response.ok) { const data = await response.json(); // Filter based on role if (user?.role === 'HOD') { const userDepts = user.department ? user.department.split(',').map(d => d.trim().toLowerCase()) : []; setEvents(data.filter((e: Event) => e.status === 'REQUESTED' && userDepts.includes(e.department?.trim().toLowerCase()))); } else if (user?.role === 'PRINCIPAL') { setEvents(data.filter((e: Event) => e.status === 'PENDING_PR')); } } } catch (error) { console.error('Failed to fetch events:', error); } finally { setIsLoading(false); } }; const handleAction = async (id: number, action: 'approve' | 'reject') => { let reason = ''; if (action === 'reject') { reason = window.prompt('Please enter a rejection reason:') || ''; if (!reason) return; } setProcessingId(id); try { const response = await fetch(`${API_BASE_URL}/api/events/${id}/${action}?userId=${user?.id}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: action === 'reject' ? JSON.stringify({ reason }) : undefined }); if (response.ok) { setEvents(events.filter(e => e.id !== id)); setSelectedEvent(null); } else { const err = await response.json(); alert(err.message || 'Operation failed'); } } catch (error) { console.error(`Failed to ${action} event:`, error); } finally { setProcessingId(null); } }; const sortedEvents = useMemo(() => { return [...events].sort((a: any, b: any) => { const dateA = new Date(a.updatedAt || a.createdAt || 0).getTime(); const dateB = new Date(b.updatedAt || b.createdAt || 0).getTime(); return dateB - dateA; }); }, [events]); const currentEvents = sortedEvents.slice( (currentPage - 1) * itemsPerPage, currentPage * itemsPerPage ); return (

Pending Approvals

Review and take action on event proposals from your {user?.role === 'HOD' ? 'department' : 'institution'}.

{isLoading ? (
) : events.length === 0 ? (

Queue is Empty

All proposals have been processed. Great work!

) : ( {currentEvents.map((event) => ( setSelectedEvent(event)} className={cn( "bg-white rounded-[2rem] p-6 border transition-all flex flex-col md:flex-row items-center justify-between gap-6 cursor-pointer group", event.conflictMessage ? "border-red-200 bg-red-50/30" : "border-slate-100 hover:premium-shadow" )} >
{event.title[0]}
{event.category === 'CLUB' && ( Institutional Club )} {event.type}

{event.title}

{event.conflictMessage ? (
{event.conflictMessage}
) : (
{event.proposer?.fullName || 'Faculty Member'}
{new Date(event.startDate).toLocaleDateString()}
)}
e.stopPropagation()}>
))}
)}
{events.length > 0 && ( { setItemsPerPage(val); setCurrentPage(1); }} itemsPerPageOptions={[5, 10, 15, 20]} /> )} {/* Detail Modal */} {selectedEvent && (
setSelectedEvent(null)} className="absolute inset-0 bg-slate-900/40 backdrop-blur-sm" />
Proposal Details {selectedEvent.institution} {selectedEvent.category === 'CLUB' && ( <> Institutional Club Event )}

{selectedEvent.title}

{/* Description Section */} {selectedEvent.description && (
Event Description

{selectedEvent.description}

)}
Schedule

{new Date(selectedEvent.startDate).toLocaleString()}

Venue

{selectedEvent.location}

Proposed By

{selectedEvent.proposer?.fullName || 'Faculty'}

{selectedEvent.department}

Target Audience

{selectedEvent.academicYears.join(', ')} Batches

{/* Sponsors Section */} {selectedEvent.sponsors && selectedEvent.sponsors.length > 0 && (
Event Sponsors
{selectedEvent.sponsors.map((sponsor, idx) => ( {sponsor} ))}
)}
Estimated Budget

₹{selectedEvent.budget?.toLocaleString() || '0'}

Registration

{selectedEvent.hasRegistrationFee ? `₹${selectedEvent.registrationFee}` : 'FREE'}

{selectedEvent.conflictMessage && (

Critical Conflict Detected

{selectedEvent.conflictMessage}

)}
)}
); };