Tweaked JobViewer for mobile

This commit is contained in:
James Ketr 2025-06-12 07:49:21 -07:00
parent 85eac72750
commit 0bc9f74c7f
3 changed files with 412 additions and 169 deletions

View File

@ -171,7 +171,7 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
id: item.id, id: item.id,
label: item.label as string, label: item.label as string,
icon: item.icon || null, icon: item.icon || null,
action: () => item.path && navigate(item.path), action: () => item.path && navigate(item.path.replace(/:.*$/, '')),
group: 'profile' group: 'profile'
}); });
} }
@ -195,7 +195,7 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
id: item.id, id: item.id,
label: item.label as string, label: item.label as string,
icon: item.icon || null, icon: item.icon || null,
action: () => item.path && navigate(item.path), action: () => item.path && navigate(item.path.replace(/:.*$/, '')),
group: 'account' group: 'account'
}); });
} }
@ -219,7 +219,7 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
id: item.id, id: item.id,
label: item.label as string, label: item.label as string,
icon: item.icon || null, icon: item.icon || null,
action: () => item.path && navigate(item.path), action: () => item.path && navigate(item.path.replace(/:.*$/, '')),
group: 'admin' group: 'admin'
}); });
} }
@ -254,7 +254,7 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
id: item.id, id: item.id,
label: item.label as string, label: item.label as string,
icon: item.icon || null, icon: item.icon || null,
action: () => item.path && navigate(item.path), action: () => item.path && navigate(item.path.replace(/:.*$/, '')),
group: 'system' group: 'system'
}); });
} }
@ -267,7 +267,7 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
id: item.id, id: item.id,
label: item.label as string, label: item.label as string,
icon: item.icon || null, icon: item.icon || null,
action: () => item.path && navigate(item.path), action: () => item.path && navigate(item.path.replace(/:.*$/, '')),
group: 'other' group: 'other'
}); });
} }
@ -328,7 +328,7 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
// Navigation handlers // Navigation handlers
const handleNavigate = (path: string) => { const handleNavigate = (path: string) => {
navigate(path); navigate(path.replace(/:.*$/, ''));
setMobileOpen(false); setMobileOpen(false);
// Close all dropdowns // Close all dropdowns
setDropdownAnchors({}); setDropdownAnchors({});
@ -372,6 +372,7 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
onClick={() => child.path && handleNavigate(child.path)} onClick={() => child.path && handleNavigate(child.path)}
selected={isCurrentPath(child)} selected={isCurrentPath(child)}
disabled={!child.path} disabled={!child.path}
sx={{ display: 'flex', alignItems: 'center', "& *": { m: 0, p: 0 }, m: 0 }}
> >
{child.icon && <ListItemIcon>{child.icon}</ListItemIcon>} {child.icon && <ListItemIcon>{child.icon}</ListItemIcon>}
<ListItemText>{child.label}</ListItemText> <ListItemText>{child.label}</ListItemText>
@ -487,7 +488,7 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
item.group === 'divider' ? ( item.group === 'divider' ? (
<Divider key={`divider-${index}`} /> <Divider key={`divider-${index}`} />
) : ( ) : (
<ListItem key={item.id} disablePadding> <ListItem key={item.id}>
<ListItemButton onClick={() => handleUserMenuAction(item)}> <ListItemButton onClick={() => handleUserMenuAction(item)}>
{item.icon && <ListItemIcon sx={{ minWidth: 36 }}>{item.icon}</ListItemIcon>} {item.icon && <ListItemIcon sx={{ minWidth: 36 }}>{item.icon}</ListItemIcon>}
<ListItemText primary={item.label} /> <ListItemText primary={item.label} />

View File

@ -14,17 +14,24 @@ import {
MenuItem, MenuItem,
InputLabel, InputLabel,
Chip, Chip,
Divider,
IconButton, IconButton,
Tooltip Dialog,
AppBar,
Toolbar,
useMediaQuery,
useTheme,
Slide
} from '@mui/material'; } from '@mui/material';
import { import {
KeyboardArrowUp as ArrowUpIcon, KeyboardArrowUp as ArrowUpIcon,
KeyboardArrowDown as ArrowDownIcon, KeyboardArrowDown as ArrowDownIcon,
Business as BusinessIcon, Business as BusinessIcon,
Work as WorkIcon, Work as WorkIcon,
Schedule as ScheduleIcon Schedule as ScheduleIcon,
Close as CloseIcon,
ArrowBack as ArrowBackIcon
} from '@mui/icons-material'; } from '@mui/icons-material';
import { TransitionProps } from '@mui/material/transitions';
import { JobInfo } from 'components/ui/JobInfo'; import { JobInfo } from 'components/ui/JobInfo';
import { Job } from "types/types"; import { Job } from "types/types";
import { useAuth } from 'hooks/AuthContext'; import { useAuth } from 'hooks/AuthContext';
@ -38,8 +45,21 @@ interface JobViewerProps {
onSelect?: (job: Job) => void; onSelect?: (job: Job) => void;
} }
const Transition = React.forwardRef(function Transition(
props: TransitionProps & {
children: React.ReactElement;
},
ref: React.Ref<unknown>,
) {
return <Slide direction="up" ref={ref} {...props} />;
});
const JobViewer: React.FC<JobViewerProps> = ({ onSelect }) => { const JobViewer: React.FC<JobViewerProps> = ({ onSelect }) => {
const navigate = useNavigate(); const navigate = useNavigate();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const isSmall = useMediaQuery(theme.breakpoints.down('sm'));
const { apiClient } = useAuth(); const { apiClient } = useAuth();
const { selectedJob, setSelectedJob } = useSelectedJob(); const { selectedJob, setSelectedJob } = useSelectedJob();
const { setSnack } = useAppState(); const { setSnack } = useAppState();
@ -47,6 +67,7 @@ const JobViewer: React.FC<JobViewerProps> = ({ onSelect }) => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [sortField, setSortField] = useState<SortField>('updatedAt'); const [sortField, setSortField] = useState<SortField>('updatedAt');
const [sortOrder, setSortOrder] = useState<SortOrder>('desc'); const [sortOrder, setSortOrder] = useState<SortOrder>('desc');
const [mobileDialogOpen, setMobileDialogOpen] = useState(false);
const { jobId } = useParams<{ jobId?: string }>(); const { jobId } = useParams<{ jobId?: string }>();
useEffect(() => { useEffect(() => {
@ -56,6 +77,7 @@ const JobViewer: React.FC<JobViewerProps> = ({ onSelect }) => {
const results = await apiClient.getJobs(); const results = await apiClient.getJobs();
const jobsData: Job[] = results.data || []; const jobsData: Job[] = results.data || [];
setJobs(jobsData); setJobs(jobsData);
if (jobId) { if (jobId) {
const job = jobsData.find(j => j.id === jobId); const job = jobsData.find(j => j.id === jobId);
if (job) { if (job) {
@ -125,7 +147,15 @@ const JobViewer: React.FC<JobViewerProps> = ({ onSelect }) => {
const handleJobSelect = (job: Job) => { const handleJobSelect = (job: Job) => {
setSelectedJob(job); setSelectedJob(job);
onSelect?.(job); onSelect?.(job);
navigate(`/candidate/jobs/${job.id}`); if (isMobile) {
setMobileDialogOpen(true);
} else {
navigate(`/candidate/jobs/${job.id}`);
}
};
const handleMobileDialogClose = () => {
setMobileDialogOpen(false);
}; };
const sortedJobs = sortJobs(jobs, sortField, sortOrder); const sortedJobs = sortJobs(jobs, sortField, sortOrder);
@ -135,9 +165,8 @@ const JobViewer: React.FC<JobViewerProps> = ({ onSelect }) => {
return new Intl.DateTimeFormat('en-US', { return new Intl.DateTimeFormat('en-US', {
month: 'short', month: 'short',
day: 'numeric', day: 'numeric',
year: 'numeric', ...(isMobile ? {} : { year: 'numeric' }),
hour: '2-digit', ...(isSmall ? {} : { hour: '2-digit', minute: '2-digit' })
minute: '2-digit'
}).format(date); }).format(date);
}; };
@ -146,170 +175,363 @@ const JobViewer: React.FC<JobViewerProps> = ({ onSelect }) => {
return sortOrder === 'asc' ? <ArrowUpIcon fontSize="small" /> : <ArrowDownIcon fontSize="small" />; return sortOrder === 'asc' ? <ArrowUpIcon fontSize="small" /> : <ArrowDownIcon fontSize="small" />;
}; };
return ( const JobList = () => (
<Box sx={{ display: 'flex', height: '100%', gap: 2, p: 2, position: 'relative' }}> <Paper
{/* Left Panel - Job List */} elevation={isMobile ? 0 : 1}
<Paper sx={{ width: '50%', display: 'flex', flexDirection: 'column' }}> sx={{
<Box sx={{ p: 2, borderBottom: 1, borderColor: 'divider' }}> display: 'flex',
<Typography variant="h6" gutterBottom> flexDirection: 'column',
Jobs ({jobs.length}) ...(isMobile ? {
</Typography> width: '100%',
boxShadow: 'none',
backgroundColor: 'transparent'
} : { width: '50%' })
}}
>
<Box sx={{
p: isMobile ? 0.5 : 1,
borderBottom: 1,
borderColor: 'divider',
backgroundColor: isMobile ? 'background.paper' : 'inherit'
}}>
<Typography
variant={isSmall ? "subtitle2" : isMobile ? "subtitle1" : "h6"}
gutterBottom
sx={{ mb: isMobile ? 0.5 : 1, fontWeight: 600 }}
>
Jobs ({jobs.length})
</Typography>
<FormControl size="small" sx={{ minWidth: 200 }}> <FormControl size="small" sx={{ minWidth: isSmall ? 120 : isMobile ? 150 : 200 }}>
<InputLabel>Sort by</InputLabel> <InputLabel>Sort by</InputLabel>
<Select <Select
value={`${sortField}-${sortOrder}`} value={`${sortField}-${sortOrder}`}
label="Sort by" label="Sort by"
onChange={(e) => { onChange={(e) => {
const [field, order] = e.target.value.split('-') as [SortField, SortOrder]; const [field, order] = e.target.value.split('-') as [SortField, SortOrder];
setSortField(field); setSortField(field);
setSortOrder(order); setSortOrder(order);
}} }}
> >
<MenuItem value="updatedAt-desc">Updated (Newest)</MenuItem> <MenuItem value="updatedAt-desc">Updated (Newest)</MenuItem>
<MenuItem value="updatedAt-asc">Updated (Oldest)</MenuItem> <MenuItem value="updatedAt-asc">Updated (Oldest)</MenuItem>
<MenuItem value="createdAt-desc">Created (Newest)</MenuItem> <MenuItem value="createdAt-desc">Created (Newest)</MenuItem>
<MenuItem value="createdAt-asc">Created (Oldest)</MenuItem> <MenuItem value="createdAt-asc">Created (Oldest)</MenuItem>
<MenuItem value="company-asc">Company (A-Z)</MenuItem> <MenuItem value="company-asc">Company (A-Z)</MenuItem>
<MenuItem value="company-desc">Company (Z-A)</MenuItem> <MenuItem value="company-desc">Company (Z-A)</MenuItem>
<MenuItem value="title-asc">Title (A-Z)</MenuItem> <MenuItem value="title-asc">Title (A-Z)</MenuItem>
<MenuItem value="title-desc">Title (Z-A)</MenuItem> <MenuItem value="title-desc">Title (Z-A)</MenuItem>
</Select> </Select>
</FormControl> </FormControl>
</Box> </Box>
<TableContainer sx={{ flex: 1, overflow: 'auto' }}> <TableContainer sx={{
<Table stickyHeader size="small"> flex: 1,
<TableHead> overflow: 'auto',
<TableRow> '& .MuiTable-root': {
tableLayout: isMobile ? 'fixed' : 'auto'
}
}}>
<Table stickyHeader size="small">
<TableHead>
<TableRow>
<TableCell
sx={{
cursor: 'pointer',
userSelect: 'none',
py: isMobile ? 0.25 : 0.5,
px: isMobile ? 0.5 : 1,
width: isMobile ? '25%' : 'auto',
backgroundColor: 'background.paper'
}}
onClick={() => handleSort('company')}
>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<BusinessIcon fontSize={isMobile ? "small" : "medium"} />
<Typography variant="caption" fontWeight="bold" noWrap>
{isSmall ? 'Co.' : isMobile ? 'Company' : 'Company'}
</Typography>
{getSortIcon('company')}
</Box>
</TableCell>
<TableCell
sx={{
cursor: 'pointer',
userSelect: 'none',
py: isMobile ? 0.25 : 0.5,
px: isMobile ? 0.5 : 1,
width: isMobile ? '45%' : 'auto',
backgroundColor: 'background.paper'
}}
onClick={() => handleSort('title')}
>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<WorkIcon fontSize={isMobile ? "small" : "medium"} />
<Typography variant="caption" fontWeight="bold" noWrap>Title</Typography>
{getSortIcon('title')}
</Box>
</TableCell>
{!isMobile && (
<TableCell <TableCell
sx={{ cursor: 'pointer', userSelect: 'none' }} sx={{
onClick={() => handleSort('company')} cursor: 'pointer',
> userSelect: 'none',
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}> py: 0.5,
<BusinessIcon fontSize="small" /> px: 1,
Company backgroundColor: 'background.paper'
{getSortIcon('company')} }}
</Box>
</TableCell>
<TableCell
sx={{ cursor: 'pointer', userSelect: 'none' }}
onClick={() => handleSort('title')}
>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<WorkIcon fontSize="small" />
Title
{getSortIcon('title')}
</Box>
</TableCell>
<TableCell
sx={{ cursor: 'pointer', userSelect: 'none' }}
onClick={() => handleSort('updatedAt')} onClick={() => handleSort('updatedAt')}
> >
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}> <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<ScheduleIcon fontSize="small" /> <ScheduleIcon fontSize="medium" />
Updated <Typography variant="caption" fontWeight="bold">Updated</Typography>
{getSortIcon('updatedAt')} {getSortIcon('updatedAt')}
</Box> </Box>
</TableCell> </TableCell>
<TableCell>Status</TableCell> )}
</TableRow> <TableCell sx={{
</TableHead> py: isMobile ? 0.25 : 0.5,
<TableBody> px: isMobile ? 0.5 : 1,
{sortedJobs.map((job) => ( width: isMobile ? '30%' : 'auto',
<TableRow backgroundColor: 'background.paper'
key={job.id} }}>
hover <Typography variant="caption" fontWeight="bold" noWrap>
selected={selectedJob?.id === job.id} {isMobile ? 'Status' : 'Status'}
onClick={() => handleJobSelect(job)} </Typography>
sx={{ </TableCell>
cursor: 'pointer', </TableRow>
'&.Mui-selected': { </TableHead>
backgroundColor: 'action.selected', <TableBody>
} {sortedJobs.map((job) => (
}} <TableRow
> key={job.id}
<TableCell> hover
<Typography variant="body2" fontWeight="medium"> selected={selectedJob?.id === job.id}
{job.company || 'N/A'} onClick={() => handleJobSelect(job)}
sx={{
cursor: 'pointer',
height: isMobile ? 48 : 'auto',
'&.Mui-selected': {
backgroundColor: 'action.selected',
},
'&:hover': {
backgroundColor: 'action.hover',
}
}}
>
<TableCell sx={{
py: isMobile ? 0.25 : 0.5,
px: isMobile ? 0.5 : 1,
overflow: 'hidden'
}}>
<Typography
variant={isMobile ? "caption" : "body2"}
fontWeight="medium"
noWrap
sx={{ fontSize: isMobile ? '0.75rem' : '0.875rem' }}
>
{job.company || 'N/A'}
</Typography>
{!isMobile && job.details?.location && (
<Typography
variant="caption"
color="text.secondary"
noWrap
sx={{ display: 'block', fontSize: '0.7rem' }}
>
{job.details.location.city}, {job.details.location.state || job.details.location.country}
</Typography> </Typography>
{job.details?.location && ( )}
<Typography variant="caption" color="text.secondary"> </TableCell>
{job.details.location.city}, {job.details.location.state || job.details.location.country} <TableCell sx={{
</Typography> py: isMobile ? 0.25 : 0.5,
)} px: isMobile ? 0.5 : 1,
</TableCell> overflow: 'hidden'
<TableCell> }}>
<Typography variant="body2" fontWeight="medium"> <Typography
{job.title || 'N/A'} variant={isMobile ? "caption" : "body2"}
</Typography> fontWeight="medium"
{job.details?.employmentType && ( noWrap
<Chip sx={{ fontSize: isMobile ? '0.75rem' : '0.875rem' }}
label={job.details.employmentType} >
size="small" {job.title || 'N/A'}
variant="outlined" </Typography>
sx={{ mt: 0.5, fontSize: '0.7rem', height: 20 }} {!isMobile && job.details?.employmentType && (
/> <Chip
)} label={job.details.employmentType}
</TableCell> size="small"
<TableCell> variant="outlined"
<Typography variant="body2"> sx={{
mt: 0.25,
fontSize: '0.6rem',
height: 16,
'& .MuiChip-label': { px: 0.5 }
}}
/>
)}
</TableCell>
{!isMobile && (
<TableCell sx={{ py: 0.5, px: 1 }}>
<Typography variant="body2" sx={{ fontSize: '0.8rem' }}>
{formatDate(job.updatedAt)} {formatDate(job.updatedAt)}
</Typography> </Typography>
{job.createdAt && ( {job.createdAt && (
<Typography variant="caption" color="text.secondary"> <Typography
variant="caption"
color="text.secondary"
sx={{ display: 'block', fontSize: '0.7rem' }}
>
Created: {formatDate(job.createdAt)} Created: {formatDate(job.createdAt)}
</Typography> </Typography>
)} )}
</TableCell> </TableCell>
<TableCell> )}
<Chip <TableCell sx={{
label={job.details?.isActive ? "Active" : "Inactive"} py: isMobile ? 0.25 : 0.5,
color={job.details?.isActive ? "success" : "default"} px: isMobile ? 0.5 : 1,
size="small" overflow: 'hidden'
variant="outlined" }}>
/> <Chip
</TableCell> label={job.details?.isActive ? "Active" : "Inactive"}
</TableRow> color={job.details?.isActive ? "success" : "default"}
))} size="small"
</TableBody> variant="outlined"
</Table> sx={{
</TableContainer> fontSize: isMobile ? '0.65rem' : '0.7rem',
</Paper> height: isMobile ? 20 : 22,
'& .MuiChip-label': {
px: isMobile ? 0.5 : 0.75,
py: 0
}
}}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Paper>
);
{/* Right Panel - Job Details */} const JobDetails = ({ inDialog = false }: { inDialog?: boolean }) => (
<Paper sx={{ width: '50%', display: 'flex', flexDirection: 'column' }}> <Box sx={{
<Box sx={{ p: 2, borderBottom: 1, borderColor: 'divider' }}> flex: 1,
<Typography variant="h6"> overflow: 'auto',
p: inDialog ? 1.5 : 0.75,
height: inDialog ? '100%' : 'auto'
}}>
{selectedJob ? (
<JobInfo
job={selectedJob}
variant="all"
sx={{
border: 'none',
boxShadow: 'none',
backgroundColor: 'transparent',
'& .MuiTypography-h6': {
fontSize: inDialog ? '1.25rem' : '1.1rem'
}
}}
/>
) : (
<Box sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100%',
color: 'text.secondary',
textAlign: 'center',
p: 2
}}>
<Typography variant="body2">
Select a job to view details
</Typography>
</Box>
)}
</Box>
);
if (isMobile) {
return (
<Box sx={{
height: '100%',
p: 0.5,
backgroundColor: 'background.default'
}}>
<JobList />
<Dialog
fullScreen
open={mobileDialogOpen}
onClose={handleMobileDialogClose}
TransitionComponent={Transition}
TransitionProps={{ timeout: 300 }}
>
<AppBar sx={{ position: 'relative', elevation: 1 }}>
<Toolbar variant="dense" sx={{ minHeight: 48 }}>
<IconButton
edge="start"
color="inherit"
onClick={handleMobileDialogClose}
aria-label="back"
size="small"
>
<ArrowBackIcon />
</IconButton>
<Box sx={{ ml: 1, flex: 1, minWidth: 0 }}>
<Typography
variant="h6"
component="div"
noWrap
sx={{ fontSize: '1rem' }}
>
{selectedJob?.title}
</Typography>
<Typography
variant="caption"
component="div"
sx={{ color: 'rgba(255, 255, 255, 0.7)' }}
noWrap
>
{selectedJob?.company}
</Typography>
</Box>
</Toolbar>
</AppBar>
<JobDetails inDialog />
</Dialog>
</Box>
);
}
return (
<Box sx={{
display: 'flex',
height: '100%',
gap: 0.75,
p: 0.75,
backgroundColor: 'background.default'
}}>
<JobList />
<Paper sx={{
width: '50%',
display: 'flex',
flexDirection: 'column',
elevation: 1
}}>
<Box sx={{
p: 0.75,
borderBottom: 1,
borderColor: 'divider',
backgroundColor: 'background.paper'
}}>
<Typography variant="h6" sx={{ fontSize: '1.1rem', fontWeight: 600 }}>
Job Details Job Details
</Typography> </Typography>
</Box> </Box>
<JobDetails />
<Box sx={{ flex: 1, overflow: 'auto', p: 2 }}>
{selectedJob ? (
<JobInfo
job={selectedJob}
variant="all"
sx={{
border: 'none',
boxShadow: 'none',
backgroundColor: 'transparent'
}}
/>
) : (
<Box sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100%',
color: 'text.secondary'
}}>
<Typography variant="body1">
Select a job to view details
</Typography>
</Box>
)}
</Box>
</Paper> </Paper>
</Box> </Box>
); );

View File

@ -44,6 +44,7 @@ import { DocumentManager } from "components/DocumentManager";
import { useAuth } from "hooks/AuthContext"; import { useAuth } from "hooks/AuthContext";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { JobViewer } from "components/ui/JobViewer"; import { JobViewer } from "components/ui/JobViewer";
import { CandidatePicker } from "components/ui/CandidatePicker";
// Beta page components for placeholder routes // Beta page components for placeholder routes
const BackstoryPage = () => ( const BackstoryPage = () => (
@ -129,6 +130,36 @@ export const navigationConfig: NavigationConfig = {
component: <CandidateChatPage />, component: <CandidateChatPage />,
userTypes: ["guest", "candidate", "employer"], 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"],
// },
{
id: "explore-jobs",
label: "Jobs",
path: "/candidate/jobs/:jobId?",
icon: <SearchIcon />,
component: (
<JobViewer />
),
userTypes: ["candidate", "guest", "employer"],
},
],
showInNavigation: true,
},
{ {
id: "generate-candidate", id: "generate-candidate",
label: "Generate Candidate", label: "Generate Candidate",
@ -163,17 +194,6 @@ export const navigationConfig: NavigationConfig = {
showInNavigation: false, showInNavigation: false,
showInUserMenu: true, showInUserMenu: true,
}, },
{
id: "candidate-jobs",
label: "Jobs",
icon: <WorkIcon />,
path: "/candidate/jobs/:jobId?",
component: <JobViewer />,
userTypes: ["candidate", "guest", "employer"],
userMenuGroup: "profile",
showInNavigation: false,
showInUserMenu: true,
},
{ {
id: "candidate-docs", id: "candidate-docs",
label: "Content", label: "Content",