feat(timetable): add navigation links to Header component
This commit is contained in:
parent
11c139b410
commit
a64836c94a
@ -1,7 +1,7 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useNavigate, useLocation } from 'react-router-dom';
|
import { useNavigate, useLocation } from 'react-router-dom';
|
||||||
import { useAuth } from '../contexts/AuthContext';
|
import { useAuth } from '../contexts/AuthContext';
|
||||||
import {
|
import {
|
||||||
AppBar,
|
AppBar,
|
||||||
Toolbar,
|
Toolbar,
|
||||||
Typography,
|
Typography,
|
||||||
@ -15,7 +15,7 @@ import {
|
|||||||
Divider
|
Divider
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import MenuIcon from '@mui/icons-material/Menu';
|
import MenuIcon from '@mui/icons-material/Menu';
|
||||||
import {
|
import {
|
||||||
Login as LoginIcon,
|
Login as LoginIcon,
|
||||||
Logout as LogoutIcon,
|
Logout as LogoutIcon,
|
||||||
School as TeacherIcon,
|
School as TeacherIcon,
|
||||||
@ -29,7 +29,12 @@ import {
|
|||||||
Settings as SettingsIcon,
|
Settings as SettingsIcon,
|
||||||
Search as SearchIcon,
|
Search as SearchIcon,
|
||||||
AdminPanelSettings as AdminIcon,
|
AdminPanelSettings as AdminIcon,
|
||||||
Home as HomeIcon
|
Home as HomeIcon,
|
||||||
|
// Timetable icons
|
||||||
|
Schedule as ScheduleIcon,
|
||||||
|
Class as ClassIcon,
|
||||||
|
Book as BookIcon,
|
||||||
|
HowToReg as EnrollmentIcon
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { HEADER_HEIGHT } from './Layout';
|
import { HEADER_HEIGHT } from './Layout';
|
||||||
import { logger } from '../debugConfig';
|
import { logger } from '../debugConfig';
|
||||||
@ -49,7 +54,7 @@ const Header: React.FC = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const newAuthState = !!user;
|
const newAuthState = !!user;
|
||||||
setIsAuthenticated(newAuthState);
|
setIsAuthenticated(newAuthState);
|
||||||
logger.debug('user-context', '🔄 User state changed in header', {
|
logger.debug('user-context', '🔄 User state changed in header', {
|
||||||
hasUser: newAuthState,
|
hasUser: newAuthState,
|
||||||
userId: user?.id,
|
userId: user?.id,
|
||||||
userEmail: user?.email,
|
userEmail: user?.email,
|
||||||
@ -80,7 +85,6 @@ const Header: React.FC = () => {
|
|||||||
try {
|
try {
|
||||||
logger.debug('auth-service', '🔄 Signing out user', { userId: user?.id });
|
logger.debug('auth-service', '🔄 Signing out user', { userId: user?.id });
|
||||||
await signOut();
|
await signOut();
|
||||||
// Clear local state immediately
|
|
||||||
setIsAuthenticated(false);
|
setIsAuthenticated(false);
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
logger.debug('auth-service', '✅ User signed out');
|
logger.debug('auth-service', '✅ User signed out');
|
||||||
@ -91,85 +95,62 @@ const Header: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppBar
|
<AppBar
|
||||||
position="fixed"
|
position="fixed"
|
||||||
sx={{
|
sx={{
|
||||||
height: `${HEADER_HEIGHT}px`,
|
height: `${HEADER_HEIGHT}px`,
|
||||||
bgcolor: theme.palette.background.paper,
|
bgcolor: theme.palette.background.paper,
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
boxShadow: 1
|
boxShadow: 1
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Toolbar sx={{
|
<Toolbar sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
minHeight: `${HEADER_HEIGHT}px !important`,
|
alignItems: 'center',
|
||||||
height: `${HEADER_HEIGHT}px`,
|
height: '100%'
|
||||||
gap: 2,
|
|
||||||
px: { xs: 1, sm: 2 }
|
|
||||||
}}>
|
}}>
|
||||||
<Box sx={{
|
{showGraphNavigation && (
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 2,
|
|
||||||
minWidth: { xs: 'auto', sm: '200px' }
|
|
||||||
}}>
|
|
||||||
<Typography
|
|
||||||
variant="h6"
|
|
||||||
component="div"
|
|
||||||
className="app-title"
|
|
||||||
sx={{
|
|
||||||
cursor: 'pointer',
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
'&:hover': {
|
|
||||||
color: theme.palette.primary.main
|
|
||||||
},
|
|
||||||
fontSize: { xs: '1rem', sm: '1.25rem' }
|
|
||||||
}}
|
|
||||||
onClick={() => navigate(isAuthenticated ? '/dashboard' : '/')}
|
|
||||||
>
|
|
||||||
ClassroomCopilot
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box sx={{
|
|
||||||
position: 'absolute',
|
|
||||||
left: '50%',
|
|
||||||
transform: 'translateX(-50%)',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
visibility: showGraphNavigation ? 'visible' : 'hidden',
|
|
||||||
width: {
|
|
||||||
xs: 'calc(100% - 160px)', // More space for menu and title
|
|
||||||
sm: 'calc(100% - 200px)', // Standard spacing
|
|
||||||
md: 'auto' // Full width on medium and up
|
|
||||||
},
|
|
||||||
maxWidth: '800px',
|
|
||||||
'& .navigation-controls': {
|
|
||||||
display: { xs: 'none', sm: 'flex' }
|
|
||||||
},
|
|
||||||
'& .context-section': {
|
|
||||||
display: { xs: 'none', md: 'flex' }
|
|
||||||
},
|
|
||||||
'& .context-toggle': {
|
|
||||||
display: 'flex' // Always show the profile/institute toggle
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<GraphNavigator />
|
<GraphNavigator />
|
||||||
</Box>
|
)}
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
component="div"
|
||||||
|
sx={{
|
||||||
|
flexGrow: showGraphNavigation ? 0 : 1,
|
||||||
|
fontWeight: 600,
|
||||||
|
cursor: 'pointer',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 1
|
||||||
|
}}
|
||||||
|
onClick={() => handleNavigation('/')}
|
||||||
|
>
|
||||||
|
<HomeIcon sx={{ color: theme.palette.primary.main }} />
|
||||||
|
Classroom Copilot
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||||
|
{isAuthenticated && (
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
display: { xs: 'none', sm: 'block' }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{user?.email}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
|
||||||
<Box sx={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'flex-end',
|
|
||||||
minWidth: { xs: 'auto', sm: '200px' },
|
|
||||||
ml: 'auto'
|
|
||||||
}}>
|
|
||||||
<IconButton
|
<IconButton
|
||||||
className="menu-button"
|
|
||||||
color="inherit"
|
color="inherit"
|
||||||
|
aria-label="menu"
|
||||||
onClick={handleMenuOpen}
|
onClick={handleMenuOpen}
|
||||||
edge="end"
|
sx={{
|
||||||
sx={{
|
border: `1px solid ${theme.palette.divider}`,
|
||||||
|
borderRadius: 1,
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
bgcolor: theme.palette.action.hover
|
bgcolor: theme.palette.action.hover
|
||||||
}
|
}
|
||||||
@ -177,64 +158,126 @@ const Header: React.FC = () => {
|
|||||||
>
|
>
|
||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
||||||
<Menu
|
<Menu
|
||||||
anchorEl={anchorEl}
|
anchorEl={anchorEl}
|
||||||
open={Boolean(anchorEl)}
|
open={Boolean(anchorEl)}
|
||||||
onClose={handleMenuClose}
|
onClose={handleMenuClose}
|
||||||
slotProps={{
|
PaperProps={{
|
||||||
paper: {
|
sx: {
|
||||||
elevation: 3,
|
width: 280,
|
||||||
sx: {
|
maxHeight: '80vh'
|
||||||
bgcolor: theme.palette.background.paper,
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
minWidth: '240px'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<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 ? [
|
{isAuthenticated ? [
|
||||||
<MenuItem key="dashboard" onClick={() => handleNavigation('/dashboard')}>
|
// Home
|
||||||
|
<MenuItem key="home" onClick={() => handleNavigation('/')}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<HomeIcon />
|
<HomeIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary="Dashboard" />
|
<ListItemText primary="Home" />
|
||||||
</MenuItem>,
|
</MenuItem>,
|
||||||
<Divider key="dashboard-divider" />,
|
<Divider key="home-divider" />,
|
||||||
// Development Tools Section
|
|
||||||
<MenuItem key="tldraw" onClick={() => handleNavigation('/tldraw-dev')}>
|
|
||||||
<ListItemIcon>
|
|
||||||
<TLDrawDevIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary="TLDraw Dev" />
|
|
||||||
</MenuItem>,
|
|
||||||
<MenuItem key="dev" onClick={() => handleNavigation('/dev')}>
|
|
||||||
<ListItemIcon>
|
|
||||||
<DevToolsIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary="Dev Tools" />
|
|
||||||
</MenuItem>,
|
|
||||||
<Divider key="dev-divider" />,
|
|
||||||
|
|
||||||
// Main Features Section
|
// Timetable Section
|
||||||
<MenuItem key="multiplayer" onClick={() => handleNavigation('/multiplayer')}>
|
<Typography
|
||||||
|
key="timetable-header"
|
||||||
|
variant="subtitle2"
|
||||||
|
sx={{
|
||||||
|
px: 2,
|
||||||
|
py: 1,
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
fontWeight: 600,
|
||||||
|
letterSpacing: '0.5px',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
fontSize: '0.75rem'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Timetable & Classes
|
||||||
|
</Typography>,
|
||||||
|
<MenuItem key="timetable" onClick={() => handleNavigation('/timetable')}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<MultiplayerIcon />
|
<ScheduleIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary="Multiplayer" />
|
<ListItemText
|
||||||
|
primary="My Timetable"
|
||||||
|
secondary="View your schedule"
|
||||||
|
/>
|
||||||
</MenuItem>,
|
</MenuItem>,
|
||||||
|
<MenuItem key="classes" onClick={() => handleNavigation('/classes')}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<ClassIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary="Browse Classes"
|
||||||
|
secondary="Find and enroll in classes"
|
||||||
|
/>
|
||||||
|
</MenuItem>,
|
||||||
|
<MenuItem key="my-classes" onClick={() => handleNavigation('/my-classes')}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<BookIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary="My Classes"
|
||||||
|
secondary="Manage your classes"
|
||||||
|
/>
|
||||||
|
</MenuItem>,
|
||||||
|
<MenuItem key="enrollment-requests" onClick={() => handleNavigation('/enrollment-requests')}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<EnrollmentIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary="Enrollment Requests"
|
||||||
|
secondary="Review pending enrollments"
|
||||||
|
/>
|
||||||
|
</MenuItem>,
|
||||||
|
<Divider key="timetable-divider" />,
|
||||||
|
|
||||||
|
// Features Section
|
||||||
|
<Typography
|
||||||
|
key="features-header"
|
||||||
|
variant="subtitle2"
|
||||||
|
sx={{
|
||||||
|
px: 2,
|
||||||
|
py: 1,
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
fontWeight: 600,
|
||||||
|
letterSpacing: '0.5px',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
fontSize: '0.75rem'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Features
|
||||||
|
</Typography>,
|
||||||
<MenuItem key="calendar" onClick={() => handleNavigation('/calendar')}>
|
<MenuItem key="calendar" onClick={() => handleNavigation('/calendar')}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<CalendarIcon />
|
<CalendarIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary="Calendar" />
|
<ListItemText primary="Calendar" />
|
||||||
</MenuItem>,
|
</MenuItem>,
|
||||||
<MenuItem key="planner" onClick={() => handleNavigation('/teacher-planner')}>
|
<MenuItem key="teacher-planner" onClick={() => handleNavigation('/teacher-planner')}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<TeacherPlannerIcon />
|
<TeacherPlannerIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary="Teacher Planner" />
|
<ListItemText primary="Teacher Planner" />
|
||||||
</MenuItem>,
|
</MenuItem>,
|
||||||
<MenuItem key="exam" onClick={() => handleNavigation('/exam-marker')}>
|
<MenuItem key="exam-marker" onClick={() => handleNavigation('/exam-marker')}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<ExamMarkerIcon />
|
<ExamMarkerIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
@ -243,6 +286,21 @@ const Header: React.FC = () => {
|
|||||||
<Divider key="features-divider" />,
|
<Divider key="features-divider" />,
|
||||||
|
|
||||||
// Utilities Section
|
// Utilities Section
|
||||||
|
<Typography
|
||||||
|
key="utilities-header"
|
||||||
|
variant="subtitle2"
|
||||||
|
sx={{
|
||||||
|
px: 2,
|
||||||
|
py: 1,
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
fontWeight: 600,
|
||||||
|
letterSpacing: '0.5px',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
fontSize: '0.75rem'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Utilities
|
||||||
|
</Typography>,
|
||||||
<MenuItem key="settings" onClick={() => handleNavigation('/settings')}>
|
<MenuItem key="settings" onClick={() => handleNavigation('/settings')}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<SettingsIcon />
|
<SettingsIcon />
|
||||||
@ -259,6 +317,21 @@ const Header: React.FC = () => {
|
|||||||
// Admin Section
|
// Admin Section
|
||||||
...(isAdmin ? [
|
...(isAdmin ? [
|
||||||
<Divider key="admin-divider" />,
|
<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')}>
|
<MenuItem key="admin" onClick={() => handleNavigation('/admin')}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<AdminIcon />
|
<AdminIcon />
|
||||||
@ -288,7 +361,7 @@ const Header: React.FC = () => {
|
|||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<TeacherIcon />
|
<TeacherIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary="Sign up as Teacher"
|
primary="Sign up as Teacher"
|
||||||
secondary="Create a teacher account"
|
secondary="Create a teacher account"
|
||||||
/>
|
/>
|
||||||
@ -297,7 +370,7 @@ const Header: React.FC = () => {
|
|||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<StudentIcon />
|
<StudentIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary="Sign up as Student"
|
primary="Sign up as Student"
|
||||||
secondary="Create a student account"
|
secondary="Create a student account"
|
||||||
/>
|
/>
|
||||||
@ -310,4 +383,4 @@ const Header: React.FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Header;
|
export default Header;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user