215 lines
7.6 KiB
TypeScript
215 lines
7.6 KiB
TypeScript
import { API_BASE_URL } from './lib/config';
|
|
import React, { useState } from 'react';
|
|
import { DashboardLayout } from './components/DashboardLayout';
|
|
import { InstitutionalChecklist } from './components/dashboard/InstitutionalChecklist';
|
|
import { EventProposalForm } from './components/dashboard/EventProposalForm';
|
|
import { AllEvents } from './components/dashboard/AllEvents';
|
|
import { ApprovalsView } from './components/dashboard/ApprovalsView';
|
|
import { UserManagement } from './components/dashboard/UserManagement';
|
|
import { ClassManagement } from './components/dashboard/ClassManagement';
|
|
import { LoginPage } from './pages/LoginPage';
|
|
import { AuthProvider, useAuth } from './context/AuthContext';
|
|
import { DialogProvider } from './context/DialogContext';
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
import { StatusTimeline, type Event } from './components/dashboard/EventStatusTimeline';
|
|
import { useEffect } from 'react';
|
|
|
|
import { InstitutionalCalendar } from './components/dashboard/InstitutionalCalendar';
|
|
import { VenueTimeline } from './components/dashboard/VenueTimeline';
|
|
import { EventHistory } from './components/dashboard/EventHistory';
|
|
import { ClubInstitutionalChecklist } from './components/dashboard/ClubInstitutionalChecklist';
|
|
import { AutomationView } from './components/dashboard/AutomationView';
|
|
import { Overview } from './components/dashboard/Overview';
|
|
import { ExcelImport } from './components/dashboard/ExcelImport';
|
|
import { StudentDashboard } from './components/dashboard/StudentDashboard';
|
|
import { StudentRegistrationsView } from './components/dashboard/StudentRegistrationsView';
|
|
import { ManageNoticesView } from './components/dashboard/ManageNoticesView';
|
|
import { ManageStudentsView } from './components/dashboard/ManageStudentsView';
|
|
import { VenueManagement } from './components/dashboard/VenueManagement';
|
|
|
|
|
|
const AppContent: React.FC = () => {
|
|
const { isAuthenticated, user } = useAuth();
|
|
const isClubAuthorized = user?.isClubCoordinator || user?.role === 'ADMIN';
|
|
const [activeItem, setActiveItem] = useState('dashboard');
|
|
const [userEvents, setUserEvents] = useState<Event[]>([]);
|
|
const [preFillData, setPreFillData] = useState<any>(null);
|
|
|
|
const handleIncompleteClick = (data: any) => {
|
|
setPreFillData(data);
|
|
setActiveItem('propose');
|
|
};
|
|
|
|
const handleCalendarPropose = (date: string) => {
|
|
setPreFillData({ startDate: `${date}T09:00` });
|
|
setActiveItem('propose');
|
|
};
|
|
|
|
const handleClubEventClick = (data: any) => {
|
|
setPreFillData(data);
|
|
setActiveItem('propose');
|
|
};
|
|
|
|
const handleEditEvent = (event: any) => {
|
|
setPreFillData({
|
|
...event,
|
|
eventName: event.title,
|
|
venue: event.location,
|
|
category: event.category,
|
|
eventType: event.type,
|
|
socialProfile: event.guestSocialProfile,
|
|
maxParticipants: event["total capacity"] || (event.maxParticipants ?? ''),
|
|
sponsors: event.sponsors ?? [],
|
|
isEditMode: true,
|
|
openToAll: !!event.openToAll
|
|
});
|
|
setActiveItem('propose');
|
|
};
|
|
|
|
const handleSidebarClick = (item: string) => {
|
|
if (item === 'propose') setPreFillData(null);
|
|
setActiveItem(item);
|
|
};
|
|
|
|
useEffect(() => {
|
|
const handleNav = (e: any) => setActiveItem(e.detail);
|
|
window.addEventListener('navigate', handleNav);
|
|
return () => window.removeEventListener('navigate', handleNav);
|
|
}, []);
|
|
|
|
|
|
useEffect(() => {
|
|
if (isAuthenticated && activeItem === 'dashboard') {
|
|
fetch(API_BASE_URL + '/api/events')
|
|
.then(res => {
|
|
if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
|
|
return res.json();
|
|
})
|
|
.then(data => {
|
|
if (Array.isArray(data)) {
|
|
let filtered = data;
|
|
if (user?.role === 'HOD') {
|
|
const userDepts = user?.department ? user.department.split(',').map(d => d.trim().toLowerCase()) : [];
|
|
filtered = data.filter((e: Event) => userDepts.includes(e.department?.trim().toLowerCase()));
|
|
} else if (user?.role === 'FACULTY') {
|
|
filtered = data.filter((e: Event) => e.proposer?.email === user?.email);
|
|
}
|
|
setUserEvents(filtered);
|
|
}
|
|
})
|
|
.catch(err => console.error("Failed to fetch dashboard events:", err));
|
|
}
|
|
}, [isAuthenticated, activeItem, user?.email, user?.role, user?.department]);
|
|
|
|
if (!isAuthenticated) {
|
|
return (
|
|
<AnimatePresence mode="wait">
|
|
<motion.div
|
|
key="login"
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
transition={{ duration: 0.5 }}
|
|
>
|
|
<LoginPage />
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
);
|
|
}
|
|
|
|
if (user?.role === 'STUDENT') {
|
|
return (
|
|
<AnimatePresence mode="wait">
|
|
<motion.div
|
|
key="student-dashboard"
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
transition={{ duration: 0.5 }}
|
|
>
|
|
<StudentDashboard />
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
);
|
|
}
|
|
|
|
const renderContent = () => {
|
|
const isDashboard = (
|
|
<Overview
|
|
userEvents={userEvents}
|
|
onNavigate={handleSidebarClick}
|
|
onIncompleteClick={handleIncompleteClick}
|
|
onCalendarPropose={handleCalendarPropose}
|
|
onClubEventClick={handleClubEventClick}
|
|
onEditEvent={handleEditEvent}
|
|
/>
|
|
);
|
|
|
|
switch (activeItem) {
|
|
case 'user-management':
|
|
return user?.role === 'ADMIN' ? <UserManagement /> : isDashboard;
|
|
case 'approvals':
|
|
return (user?.role === 'HOD' || user?.role === 'PRINCIPAL') ? <ApprovalsView /> : isDashboard;
|
|
case 'clubs':
|
|
return isClubAuthorized ? <ClubInstitutionalChecklist onEventClick={handleClubEventClick} /> : isDashboard;
|
|
case 'events':
|
|
return <AllEvents onEditEvent={handleEditEvent} />;
|
|
case 'propose':
|
|
return <EventProposalForm initialData={preFillData} />;
|
|
case 'checklist':
|
|
return <InstitutionalChecklist isGlobalView={true} onIncompleteClick={handleIncompleteClick} />;
|
|
case 'history':
|
|
return <EventHistory />;
|
|
case 'classes':
|
|
return user?.role === 'ADMIN' ? <ClassManagement /> : isDashboard;
|
|
case 'manage-venues':
|
|
return user?.role === 'ADMIN' ? <VenueManagement /> : isDashboard;
|
|
case 'automation':
|
|
return (user?.role === 'ADMIN' || user?.role === 'PRINCIPAL' || user?.role === 'HOD') ? <AutomationView /> : isDashboard;
|
|
case 'import-excel':
|
|
return <ExcelImport />;
|
|
case 'student-registrations':
|
|
return (user?.role === 'FACULTY' || user?.role === 'HOD' || user?.role === 'ADMIN') ? <StudentRegistrationsView /> : isDashboard;
|
|
case 'manage-notices':
|
|
return user?.role === 'ADMIN' ? <ManageNoticesView /> : isDashboard;
|
|
case 'manage-students':
|
|
return user?.isClassIncharge ? <ManageStudentsView /> : isDashboard;
|
|
case 'dashboard':
|
|
return isDashboard;
|
|
default:
|
|
return isDashboard;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<DashboardLayout
|
|
activeItem={activeItem}
|
|
onItemClick={handleSidebarClick}
|
|
>
|
|
<AnimatePresence mode="wait">
|
|
<motion.div
|
|
key={activeItem}
|
|
initial={{ opacity: 0, x: 20 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
exit={{ opacity: 0, x: -20 }}
|
|
transition={{ duration: 0.3 }}
|
|
>
|
|
{renderContent()}
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
</DashboardLayout>
|
|
);
|
|
};
|
|
|
|
function App() {
|
|
return (
|
|
<DialogProvider>
|
|
<AuthProvider>
|
|
<AppContent />
|
|
</AuthProvider>
|
|
</DialogProvider>
|
|
);
|
|
}
|
|
|
|
export default App;
|