not working
This commit is contained in:
parent
7c78f39b02
commit
4689aa66c6
@ -12,7 +12,7 @@ import { Snack, SetSnackType } from 'components/Snack';
|
||||
import { User } from 'types/types';
|
||||
import { LoadingComponent } from "components/LoadingComponent";
|
||||
import { AuthProvider, useAuth, ProtectedRoute } from 'hooks/AuthContext';
|
||||
import { useAppState, useSelectedCandidate } from 'hooks/GlobalContext';
|
||||
import { useSelectedCandidate } from 'hooks/GlobalContext';
|
||||
import {
|
||||
getMainNavigationItems,
|
||||
getAllRoutes,
|
||||
@ -50,7 +50,7 @@ const BackstoryPageContainer = (props: BackstoryPageContainerProps) => {
|
||||
<Box sx={{
|
||||
display: "flex",
|
||||
p: { xs: 0, sm: 0.5 },
|
||||
flexGrow: 1,
|
||||
flexGrow: 1,
|
||||
minHeight: "min-content",
|
||||
}}>
|
||||
<Paper
|
||||
@ -76,34 +76,29 @@ const BackstoryPageContainer = (props: BackstoryPageContainerProps) => {
|
||||
interface BackstoryLayoutProps {
|
||||
page: string;
|
||||
chatRef: React.Ref<any>;
|
||||
snackRef: React.Ref<any>;
|
||||
submitQuery: any;
|
||||
}
|
||||
|
||||
const BackstoryLayout: React.FC<BackstoryLayoutProps> = (props: BackstoryLayoutProps) => {
|
||||
const { page, chatRef } = props;
|
||||
const { setSnack } = useAppState();
|
||||
const { page, chatRef, snackRef, submitQuery } = props;
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const { guest, user } = useAuth();
|
||||
const { selectedCandidate } = useSelectedCandidate();
|
||||
const [navigationItems, setNavigationItems] = useState<NavigationItem[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const userType = user?.userType || null;
|
||||
setNavigationItems(getMainNavigationItems(userType, user?.isAdmin ? true : false));
|
||||
setNavigationItems(getMainNavigationItems(userType));
|
||||
}, [user]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log({ guest, user });
|
||||
}, [guest, user]);
|
||||
|
||||
// Generate dynamic routes from navigation config
|
||||
const generateRoutes = () => {
|
||||
if (!guest && !user) return null;
|
||||
if (!guest) return null;
|
||||
|
||||
const userType = user?.userType || null;
|
||||
const isAdmin = user?.isAdmin ? true : false;
|
||||
|
||||
// Get all routes from navigation config
|
||||
const routes = getAllRoutes(userType, isAdmin);
|
||||
const routes = getAllRoutes(userType);
|
||||
|
||||
return routes.map((route, index) => {
|
||||
if (!route.path || !route.component) return null;
|
||||
@ -129,10 +124,9 @@ const BackstoryLayout: React.FC<BackstoryLayoutProps> = (props: BackstoryLayoutP
|
||||
height: "100%",
|
||||
maxHeight: "100%",
|
||||
minHeight: "100%",
|
||||
flexDirection: "column"
|
||||
flexDirection: "column"
|
||||
}}>
|
||||
<Header
|
||||
setSnack={setSnack}
|
||||
<Header
|
||||
currentPath={page}
|
||||
navigate={navigate}
|
||||
navigationItems={navigationItems}
|
||||
@ -164,7 +158,7 @@ const BackstoryLayout: React.FC<BackstoryLayoutProps> = (props: BackstoryLayoutP
|
||||
}}
|
||||
>
|
||||
<BackstoryPageContainer>
|
||||
{!guest && !user && (
|
||||
{!guest && (
|
||||
<Box>
|
||||
<LoadingComponent
|
||||
loadingText="Creating session..."
|
||||
@ -174,7 +168,7 @@ const BackstoryLayout: React.FC<BackstoryLayoutProps> = (props: BackstoryLayoutP
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
{(guest || user) && (
|
||||
{guest && (
|
||||
<>
|
||||
<Outlet />
|
||||
<Routes>
|
||||
@ -185,6 +179,7 @@ const BackstoryLayout: React.FC<BackstoryLayoutProps> = (props: BackstoryLayoutP
|
||||
{location.pathname === "/" && <Footer />}
|
||||
</BackstoryPageContainer>
|
||||
</Scrollable>
|
||||
<Snack ref={snackRef} />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
@ -20,7 +20,7 @@ const getBackstoryDynamicRoutes = (props: BackstoryDynamicRoutesProps): ReactNod
|
||||
const isAdmin = user?.isAdmin ? true : false;
|
||||
|
||||
// Get all routes from navigation config
|
||||
const routes = getAllRoutes(userType, isAdmin);
|
||||
const routes = getAllRoutes(userType);
|
||||
|
||||
return routes.map((route: NavigationItem, index: number) => {
|
||||
if (!route.path || !route.component) return null;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// components/layout/Header.tsx
|
||||
import React, { JSX, useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { NavigateFunction, useLocation } from 'react-router-dom';
|
||||
import {
|
||||
AppBar,
|
||||
@ -26,7 +26,6 @@ import {
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
SxProps,
|
||||
} from '@mui/material';
|
||||
import { styled, useTheme } from '@mui/material/styles';
|
||||
import {
|
||||
@ -39,8 +38,8 @@ import {
|
||||
ExpandLess,
|
||||
KeyboardArrowDown,
|
||||
} from '@mui/icons-material';
|
||||
import FaceRetouchingNaturalIcon from '@mui/icons-material/FaceRetouchingNatural';
|
||||
|
||||
import { getUserMenuItemsByGroup } from 'config/navigationConfig';
|
||||
import { NavigationItem } from 'types/navigation';
|
||||
import { Beta } from 'components/ui/Beta';
|
||||
import { Candidate, Employer } from 'types/types';
|
||||
@ -121,11 +120,13 @@ interface HeaderProps {
|
||||
navigationItems: NavigationItem[];
|
||||
currentPath: string;
|
||||
sessionId?: string | null;
|
||||
setSnack: SetSnackType;
|
||||
}
|
||||
|
||||
const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
const { user, logout } = useAuth();
|
||||
const { setSnack } = useAppState();
|
||||
const candidate: Candidate | null = (user && user.userType === "candidate") ? user as Candidate : null;
|
||||
const employer: Employer | null = (user && user.userType === "employer") ? user as Employer : null;
|
||||
const {
|
||||
transparent = false,
|
||||
className,
|
||||
@ -133,8 +134,6 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
navigationItems,
|
||||
sessionId,
|
||||
} = props;
|
||||
|
||||
const { setSnack } = useAppState();
|
||||
const theme = useTheme();
|
||||
const location = useLocation();
|
||||
|
||||
@ -151,52 +150,97 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
const [userMenuAnchor, setUserMenuAnchor] = useState<null | HTMLElement>(null);
|
||||
const userMenuOpen = Boolean(userMenuAnchor);
|
||||
|
||||
// User menu items
|
||||
const userMenuItems = [
|
||||
{
|
||||
id: 'profile',
|
||||
label: 'Profile',
|
||||
icon: <Person fontSize="small" />,
|
||||
action: () => navigate(`/${user?.userType}/profile`)
|
||||
},
|
||||
{
|
||||
id: 'dashboard',
|
||||
label: 'Dashboard',
|
||||
icon: <Dashboard fontSize="small" />,
|
||||
action: () => navigate(`/${user?.userType}/dashboard`)
|
||||
},
|
||||
{
|
||||
id: 'settings',
|
||||
label: 'Settings',
|
||||
icon: <Settings fontSize="small" />,
|
||||
action: () => navigate(`/${user?.userType}/settings`)
|
||||
},
|
||||
{
|
||||
id: 'divider',
|
||||
label: '',
|
||||
icon: null,
|
||||
action: () => { }
|
||||
},
|
||||
{
|
||||
id: 'logout',
|
||||
label: 'Logout',
|
||||
icon: <Logout fontSize="small" />,
|
||||
action: () => {
|
||||
logout();
|
||||
navigate('/');
|
||||
}
|
||||
}
|
||||
];
|
||||
// Get user menu items from navigation config
|
||||
const userMenuGroups = getUserMenuItemsByGroup(user?.userType || null);
|
||||
|
||||
if (user?.isAdmin) {
|
||||
const divider = userMenuItems.findIndex(p => p.id === 'divider');
|
||||
if (divider !== -1) {
|
||||
userMenuItems.splice(divider, 0, ...[
|
||||
{ id: 'divider', label: '', icon: null, action: () => { } },
|
||||
{ id: 'generate', label: 'Generate Candidate', icon: <FaceRetouchingNaturalIcon fontSize="small" />, action: () => { navigate('/admin/generate-candidate'); } }
|
||||
]);
|
||||
// Create user menu items array with proper actions
|
||||
const createUserMenuItems = () => {
|
||||
const items: Array<{
|
||||
id: string;
|
||||
label: string;
|
||||
icon: React.ReactElement | null;
|
||||
action: () => void;
|
||||
group?: string;
|
||||
}> = [];
|
||||
|
||||
// Add profile group items
|
||||
userMenuGroups.profile.forEach(item => {
|
||||
if (!item.divider) {
|
||||
items.push({
|
||||
id: item.id,
|
||||
label: item.label as string,
|
||||
icon: item.icon || null,
|
||||
action: () => item.path && navigate(item.path),
|
||||
group: 'profile'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Add account group items
|
||||
userMenuGroups.account.forEach(item => {
|
||||
if (!item.divider) {
|
||||
items.push({
|
||||
id: item.id,
|
||||
label: item.label as string,
|
||||
icon: item.icon || null,
|
||||
action: () => item.path && navigate(item.path),
|
||||
group: 'account'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Add divider if we have items before system group
|
||||
if (items.length > 0 && userMenuGroups.system.length > 0) {
|
||||
items.push({
|
||||
id: 'divider',
|
||||
label: '',
|
||||
icon: null,
|
||||
action: () => { },
|
||||
group: 'divider'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add system group items with special handling for logout
|
||||
userMenuGroups.system.forEach(item => {
|
||||
if (item.id === 'logout') {
|
||||
items.push({
|
||||
id: 'logout',
|
||||
label: 'Logout',
|
||||
icon: <Logout fontSize="small" />,
|
||||
action: () => {
|
||||
logout();
|
||||
navigate('/');
|
||||
},
|
||||
group: 'system'
|
||||
});
|
||||
} else if (!item.divider) {
|
||||
items.push({
|
||||
id: item.id,
|
||||
label: item.label as string,
|
||||
icon: item.icon || null,
|
||||
action: () => item.path && navigate(item.path),
|
||||
group: 'system'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Add other group items
|
||||
userMenuGroups.other.forEach(item => {
|
||||
if (!item.divider) {
|
||||
items.push({
|
||||
id: item.id,
|
||||
label: item.label as string,
|
||||
icon: item.icon || null,
|
||||
action: () => item.path && navigate(item.path),
|
||||
group: 'other'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
const userMenuItems = createUserMenuItems();
|
||||
|
||||
// Helper function to check if current path matches navigation item
|
||||
const isCurrentPath = (item: NavigationItem): boolean => {
|
||||
@ -210,7 +254,7 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
// Helper function to check if any child is current path
|
||||
const hasActiveChild = (item: NavigationItem): boolean => {
|
||||
if (!item.children) return false;
|
||||
return item.children.some(child => isCurrentPath(child) || hasActiveChild(child));
|
||||
return item.children.some((child: any) => isCurrentPath(child) || hasActiveChild(child));
|
||||
};
|
||||
|
||||
// Desktop dropdown handlers
|
||||
@ -239,8 +283,8 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
setUserMenuAnchor(null);
|
||||
};
|
||||
|
||||
const handleUserMenuAction = (item: typeof userMenuItems[0]) => {
|
||||
if (item.id !== 'divider') {
|
||||
const handleUserMenuAction = (item: { id: string; label: string; icon: React.ReactElement | null; action: () => void; group?: string }) => {
|
||||
if (item.group !== 'divider') {
|
||||
item.action();
|
||||
handleUserMenuClose();
|
||||
}
|
||||
@ -257,23 +301,14 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
// Render desktop navigation with dropdowns
|
||||
const renderDesktopNavigation = () => {
|
||||
return (
|
||||
<Box sx={{ display: 'flex', width: "100%", alignItems: 'center', justifyContent: "space-between", "& > :last-of-type": { marginRight: "auto"} }}>
|
||||
{navigationItems.map((item, index) => {
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
{navigationItems.map((item) => {
|
||||
const hasChildren = item.children && item.children.length > 0;
|
||||
const isActive = isCurrentPath(item) || hasActiveChild(item);
|
||||
// Default is centered for all menu items
|
||||
let sx : SxProps = { justifycontent: "center"};
|
||||
// First item ("Backstory") is left aligned
|
||||
if (index === 0) {
|
||||
sx = { marginRight: "auto" };
|
||||
}
|
||||
// If there is an Admin menu, it is on the far right
|
||||
if (item.userTypes?.includes('admin')) {
|
||||
sx = { marginLeft: "auto"};
|
||||
}
|
||||
|
||||
if (hasChildren) {
|
||||
return (
|
||||
<Box key={item.id} sx={sx}>
|
||||
<Box key={item.id}>
|
||||
<DropdownButton
|
||||
onClick={(e) => handleDropdownOpen(e, item.id)}
|
||||
endIcon={<KeyboardArrowDown />}
|
||||
@ -293,16 +328,15 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
transformOrigin={{ vertical: 'top', horizontal: 'left' }}
|
||||
TransitionComponent={Fade}
|
||||
>
|
||||
{item.children?.map((child) => (
|
||||
{item.children?.map((child: any) => (
|
||||
<MenuItem
|
||||
key={child.id}
|
||||
onClick={() => child.path && handleNavigate(child.path)}
|
||||
selected={isCurrentPath(child)}
|
||||
disabled={!child.path}
|
||||
sx={{ alignContent: 'center', margin: "0 !important" }}
|
||||
>
|
||||
{child.icon && <ListItemIcon>{child.icon}</ListItemIcon>}
|
||||
<ListItemText sx={{ p: 0, margin: "0 !important", "& > *": { m: 0 } }}>{child.label}</ListItemText>
|
||||
<ListItemText>{child.label}</ListItemText>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
@ -316,7 +350,6 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
sx={{
|
||||
backgroundColor: isActive ? 'action.selected' : 'transparent',
|
||||
color: isActive ? 'secondary.main' : 'primary.contrastText',
|
||||
...sx
|
||||
}}
|
||||
>
|
||||
{item.icon && <Box sx={{ mr: 1, display: 'flex' }}>{item.icon}</Box>}
|
||||
@ -367,11 +400,11 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
<ListItemText
|
||||
primary={item.label}
|
||||
sx={{
|
||||
'& .MuiTypography-root': {
|
||||
'& .MuiTypography-root': {
|
||||
fontSize: depth > 0 ? '0.875rem' : '1rem',
|
||||
fontWeight: depth === 0 ? 500 : 400,
|
||||
}
|
||||
}}
|
||||
}}
|
||||
/>
|
||||
{hasChildren && (
|
||||
<IconButton size="small">
|
||||
@ -383,7 +416,7 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
{hasChildren && (
|
||||
<Collapse in={isExpanded} timeout="auto" unmountOnExit>
|
||||
<List disablePadding>
|
||||
{item.children?.map((child) => renderNavigationItem(child, depth + 1))}
|
||||
{item.children?.map((child: any) => renderNavigationItem(child, depth + 1))}
|
||||
</List>
|
||||
</Collapse>
|
||||
)}
|
||||
@ -412,13 +445,13 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
<UserMenuContainer>
|
||||
<List dense>
|
||||
{userMenuItems.map((item, index) => (
|
||||
item.id === 'divider' ? (
|
||||
item.group === 'divider' ? (
|
||||
<Divider key={`divider-${index}`} />
|
||||
) : (
|
||||
<ListItem key={item.id} disablePadding>
|
||||
<ListItemButton onClick={() => handleUserMenuAction(item)} sx={{ alignContent: "center" }}>
|
||||
<ListItemButton onClick={() => handleUserMenuAction(item)}>
|
||||
{item.icon && <ListItemIcon sx={{ minWidth: 36 }}>{item.icon}</ListItemIcon>}
|
||||
<ListItemText primary={item.label} sx={{ padding: 0 }} />
|
||||
<ListItemText primary={item.label} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
)
|
||||
@ -535,7 +568,7 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
content={`${window.location.origin}${window.location.pathname}?id=${sessionId}`}
|
||||
onClick={() => {
|
||||
navigate(`${window.location.pathname}?id=${sessionId}`);
|
||||
setSnack("Link copied!");
|
||||
setSnack("Link copied!");
|
||||
}}
|
||||
size="large"
|
||||
/>
|
||||
@ -558,7 +591,7 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
|
||||
</Container>
|
||||
<Beta
|
||||
sx={{ left: "-90px", "& .mobile": { right: "-72px" } }}
|
||||
onClick={() => { navigate('/docs/beta'); }}
|
||||
onClick={() => { navigate('/docs/beta'); }}
|
||||
/>
|
||||
</StyledAppBar>
|
||||
);
|
||||
|
@ -1,5 +1,3 @@
|
||||
|
||||
// config/navigationConfig.tsx
|
||||
import React from 'react';
|
||||
import {
|
||||
Chat as ChatIcon,
|
||||
@ -8,18 +6,16 @@ import {
|
||||
BarChart as BarChartIcon,
|
||||
Settings as SettingsIcon,
|
||||
Work as WorkIcon,
|
||||
Info as InfoIcon,
|
||||
Person as PersonIcon,
|
||||
Business as BusinessIcon,
|
||||
Quiz as QuizIcon,
|
||||
Analytics as AnalyticsIcon,
|
||||
Search as SearchIcon,
|
||||
Bookmark as BookmarkIcon,
|
||||
BubbleChart,
|
||||
History as HistoryIcon,
|
||||
QuestionAnswer as QuestionAnswerIcon,
|
||||
AttachMoney as AttachMoneyIcon,
|
||||
} from '@mui/icons-material';
|
||||
import SchoolIcon from '@mui/icons-material/School';
|
||||
|
||||
import FaceRetouchingNaturalIcon from '@mui/icons-material/FaceRetouchingNatural';
|
||||
import LibraryBooksIcon from '@mui/icons-material/LibraryBooks';
|
||||
import { BackstoryLogo } from 'components/ui/BackstoryLogo';
|
||||
import { HomePage } from 'pages/HomePage';
|
||||
import { CandidateChatPage } from 'pages/CandidateChatPage';
|
||||
@ -27,20 +23,19 @@ import { DocsPage } from 'pages/DocsPage';
|
||||
import { CreateProfilePage } from 'pages/candidate/ProfileWizard';
|
||||
import { VectorVisualizerPage } from 'pages/VectorVisualizerPage';
|
||||
import { BetaPage } from 'pages/BetaPage';
|
||||
import { CandidateListingPage } from 'pages/FindCandidatePage';
|
||||
import { JobAnalysisPage } from 'pages/JobAnalysisPage';
|
||||
import { GenerateCandidate } from 'pages/GenerateCandidate';
|
||||
import { Settings } from 'pages/candidate/Settings';
|
||||
import { LoginPage } from 'pages/LoginPage';
|
||||
import { CandidateDashboard } from 'pages/candidate/Dashboard';
|
||||
import { EmailVerificationPage } from 'components/EmailVerificationComponents';
|
||||
import { Box, Typography } from '@mui/material';
|
||||
import { Typography } from '@mui/material';
|
||||
import { CandidateDashboard } from 'pages/candidate/Dashboard';
|
||||
import { NavigationConfig, NavigationItem } from 'types/navigation';
|
||||
import { CandidateProfile } from 'pages/candidate/Profile';
|
||||
import { DocumentManager } from 'components/DocumentManager';
|
||||
import { VectorVisualizer } from 'components/VectorVisualizer';
|
||||
import { HowItWorks } from 'pages/HowItWorks';
|
||||
|
||||
// Beta page components for placeholder routes
|
||||
const BackstoryPage = () => (<BetaPage><Typography variant="h4">Backstory</Typography></BetaPage>);
|
||||
const ResumesPage = () => (<BetaPage><Typography variant="h4">Resumes</Typography></BetaPage>);
|
||||
const QASetupPage = () => (<BetaPage><Typography variant="h4">Q&A Setup</Typography></BetaPage>);
|
||||
const SearchPage = () => (<BetaPage><Typography variant="h4">Search</Typography></BetaPage>);
|
||||
const SavedPage = () => (<BetaPage><Typography variant="h4">Saved</Typography></BetaPage>);
|
||||
const JobsPage = () => (<BetaPage><Typography variant="h4">Jobs</Typography></BetaPage>);
|
||||
@ -51,8 +46,8 @@ const SettingsPage = () => (<BetaPage><Typography variant="h4">Settings</Typogra
|
||||
|
||||
export const navigationConfig: NavigationConfig = {
|
||||
items: [
|
||||
{ id: 'home', label: <BackstoryLogo />, path: '/', component: <HowItWorks />, userTypes: ['guest', 'candidate', 'employer'], exact: true, },
|
||||
// { id: 'how-it-works', label: 'How It Works', path: '/how-it-works', icon: <SchoolIcon />, component: <HowItWorks />, userTypes: ['guest', 'candidate', 'employer',], },
|
||||
{ id: 'home', label: <BackstoryLogo />, path: '/', component: <HomePage />, userTypes: ['guest', 'candidate', 'employer'], exact: true, },
|
||||
{ id: 'how-it-works', label: 'How It Works', path: '/how-it-works', icon: <SchoolIcon />, component: <HowItWorks />, userTypes: ['guest', 'candidate', 'employer',], },
|
||||
{ id: 'job-analysis', label: 'Job Analysis', path: '/job-analysis', icon: <WorkIcon />, component: <JobAnalysisPage />, userTypes: ['guest', 'candidate', 'employer',], },
|
||||
{ id: 'chat', label: 'Candidate Chat', path: '/chat', icon: <ChatIcon />, component: <CandidateChatPage />, userTypes: ['guest', 'candidate', 'employer',], }, {
|
||||
id: 'candidate-menu', label: 'Tools', icon: <PersonIcon />, userTypes: ['candidate'], children: [
|
||||
@ -61,7 +56,9 @@ export const navigationConfig: NavigationConfig = {
|
||||
{ id: 'candidate-docs', label: 'Documents', icon: <BubbleChart />, path: '/candidate/documents', component: <Box sx={{ display: "flex", width: "100%", flexDirection: "column" }}><VectorVisualizer /><DocumentManager /></Box>, userTypes: ['candidate'] },
|
||||
{ id: 'candidate-qa-setup', label: 'Q&A Setup', icon: <QuizIcon />, path: '/candidate/qa-setup', component: <BetaPage><Box>Candidate q&a setup page</Box></BetaPage>, userTypes: ['candidate'] },
|
||||
{ id: 'candidate-analytics', label: 'Analytics', icon: <AnalyticsIcon />, path: '/candidate/analytics', component: <BetaPage><Box>Candidate analytics page</Box></BetaPage>, userTypes: ['candidate'] },
|
||||
{ id: 'candidate-job-analysis', label: 'Job Analysis', path: '/candidate/job-analysis', icon: <WorkIcon />, component: <JobAnalysisPage />, userTypes: ['candidate'], },
|
||||
{ id: 'candidate-job-analysis', label: 'Job Analysis', path: '/candidate/job-analysis', icon: <WorkIcon />, component: <JobAnalysisPage />, userTypes: ['candidate'], showInNavigation: false,
|
||||
showInUserMenu: true,
|
||||
userMenuGroup: 'profile',},
|
||||
{ id: 'candidate-resumes', label: 'Resumes', icon: <DescriptionIcon />, path: '/candidate/resumes', component: <BetaPage><Box>Candidate resumes page</Box></BetaPage>, userTypes: ['candidate'] },
|
||||
{ id: 'candidate-settings', label: 'Settings', path: '/candidate/settings', icon: <SettingsIcon />, component: <Settings />, userTypes: ['candidate'], },
|
||||
],
|
||||
@ -78,22 +75,101 @@ export const navigationConfig: NavigationConfig = {
|
||||
{ id: 'employer-settings', label: 'Settings', path: '/employer/settings', icon: <SettingsIcon />, component: <SettingsPage />, userTypes: ['employer'], },
|
||||
],
|
||||
},
|
||||
// { id: 'find-candidate', label: 'Find a Candidate', path: '/find-a-candidate', icon: <PersonSearchIcon />, component: <CandidateListingPage />, userTypes: ['guest', 'candidate', 'employer'], },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'admin-menu',
|
||||
label: 'Admin',
|
||||
icon: <PersonIcon />,
|
||||
userTypes: ['admin'],
|
||||
children: [
|
||||
{ id: 'generate-candidate', label: 'Generate Candidate', path: '/admin/generate-candidate', icon: <FaceRetouchingNaturalIcon />, component: <GenerateCandidate />, userTypes: ['admin'] },
|
||||
{ id: 'docs', label: 'Docs', path: '/docs/*', icon: <LibraryBooksIcon />, component: <DocsPage />, userTypes: ['admin'], },
|
||||
],
|
||||
id: 'global-tools',
|
||||
label: 'Tools',
|
||||
icon: <SettingsIcon />,
|
||||
userTypes: ['candidate', 'employer'],
|
||||
showInNavigation: true,
|
||||
children: [
|
||||
{
|
||||
id: 'knowledge-explorer',
|
||||
label: 'Knowledge Explorer',
|
||||
path: '/knowledge-explorer',
|
||||
icon: <WorkIcon />,
|
||||
component: <VectorVisualizerPage />,
|
||||
userTypes: ['candidate', 'employer'],
|
||||
showInNavigation: true,
|
||||
},
|
||||
{
|
||||
id: 'job-analysis',
|
||||
label: 'Job Analysis',
|
||||
path: '/job-analysis',
|
||||
icon: <WorkIcon />,
|
||||
component: <JobAnalysisPage />,
|
||||
userTypes: ['candidate', 'employer'],
|
||||
showInNavigation: true,
|
||||
},
|
||||
{
|
||||
id: 'generate-candidate',
|
||||
label: 'Generate Candidate',
|
||||
path: '/generate-candidate',
|
||||
icon: <PersonIcon />,
|
||||
component: <GenerateCandidate />,
|
||||
userTypes: ['candidate', 'employer'],
|
||||
showInNavigation: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
// User menu only items (not shown in main navigation)
|
||||
{
|
||||
id: 'user-profile',
|
||||
label: 'Profile',
|
||||
path: '/profile',
|
||||
icon: <PersonIcon />,
|
||||
component: <AnalyticsPage />, // Replace with actual profile page
|
||||
userTypes: ['candidate', 'employer'],
|
||||
showInNavigation: false,
|
||||
showInUserMenu: true,
|
||||
userMenuGroup: 'profile',
|
||||
},
|
||||
{
|
||||
id: 'account-settings',
|
||||
label: 'Account Settings',
|
||||
path: '/account/settings',
|
||||
icon: <SettingsIcon />,
|
||||
component: <SettingsPage />,
|
||||
userTypes: ['candidate', 'employer'],
|
||||
showInNavigation: false,
|
||||
showInUserMenu: true,
|
||||
userMenuGroup: 'account',
|
||||
},
|
||||
{
|
||||
id: 'billing',
|
||||
label: 'Billing',
|
||||
path: '/billing',
|
||||
icon: <AttachMoneyIcon />,
|
||||
component: <AnalyticsPage />, // Replace with actual billing page
|
||||
userTypes: ['candidate', 'employer'],
|
||||
showInNavigation: false,
|
||||
showInUserMenu: true,
|
||||
userMenuGroup: 'account',
|
||||
},
|
||||
{
|
||||
id: 'user-menu-divider',
|
||||
label: '',
|
||||
userTypes: ['candidate', 'employer'],
|
||||
showInNavigation: false,
|
||||
showInUserMenu: true,
|
||||
divider: true,
|
||||
},
|
||||
{
|
||||
id: 'logout',
|
||||
label: 'Logout',
|
||||
icon: <PersonIcon />, // This will be handled specially in Header
|
||||
userTypes: ['candidate', 'employer'],
|
||||
showInNavigation: false,
|
||||
showInUserMenu: true,
|
||||
userMenuGroup: 'system',
|
||||
},
|
||||
// Auth routes (special handling)
|
||||
{
|
||||
id: 'auth',
|
||||
label: 'Auth',
|
||||
userTypes: ['guest', 'candidate', 'employer'],
|
||||
showInNavigation: false,
|
||||
children: [
|
||||
{
|
||||
id: 'register',
|
||||
@ -101,6 +177,7 @@ export const navigationConfig: NavigationConfig = {
|
||||
path: '/register',
|
||||
component: <BetaPage><CreateProfilePage /></BetaPage>,
|
||||
userTypes: ['guest'],
|
||||
showInNavigation: false,
|
||||
},
|
||||
{
|
||||
id: 'login',
|
||||
@ -108,6 +185,7 @@ export const navigationConfig: NavigationConfig = {
|
||||
path: '/login/*',
|
||||
component: <LoginPage />,
|
||||
userTypes: ['guest', 'candidate', 'employer'],
|
||||
showInNavigation: false,
|
||||
},
|
||||
{
|
||||
id: 'verify-email',
|
||||
@ -115,13 +193,15 @@ export const navigationConfig: NavigationConfig = {
|
||||
path: '/login/verify-email',
|
||||
component: <EmailVerificationPage />,
|
||||
userTypes: ['guest', 'candidate', 'employer'],
|
||||
showInNavigation: false,
|
||||
},
|
||||
{
|
||||
id: 'logout',
|
||||
id: 'logout-page',
|
||||
label: 'Logout',
|
||||
path: '/logout',
|
||||
component: <LogoutPage />,
|
||||
userTypes: ['candidate', 'employer'],
|
||||
showInNavigation: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -132,16 +212,19 @@ export const navigationConfig: NavigationConfig = {
|
||||
path: '*',
|
||||
component: <BetaPage />,
|
||||
userTypes: ['guest', 'candidate', 'employer'],
|
||||
showInNavigation: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Utility functions for working with navigation config
|
||||
export const getNavigationItemsForUser = (userType: 'guest' | 'candidate' | 'employer' | null, isAdmin: boolean = false): NavigationItem[] => {
|
||||
const currentUserType = userType || 'guest';
|
||||
export const getNavigationItemsForUser = (userType: 'guest' | 'candidate' | 'employer' | null): NavigationItem[] => {
|
||||
const currentUserType = userType || 'guest';
|
||||
|
||||
const filterItems = (items: NavigationItem[]): NavigationItem[] => {
|
||||
return items
|
||||
.filter(item => !item.userTypes || item.userTypes.includes(currentUserType) || (item.userTypes.includes('admin') && isAdmin))
|
||||
.filter(item => !item.userTypes || item.userTypes.includes(currentUserType))
|
||||
.filter(item => item.showInNavigation !== false) // Default to true if not specified
|
||||
.map(item => ({
|
||||
...item,
|
||||
children: item.children ? filterItems(item.children) : undefined,
|
||||
@ -152,14 +235,14 @@ export const getNavigationItemsForUser = (userType: 'guest' | 'candidate' | 'emp
|
||||
return filterItems(navigationConfig.items);
|
||||
};
|
||||
|
||||
export const getAllRoutes = (userType: 'guest' | 'candidate' | 'employer' | null, isAdmin: boolean = false): NavigationItem[] => {
|
||||
export const getAllRoutes = (userType: 'guest' | 'candidate' | 'employer' | null): NavigationItem[] => {
|
||||
const currentUserType = userType || 'guest';
|
||||
|
||||
const extractRoutes = (items: NavigationItem[]): NavigationItem[] => {
|
||||
const routes: NavigationItem[] = [];
|
||||
|
||||
items.forEach(item => {
|
||||
if (!item.userTypes || item.userTypes.includes(currentUserType) || (item.userTypes.includes('admin') && isAdmin)) {
|
||||
if (!item.userTypes || item.userTypes.includes(currentUserType)) {
|
||||
if (item.path && item.component) {
|
||||
routes.push(item);
|
||||
}
|
||||
@ -175,11 +258,55 @@ export const getAllRoutes = (userType: 'guest' | 'candidate' | 'employer' | null
|
||||
return extractRoutes(navigationConfig.items);
|
||||
};
|
||||
|
||||
export const getMainNavigationItems = (userType: 'guest' | 'candidate' | 'employer' | null, isAdmin: boolean = false): NavigationItem[] => {
|
||||
return getNavigationItemsForUser(userType, isAdmin)
|
||||
export const getMainNavigationItems = (userType: 'guest' | 'candidate' | 'employer' | null): NavigationItem[] => {
|
||||
return getNavigationItemsForUser(userType)
|
||||
.filter(item =>
|
||||
item.id !== 'auth' &&
|
||||
item.id !== 'catch-all' &&
|
||||
item.showInNavigation !== false &&
|
||||
(item.path || (item.children && item.children.length > 0))
|
||||
);
|
||||
};
|
||||
|
||||
export const getUserMenuItems = (userType: 'candidate' | 'employer' | 'guest' | null): NavigationItem[] => {
|
||||
if (!userType) return [];
|
||||
|
||||
const extractUserMenuItems = (items: NavigationItem[]): NavigationItem[] => {
|
||||
const menuItems: NavigationItem[] = [];
|
||||
|
||||
items.forEach(item => {
|
||||
if (!item.userTypes || item.userTypes.includes(userType)) {
|
||||
if (item.showInUserMenu) {
|
||||
menuItems.push(item);
|
||||
}
|
||||
if (item.children) {
|
||||
menuItems.push(...extractUserMenuItems(item.children));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return menuItems;
|
||||
};
|
||||
|
||||
return extractUserMenuItems(navigationConfig.items);
|
||||
};
|
||||
|
||||
export const getUserMenuItemsByGroup = (userType: 'candidate' | 'employer' | 'guest' | null): { [key: string]: NavigationItem[] } => {
|
||||
const menuItems = getUserMenuItems(userType);
|
||||
const grouped: { [key: string]: NavigationItem[] } = {
|
||||
profile: [],
|
||||
account: [],
|
||||
system: [],
|
||||
other: []
|
||||
};
|
||||
|
||||
menuItems.forEach(item => {
|
||||
const group = item.userMenuGroup || 'other';
|
||||
if (!grouped[group]) {
|
||||
grouped[group] = [];
|
||||
}
|
||||
grouped[group].push(item);
|
||||
});
|
||||
|
||||
return grouped;
|
||||
};
|
@ -1,4 +1,3 @@
|
||||
// types/navigation.ts
|
||||
import { ReactElement } from 'react';
|
||||
|
||||
export interface NavigationItem {
|
||||
@ -8,9 +7,12 @@ export interface NavigationItem {
|
||||
icon?: ReactElement;
|
||||
children?: NavigationItem[];
|
||||
component?: ReactElement;
|
||||
userTypes?: ('candidate' | 'employer' | 'guest' | 'admin')[];
|
||||
userTypes?: ('candidate' | 'employer' | 'guest')[];
|
||||
exact?: boolean;
|
||||
divider?: boolean;
|
||||
showInNavigation?: boolean; // Controls if item appears in main navigation
|
||||
showInUserMenu?: boolean; // Controls if item appears in user menu
|
||||
userMenuGroup?: 'profile' | 'account' | 'system'; // Groups items in user menu
|
||||
}
|
||||
|
||||
export interface NavigationConfig {
|
||||
|
Loading…
x
Reference in New Issue
Block a user