344 lines
12 KiB
TypeScript
344 lines
12 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
|
import { useNavigate, useLocation } from 'react-router-dom';
|
|
import { useAuth } from '../contexts/AuthContext';
|
|
import {
|
|
AppBar,
|
|
Toolbar,
|
|
Typography,
|
|
IconButton,
|
|
Box,
|
|
Chip,
|
|
useTheme,
|
|
Menu,
|
|
MenuItem,
|
|
ListItemIcon,
|
|
ListItemText,
|
|
Divider
|
|
} from '@mui/material';
|
|
import MenuIcon from '@mui/icons-material/Menu';
|
|
import Login from '@mui/icons-material/Login';
|
|
import Logout from '@mui/icons-material/Logout';
|
|
import Teacher from '@mui/icons-material/School';
|
|
import Student from '@mui/icons-material/Person';
|
|
import Calendar from '@mui/icons-material/CalendarToday';
|
|
import TeacherPlanner from '@mui/icons-material/Assignment';
|
|
import ExamMarker from '@mui/icons-material/AssignmentTurnedIn';
|
|
import Settings from '@mui/icons-material/Settings';
|
|
import Search from '@mui/icons-material/Search';
|
|
import Admin from '@mui/icons-material/AdminPanelSettings';
|
|
import Home from '@mui/icons-material/Home';
|
|
import Schedule from '@mui/icons-material/Schedule';
|
|
import Class from '@mui/icons-material/Class';
|
|
import Book from '@mui/icons-material/Book';
|
|
import Enrollment from '@mui/icons-material/HowToReg';
|
|
import Lessons from '@mui/icons-material/EventNote';
|
|
import LessonPlans from '@mui/icons-material/LibraryBooks';
|
|
import People from '@mui/icons-material/People';
|
|
import SchoolSettings from '@mui/icons-material/Tune';
|
|
import { HEADER_HEIGHT } from './Layout';
|
|
import { logger } from '../debugConfig';
|
|
import { GraphNavigator } from '../components/navigation/GraphNavigator';
|
|
|
|
|
|
const Header: React.FC = () => {
|
|
const theme = useTheme();
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
const { user, signOut, bootstrapData } = useAuth();
|
|
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
|
const [isAuthenticated, setIsAuthenticated] = useState(!!user);
|
|
const showGraphNavigation = location.pathname === '/single-player';
|
|
const isPlatformAdmin = bootstrapData?.permissions?.platform_admin ?? false;
|
|
const schoolRole = bootstrapData?.active_institute?.membership_role ?? null;
|
|
const isSchoolAdmin = schoolRole === 'school_admin' || schoolRole === 'department_head';
|
|
|
|
useEffect(() => {
|
|
setIsAuthenticated(!!user);
|
|
}, [user]);
|
|
|
|
|
|
|
|
const handleMenuOpen = (event: React.MouseEvent<HTMLElement>) => {
|
|
setAnchorEl(event.currentTarget);
|
|
};
|
|
|
|
const handleMenuClose = () => {
|
|
setAnchorEl(null);
|
|
};
|
|
|
|
const handleNavigation = (path: string) => {
|
|
navigate(path);
|
|
handleMenuClose();
|
|
};
|
|
|
|
const handleSignupNavigation = (role: 'teacher' | 'student') => {
|
|
navigate('/signup', { state: { role } });
|
|
handleMenuClose();
|
|
};
|
|
|
|
const handleSignOut = async () => {
|
|
try {
|
|
logger.debug('auth-service', '🔄 Signing out user', { userId: user?.id });
|
|
await signOut();
|
|
setIsAuthenticated(false);
|
|
setAnchorEl(null);
|
|
logger.debug('auth-service', '✅ User signed out');
|
|
} catch (error) {
|
|
logger.error('auth-service', '❌ Error signing out:', error);
|
|
console.error('Error signing out:', error);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<AppBar
|
|
position="fixed"
|
|
sx={{
|
|
height: `${HEADER_HEIGHT}px`,
|
|
bgcolor: theme.palette.background.paper,
|
|
color: theme.palette.text.primary,
|
|
boxShadow: 1
|
|
}}
|
|
>
|
|
<Toolbar sx={{
|
|
display: 'flex',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
height: '100%'
|
|
}}>
|
|
{showGraphNavigation && (
|
|
<GraphNavigator />
|
|
)}
|
|
|
|
<Typography
|
|
variant="h6"
|
|
component="div"
|
|
sx={{
|
|
flexGrow: showGraphNavigation ? 0 : 1,
|
|
fontWeight: 600,
|
|
cursor: 'pointer',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: 1
|
|
}}
|
|
onClick={() => handleNavigation('/')}
|
|
>
|
|
<Home sx={{ color: theme.palette.primary.main }} />
|
|
Classroom Copilot
|
|
</Typography>
|
|
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
|
{isAuthenticated && bootstrapData?.onboarding?.next_step && bootstrapData.onboarding.next_step !== 'ready' && (
|
|
<Chip
|
|
label={bootstrapData.onboarding.next_step.replace(/_/g, ' ')}
|
|
color="warning"
|
|
size="small"
|
|
onClick={() => navigate('/dashboard')}
|
|
sx={{ cursor: 'pointer', display: { xs: 'none', sm: 'flex' } }}
|
|
/>
|
|
)}
|
|
{isAuthenticated && (
|
|
<Typography
|
|
variant="body2"
|
|
sx={{
|
|
color: theme.palette.text.secondary,
|
|
display: { xs: 'none', sm: 'block' }
|
|
}}
|
|
>
|
|
{user?.email}
|
|
</Typography>
|
|
)}
|
|
|
|
<IconButton
|
|
color="inherit"
|
|
aria-label="menu"
|
|
onClick={handleMenuOpen}
|
|
sx={{
|
|
border: `1px solid ${theme.palette.divider}`,
|
|
borderRadius: 1,
|
|
'&:hover': {
|
|
bgcolor: theme.palette.action.hover
|
|
}
|
|
}}
|
|
>
|
|
<MenuIcon />
|
|
</IconButton>
|
|
|
|
<Menu
|
|
anchorEl={anchorEl}
|
|
open={Boolean(anchorEl)}
|
|
onClose={handleMenuClose}
|
|
PaperProps={{
|
|
sx: {
|
|
width: 280,
|
|
maxHeight: '80vh'
|
|
}
|
|
}}
|
|
>
|
|
<Typography
|
|
variant="subtitle2"
|
|
sx={{
|
|
px: 2,
|
|
py: 1.5,
|
|
color: theme.palette.text.secondary,
|
|
fontWeight: 600,
|
|
letterSpacing: '0.5px',
|
|
textTransform: 'uppercase',
|
|
fontSize: '0.75rem'
|
|
}}
|
|
>
|
|
Navigation
|
|
</Typography>
|
|
|
|
{isAuthenticated ? [
|
|
// Home
|
|
<MenuItem key="home" onClick={() => handleNavigation('/')}>
|
|
<ListItemIcon>
|
|
<Home />
|
|
</ListItemIcon>
|
|
<ListItemText primary="Home" />
|
|
</MenuItem>,
|
|
<Divider key="home-divider" />,
|
|
|
|
// My Work Section
|
|
<Typography
|
|
key="work-header"
|
|
variant="subtitle2"
|
|
sx={{
|
|
px: 2,
|
|
py: 1,
|
|
color: theme.palette.primary.main,
|
|
fontWeight: 600,
|
|
letterSpacing: '0.5px',
|
|
textTransform: 'uppercase',
|
|
fontSize: '0.75rem'
|
|
}}
|
|
>
|
|
My Work
|
|
</Typography>,
|
|
<MenuItem key="my-classes" onClick={() => handleNavigation('/my-classes')}>
|
|
<ListItemIcon>
|
|
<Book />
|
|
</ListItemIcon>
|
|
<ListItemText
|
|
primary="My Classes"
|
|
secondary="Manage your classes"
|
|
/>
|
|
</MenuItem>,
|
|
<MenuItem key="my-lessons" onClick={() => handleNavigation('/my-lessons')}>
|
|
<ListItemIcon>
|
|
<Lessons />
|
|
</ListItemIcon>
|
|
<ListItemText
|
|
primary="My Lessons"
|
|
secondary="Weekly lesson view"
|
|
/>
|
|
</MenuItem>,
|
|
<MenuItem key="lesson-plans" onClick={() => handleNavigation('/lesson-plans')}>
|
|
<ListItemIcon>
|
|
<LessonPlans />
|
|
</ListItemIcon>
|
|
<ListItemText
|
|
primary="Lesson Plans"
|
|
secondary="Plan and manage lessons"
|
|
/>
|
|
</MenuItem>,
|
|
<Divider key="work-divider" />,
|
|
|
|
// School Admin Section
|
|
...(isSchoolAdmin ? [
|
|
<Typography
|
|
key="school-admin-header"
|
|
variant="subtitle2"
|
|
sx={{
|
|
px: 2, py: 1,
|
|
color: theme.palette.primary.main,
|
|
fontWeight: 600,
|
|
letterSpacing: '0.5px',
|
|
textTransform: 'uppercase',
|
|
fontSize: '0.75rem',
|
|
}}
|
|
>
|
|
School Admin
|
|
</Typography>,
|
|
<MenuItem key="school-settings" onClick={() => handleNavigation('/school-settings')}>
|
|
<ListItemIcon><SchoolSettings /></ListItemIcon>
|
|
<ListItemText primary="School Settings" secondary="Calendar, overview" />
|
|
</MenuItem>,
|
|
<MenuItem key="staff-manager" onClick={() => handleNavigation('/staff-manager')}>
|
|
<ListItemIcon><People /></ListItemIcon>
|
|
<ListItemText primary="Staff Manager" secondary="Invite & manage teachers" />
|
|
</MenuItem>,
|
|
<MenuItem key="student-manager" onClick={() => handleNavigation('/student-manager')}>
|
|
<ListItemIcon><Teacher /></ListItemIcon>
|
|
<ListItemText primary="Student Manager" secondary="Invite & manage students" />
|
|
</MenuItem>,
|
|
<Divider key="school-admin-divider" />,
|
|
] : []),
|
|
|
|
// Platform Admin Section
|
|
...(isPlatformAdmin ? [
|
|
<Divider key="admin-divider" />,
|
|
<Typography
|
|
key="admin-header"
|
|
variant="subtitle2"
|
|
sx={{
|
|
px: 2,
|
|
py: 1,
|
|
color: theme.palette.error.main,
|
|
fontWeight: 600,
|
|
letterSpacing: '0.5px',
|
|
textTransform: 'uppercase',
|
|
fontSize: '0.75rem'
|
|
}}
|
|
>
|
|
Administration
|
|
</Typography>,
|
|
<MenuItem key="admin" onClick={() => handleNavigation('/admin')}>
|
|
<ListItemIcon><Admin /></ListItemIcon>
|
|
<ListItemText primary="Platform Admin" secondary="Schools & system stats" />
|
|
</MenuItem>
|
|
] : []),
|
|
|
|
<MenuItem key="signout" onClick={handleSignOut}>
|
|
<ListItemIcon>
|
|
<Logout />
|
|
</ListItemIcon>
|
|
<ListItemText primary="Sign Out" />
|
|
</MenuItem>
|
|
] : [
|
|
// Authentication Section for Non-authenticated Users
|
|
<MenuItem key="signin" onClick={() => handleNavigation('/login')}>
|
|
<ListItemIcon>
|
|
<Login />
|
|
</ListItemIcon>
|
|
<ListItemText primary="Sign In" />
|
|
</MenuItem>,
|
|
<Divider key="signup-divider" />,
|
|
<MenuItem key="teacher-signup" onClick={() => handleSignupNavigation('teacher')}>
|
|
<ListItemIcon>
|
|
<Teacher />
|
|
</ListItemIcon>
|
|
<ListItemText
|
|
primary="Sign up as Teacher"
|
|
secondary="Create a teacher account"
|
|
/>
|
|
</MenuItem>,
|
|
<MenuItem key="student-signup" onClick={() => handleSignupNavigation('student')}>
|
|
<ListItemIcon>
|
|
<Student />
|
|
</ListItemIcon>
|
|
<ListItemText
|
|
primary="Sign up as Student"
|
|
secondary="Create a student account"
|
|
/>
|
|
</MenuItem>
|
|
]}
|
|
</Menu>
|
|
</Box>
|
|
</Toolbar>
|
|
</AppBar>
|
|
);
|
|
};
|
|
|
|
export default Header;
|