backstory/frontend/src/config/navigationConfig.tsx
James Ketrenos 4a7a72812f Do not use cached skills if content updated
Add candidate/job route to job-analysis
2025-07-08 13:48:47 -07:00

388 lines
11 KiB
TypeScript

import React, { JSX } from 'react';
import {
Chat as ChatIcon,
Dashboard as DashboardIcon,
Settings as SettingsIcon,
Work as WorkIcon,
Person as PersonIcon,
BubbleChart,
AutoFixHigh,
} from '@mui/icons-material';
import EditDocumentIcon from '@mui/icons-material/EditDocument';
import { BackstoryLogo } from 'components/ui/BackstoryLogo';
import { CandidateChatPage } from 'pages/CandidateChatPage';
import { BetaPage } from 'pages/BetaPage';
import { JobAnalysisPage } from 'pages/JobAnalysisPage';
import { GenerateCandidate } from 'pages/GenerateCandidate';
import { LoginPage } from 'pages/LoginPage';
import { EmailVerificationPage } from 'components/EmailVerificationComponents';
import { Box, Typography } from '@mui/material';
import { CandidateDashboard } from 'pages/candidate/Dashboard';
import { NavigationConfig, NavigationItem } from 'types/navigation';
import { HowItWorks } from 'pages/HowItWorks';
import { CandidateProfile } from 'pages/candidate/Profile';
import { Settings } from 'pages/candidate/Settings';
import { VectorVisualizer } from 'components/VectorVisualizer';
import { DocumentManager } from 'components/DocumentManager';
import { useAuth } from 'hooks/AuthContext';
import { useNavigate } from 'react-router-dom';
import { JobsViewPage } from 'pages/JobsViewPage';
import { ResumeViewer } from 'components/ui/ResumeViewer';
const LogoutPage = (): JSX.Element => {
const { logout } = useAuth();
const navigate = useNavigate();
logout().then(() => {
navigate('/');
});
return <Typography variant="h4">Logging out...</Typography>;
};
export const navigationConfig: NavigationConfig = {
items: [
{
id: 'home',
label: <BackstoryLogo />,
path: '/',
component: <HowItWorks />,
userTypes: ['guest', 'candidate', 'employer'],
exact: true,
},
{
id: 'job-analysis',
label: 'Job Analysis',
path: '/job-analysis/:candidateId?/:jobId?/:stepId?',
variant: 'fullWidth',
icon: <WorkIcon />,
component: <JobAnalysisPage />,
userTypes: ['guest', 'candidate', 'employer'],
},
{
id: 'chat',
label: 'Candidate Chat',
path: '/chat',
icon: <ChatIcon />,
component: <CandidateChatPage />,
userTypes: ['guest', 'candidate', 'employer'],
},
// {
// id: "explore",
// label: "Explore",
// icon: <SearchIcon />,
// userTypes: ["candidate", "guest", "employer"],
// children: [
// {
// id: "explore-candidates",
// label: "Candidates",
// path: "/candidate/candidates",
// icon: <SearchIcon />,
// component: (
// <CandidatePicker />
// ),
// userTypes: ["candidate", "guest", "employer"],
// },
// ],
// showInNavigation: true,
// },
{
id: 'generate-candidate',
label: 'Generate Candidate',
path: '/admin/generate-candidate',
icon: <AutoFixHigh />,
component: <GenerateCandidate />,
userTypes: ['admin'],
showInNavigation: false,
showInUserMenu: true,
userMenuGroup: 'admin',
},
// User menu only items (not shown in main navigation)
{
id: 'candidate-profile',
label: 'Profile',
icon: <PersonIcon />,
path: '/candidate/profile',
component: <CandidateProfile />,
userTypes: ['candidate'],
userMenuGroup: 'profile',
showInNavigation: false,
showInUserMenu: true,
},
{
id: 'candidate-dashboard',
label: 'Dashboard',
path: '/candidate/dashboard',
icon: <DashboardIcon />,
component: <CandidateDashboard />,
userTypes: ['candidate'],
userMenuGroup: 'profile',
showInNavigation: false,
showInUserMenu: true,
},
{
id: 'explore-jobs',
label: 'Jobs',
path: '/candidate/jobs/:jobId?',
icon: <WorkIcon />,
component: <JobsViewPage />,
variant: 'fullWidth',
userTypes: ['candidate', 'guest', 'employer'],
showInNavigation: false,
showInUserMenu: true,
userMenuGroup: 'profile',
},
{
id: 'explore-resumes',
label: 'Resumes',
path: '/candidate/resumes/:resumeId?',
icon: <EditDocumentIcon />,
component: <ResumeViewer />,
variant: 'fullWidth',
userTypes: ['candidate', 'guest', 'employer'],
showInNavigation: false,
showInUserMenu: true,
userMenuGroup: 'profile',
},
{
id: 'candidate-docs',
label: 'Content',
icon: <BubbleChart />,
path: '/candidate/documents',
component: (
<Box sx={{ display: 'flex', width: '100%', flexDirection: 'column' }}>
<VectorVisualizer />
<DocumentManager />
</Box>
),
userTypes: ['candidate'],
userMenuGroup: 'profile',
showInNavigation: false,
showInUserMenu: true,
},
// {
// 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"],
// showInNavigation: false,
// showInUserMenu: true,
// },
// {
// id: "candidate-analytics",
// label: "Analytics",
// icon: <AnalyticsIcon />,
// path: "/candidate/analytics",
// component: (
// <BetaPage>
// <Box>Candidate analytics page</Box>
// </BetaPage>
// ),
// userTypes: ["candidate"],
// showInNavigation: false,
// showInUserMenu: true,
// },
// {
// id: "candidate-resumes",
// label: "Resumes",
// icon: <DescriptionIcon />,
// path: "/candidate/resumes",
// component: (
// <BetaPage>
// <Box>Candidate resumes page</Box>
// </BetaPage>
// ),
// userTypes: ["candidate"],
// showInNavigation: false,
// showInUserMenu: true,
// },
{
id: 'candidate-settings',
label: 'System Information',
path: '/candidate/settings',
icon: <SettingsIcon />,
component: <Settings />,
userTypes: ['candidate'],
userMenuGroup: 'account',
showInNavigation: false,
showInUserMenu: 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: 'verify-email',
label: 'Verify Email',
path: '/login/verify-email',
component: <EmailVerificationPage />,
userTypes: ['guest', 'candidate', 'employer'],
showInNavigation: false,
},
{
id: 'login',
label: 'Login',
path: '/login/:tab?',
component: <LoginPage />,
userTypes: ['guest', 'candidate', 'employer'],
showInNavigation: false,
},
{
id: 'logout-page',
label: 'Logout',
path: '/logout',
component: <LogoutPage />,
userTypes: ['candidate', 'employer'],
showInNavigation: false,
},
],
},
// Catch-all route
{
id: 'catch-all',
label: 'Not Found',
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
): 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.showInNavigation !== false) // Default to true if not specified
.map(item => ({
...item,
children: item.children ? filterItems(item.children) : undefined,
}))
.filter(item => item.path || (item.children && item.children.length > 0));
};
return filterItems(navigationConfig.items);
};
export const getAllRoutes = (
userType: 'guest' | 'candidate' | 'employer' | null,
isAdmin: boolean
): 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.path && item.component) {
routes.push(item);
}
if (item.children) {
routes.push(...extractRoutes(item.children));
}
}
});
return routes;
};
return extractRoutes(navigationConfig.items);
};
export const getMainNavigationItems = (
userType: 'guest' | 'candidate' | 'employer' | null,
isAdmin: boolean
): NavigationItem[] => {
return getNavigationItemsForUser(userType, isAdmin).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,
isAdmin: boolean
): NavigationItem[] => {
if (!userType) return [];
const extractUserMenuItems = (items: NavigationItem[]): NavigationItem[] => {
const menuItems: NavigationItem[] = [];
items.forEach(item => {
if (!item.userTypes || item.userTypes.includes(userType) || isAdmin) {
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,
isAdmin: boolean
): { [key: string]: NavigationItem[] } => {
const menuItems = getUserMenuItems(userType, isAdmin);
const grouped: { [key: string]: NavigationItem[] } = {
profile: [],
account: [],
system: [],
admin: [],
other: [],
};
menuItems.forEach(item => {
const group = item.userMenuGroup || 'other';
if (!grouped[group]) {
grouped[group] = [];
}
grouped[group].push(item);
});
return grouped;
};