diff --git a/frontend/src/components/layout/BackstoryLayout.tsx b/frontend/src/components/layout/BackstoryLayout.tsx
index 8dad6f9..8a31a69 100644
--- a/frontend/src/components/layout/BackstoryLayout.tsx
+++ b/frontend/src/components/layout/BackstoryLayout.tsx
@@ -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) => {
{
interface BackstoryLayoutProps {
page: string;
chatRef: React.Ref;
+ snackRef: React.Ref;
+ submitQuery: any;
}
const BackstoryLayout: React.FC = (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([]);
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 = (props: BackstoryLayoutP
height: "100%",
maxHeight: "100%",
minHeight: "100%",
- flexDirection: "column"
+ flexDirection: "column"
}}>
- = (props: BackstoryLayoutP
}}
>
- {!guest && !user && (
+ {!guest && (
= (props: BackstoryLayoutP
/>
)}
- {(guest || user) && (
+ {guest && (
<>
@@ -185,6 +179,7 @@ const BackstoryLayout: React.FC = (props: BackstoryLayoutP
{location.pathname === "/" && }
+
);
diff --git a/frontend/src/components/layout/BackstoryRoutes.tsx b/frontend/src/components/layout/BackstoryRoutes.tsx
index 07958cf..61052cb 100644
--- a/frontend/src/components/layout/BackstoryRoutes.tsx
+++ b/frontend/src/components/layout/BackstoryRoutes.tsx
@@ -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;
diff --git a/frontend/src/components/layout/Header.tsx b/frontend/src/components/layout/Header.tsx
index 508261d..21bdbe5 100644
--- a/frontend/src/components/layout/Header.tsx
+++ b/frontend/src/components/layout/Header.tsx
@@ -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 = (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 = (props: HeaderProps) => {
navigationItems,
sessionId,
} = props;
-
- const { setSnack } = useAppState();
const theme = useTheme();
const location = useLocation();
@@ -151,52 +150,97 @@ const Header: React.FC = (props: HeaderProps) => {
const [userMenuAnchor, setUserMenuAnchor] = useState(null);
const userMenuOpen = Boolean(userMenuAnchor);
- // User menu items
- const userMenuItems = [
- {
- id: 'profile',
- label: 'Profile',
- icon: ,
- action: () => navigate(`/${user?.userType}/profile`)
- },
- {
- id: 'dashboard',
- label: 'Dashboard',
- icon: ,
- action: () => navigate(`/${user?.userType}/dashboard`)
- },
- {
- id: 'settings',
- label: 'Settings',
- icon: ,
- action: () => navigate(`/${user?.userType}/settings`)
- },
- {
- id: 'divider',
- label: '',
- icon: null,
- action: () => { }
- },
- {
- id: 'logout',
- label: 'Logout',
- icon: ,
- 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: , 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: ,
+ 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 = (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 = (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 = (props: HeaderProps) => {
// Render desktop navigation with dropdowns
const renderDesktopNavigation = () => {
return (
- :last-of-type": { marginRight: "auto"} }}>
- {navigationItems.map((item, index) => {
+
+ {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 (
-
+
handleDropdownOpen(e, item.id)}
endIcon={}
@@ -293,16 +328,15 @@ const Header: React.FC = (props: HeaderProps) => {
transformOrigin={{ vertical: 'top', horizontal: 'left' }}
TransitionComponent={Fade}
>
- {item.children?.map((child) => (
+ {item.children?.map((child: any) => (
))}
@@ -316,7 +350,6 @@ const Header: React.FC = (props: HeaderProps) => {
sx={{
backgroundColor: isActive ? 'action.selected' : 'transparent',
color: isActive ? 'secondary.main' : 'primary.contrastText',
- ...sx
}}
>
{item.icon && {item.icon}}
@@ -367,11 +400,11 @@ const Header: React.FC = (props: HeaderProps) => {
0 ? '0.875rem' : '1rem',
fontWeight: depth === 0 ? 500 : 400,
}
- }}
+ }}
/>
{hasChildren && (
@@ -383,7 +416,7 @@ const Header: React.FC = (props: HeaderProps) => {
{hasChildren && (
- {item.children?.map((child) => renderNavigationItem(child, depth + 1))}
+ {item.children?.map((child: any) => renderNavigationItem(child, depth + 1))}
)}
@@ -412,13 +445,13 @@ const Header: React.FC = (props: HeaderProps) => {
{userMenuItems.map((item, index) => (
- item.id === 'divider' ? (
+ item.group === 'divider' ? (
) : (
- handleUserMenuAction(item)} sx={{ alignContent: "center" }}>
+ handleUserMenuAction(item)}>
{item.icon && {item.icon}}
-
+
)
@@ -535,7 +568,7 @@ const Header: React.FC = (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 = (props: HeaderProps) => {
{ navigate('/docs/beta'); }}
+ onClick={() => { navigate('/docs/beta'); }}
/>
);
diff --git a/frontend/src/config/navigationConfig.tsx b/frontend/src/config/navigationConfig.tsx
index c923917..450e28c 100644
--- a/frontend/src/config/navigationConfig.tsx
+++ b/frontend/src/config/navigationConfig.tsx
@@ -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 = () => (Backstory);
+const ResumesPage = () => (Resumes);
+const QASetupPage = () => (Q&A Setup);
const SearchPage = () => (Search);
const SavedPage = () => (Saved);
const JobsPage = () => (Jobs);
@@ -51,8 +46,8 @@ const SettingsPage = () => (Settings, path: '/', component: , userTypes: ['guest', 'candidate', 'employer'], exact: true, },
- // { id: 'how-it-works', label: 'How It Works', path: '/how-it-works', icon: , component: , userTypes: ['guest', 'candidate', 'employer',], },
+ { id: 'home', label: , path: '/', component: , userTypes: ['guest', 'candidate', 'employer'], exact: true, },
+ { id: 'how-it-works', label: 'How It Works', path: '/how-it-works', icon: , component: , userTypes: ['guest', 'candidate', 'employer',], },
{ id: 'job-analysis', label: 'Job Analysis', path: '/job-analysis', icon: , component: , userTypes: ['guest', 'candidate', 'employer',], },
{ id: 'chat', label: 'Candidate Chat', path: '/chat', icon: , component: , userTypes: ['guest', 'candidate', 'employer',], }, {
id: 'candidate-menu', label: 'Tools', icon: , userTypes: ['candidate'], children: [
@@ -61,7 +56,9 @@ export const navigationConfig: NavigationConfig = {
{ id: 'candidate-docs', label: 'Documents', icon: , path: '/candidate/documents', component: , userTypes: ['candidate'] },
{ id: 'candidate-qa-setup', label: 'Q&A Setup', icon: , path: '/candidate/qa-setup', component: Candidate q&a setup page, userTypes: ['candidate'] },
{ id: 'candidate-analytics', label: 'Analytics', icon: , path: '/candidate/analytics', component: Candidate analytics page, userTypes: ['candidate'] },
- { id: 'candidate-job-analysis', label: 'Job Analysis', path: '/candidate/job-analysis', icon: , component: , userTypes: ['candidate'], },
+ { id: 'candidate-job-analysis', label: 'Job Analysis', path: '/candidate/job-analysis', icon: , component: , userTypes: ['candidate'], showInNavigation: false,
+ showInUserMenu: true,
+ userMenuGroup: 'profile',},
{ id: 'candidate-resumes', label: 'Resumes', icon: , path: '/candidate/resumes', component: Candidate resumes page, userTypes: ['candidate'] },
{ id: 'candidate-settings', label: 'Settings', path: '/candidate/settings', icon: , component: , userTypes: ['candidate'], },
],
@@ -78,22 +75,101 @@ export const navigationConfig: NavigationConfig = {
{ id: 'employer-settings', label: 'Settings', path: '/employer/settings', icon: , component: , userTypes: ['employer'], },
],
},
- // { id: 'find-candidate', label: 'Find a Candidate', path: '/find-a-candidate', icon: , component: , userTypes: ['guest', 'candidate', 'employer'], },
+ ],
+ },
{
- id: 'admin-menu',
- label: 'Admin',
- icon: ,
- userTypes: ['admin'],
- children: [
- { id: 'generate-candidate', label: 'Generate Candidate', path: '/admin/generate-candidate', icon: , component: , userTypes: ['admin'] },
- { id: 'docs', label: 'Docs', path: '/docs/*', icon: , component: , userTypes: ['admin'], },
- ],
+ id: 'global-tools',
+ label: 'Tools',
+ icon: ,
+ userTypes: ['candidate', 'employer'],
+ showInNavigation: true,
+ children: [
+ {
+ id: 'knowledge-explorer',
+ label: 'Knowledge Explorer',
+ path: '/knowledge-explorer',
+ icon: ,
+ component: ,
+ userTypes: ['candidate', 'employer'],
+ showInNavigation: true,
+ },
+ {
+ id: 'job-analysis',
+ label: 'Job Analysis',
+ path: '/job-analysis',
+ icon: ,
+ component: ,
+ userTypes: ['candidate', 'employer'],
+ showInNavigation: true,
+ },
+ {
+ id: 'generate-candidate',
+ label: 'Generate Candidate',
+ path: '/generate-candidate',
+ icon: ,
+ component: ,
+ userTypes: ['candidate', 'employer'],
+ showInNavigation: true,
+ },
+ ],
+ },
+ // User menu only items (not shown in main navigation)
+ {
+ id: 'user-profile',
+ label: 'Profile',
+ path: '/profile',
+ icon: ,
+ component: , // Replace with actual profile page
+ userTypes: ['candidate', 'employer'],
+ showInNavigation: false,
+ showInUserMenu: true,
+ userMenuGroup: 'profile',
+ },
+ {
+ id: 'account-settings',
+ label: 'Account Settings',
+ path: '/account/settings',
+ icon: ,
+ component: ,
+ userTypes: ['candidate', 'employer'],
+ showInNavigation: false,
+ showInUserMenu: true,
+ userMenuGroup: 'account',
+ },
+ {
+ id: 'billing',
+ label: 'Billing',
+ path: '/billing',
+ icon: ,
+ component: , // 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: , // 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: ,
userTypes: ['guest'],
+ showInNavigation: false,
},
{
id: 'login',
@@ -108,6 +185,7 @@ export const navigationConfig: NavigationConfig = {
path: '/login/*',
component: ,
userTypes: ['guest', 'candidate', 'employer'],
+ showInNavigation: false,
},
{
id: 'verify-email',
@@ -115,13 +193,15 @@ export const navigationConfig: NavigationConfig = {
path: '/login/verify-email',
component: ,
userTypes: ['guest', 'candidate', 'employer'],
+ showInNavigation: false,
},
{
- id: 'logout',
+ id: 'logout-page',
label: 'Logout',
path: '/logout',
component: ,
userTypes: ['candidate', 'employer'],
+ showInNavigation: false,
},
],
},
@@ -132,16 +212,19 @@ export const navigationConfig: NavigationConfig = {
path: '*',
component: ,
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;
};
\ No newline at end of file
diff --git a/frontend/src/types/navigation.ts b/frontend/src/types/navigation.ts
index fb57cbb..4fc5e9f 100644
--- a/frontend/src/types/navigation.ts
+++ b/frontend/src/types/navigation.ts
@@ -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 {