Fixed tab errors

This commit is contained in:
James Ketr 2025-06-04 11:11:42 -07:00
parent 4f7b2f3e6a
commit efef926e45
4 changed files with 310 additions and 191 deletions

View File

@ -23,52 +23,51 @@ import { AuthProvider, useAuth, ProtectedRoute } from 'hooks/AuthContext';
import { useSelectedCandidate } from 'hooks/GlobalContext';
type NavigationLinkType = {
name: string;
label: ReactElement<any> | string;
path: string;
icon?: ReactElement<any>;
label?: ReactElement<any>;
icon?: ReactElement<any>;
};
const DefaultNavItems: NavigationLinkType[] = [
{ name: 'Find a Candidate', path: '/find-a-candidate', icon: <InfoIcon /> },
{ name: 'Docs', path: '/docs', icon: <InfoIcon /> },
// { name: 'How It Works', path: '/how-it-works', icon: <InfoIcon/> },
// { name: 'For Candidates', path: '/for-candidates', icon: <PersonIcon/> },
// { name: 'For Employers', path: '/for-employers', icon: <BusinessIcon/> },
// { name: 'Pricing', path: '/pricing', icon: <AttachMoneyIcon/> },
{ label: 'Find a Candidate', path: '/find-a-candidate', icon: <InfoIcon /> },
{ label: 'Docs', path: '/docs', icon: <InfoIcon /> },
// { label: 'How It Works', path: '/how-it-works', icon: <InfoIcon/> },
// { label: 'For Candidates', path: '/for-candidates', icon: <PersonIcon/> },
// { label: 'For Employers', path: '/for-employers', icon: <BusinessIcon/> },
// { label: 'Pricing', path: '/pricing', icon: <AttachMoneyIcon/> },
];
const ViewerNavItems: NavigationLinkType[] = [
{ name: 'Chat', path: '/chat', icon: <ChatIcon /> },
{ label: 'Chat', path: '/chat', icon: <ChatIcon /> },
];
const CandidateNavItems : NavigationLinkType[]= [
{ name: 'Chat', path: '/chat', icon: <ChatIcon /> },
{ name: 'Job Analysis', path: '/candidate/job-analysis', icon: <WorkIcon /> },
{ name: 'Resume Builder', path: '/candidate/resume-builder', icon: <WorkIcon /> },
// { name: 'Knowledge Explorer', path: '/candidate/knowledge-explorer', icon: <WorkIcon /> },
// { name: 'Dashboard', icon: <DashboardIcon />, path: '/candidate/dashboard' },
// { name: 'Profile', icon: <PersonIcon />, path: '/candidate/profile' },
// { name: 'Backstory', icon: <HistoryIcon />, path: '/candidate/backstory' },
// { name: 'Resumes', icon: <DescriptionIcon />, path: '/candidate/resumes' },
// { name: 'Q&A Setup', icon: <QuestionAnswerIcon />, path: '/candidate/qa-setup' },
// { name: 'Analytics', icon: <BarChartIcon />, path: '/candidate/analytics' },
// { name: 'Settings', icon: <SettingsIcon />, path: '/candidate/settings' },
{ label: 'Chat', path: '/chat', icon: <ChatIcon /> },
{ label: 'Job Analysis', path: '/candidate/job-analysis', icon: <WorkIcon /> },
{ label: 'Resume Builder', path: '/candidate/resume-builder', icon: <WorkIcon /> },
// { label: 'Knowledge Explorer', path: '/candidate/knowledge-explorer', icon: <WorkIcon /> },
// { label: 'Dashboard', icon: <DashboardIcon />, path: '/candidate/dashboard' },
// { label: 'Profile', icon: <PersonIcon />, path: '/candidate/profile' },
// { label: 'Backstory', icon: <HistoryIcon />, path: '/candidate/backstory' },
// { label: 'Resumes', icon: <DescriptionIcon />, path: '/candidate/resumes' },
// { label: 'Q&A Setup', icon: <QuestionAnswerIcon />, path: '/candidate/qa-setup' },
// { label: 'Analytics', icon: <BarChartIcon />, path: '/candidate/analytics' },
// { label: 'Settings', icon: <SettingsIcon />, path: '/candidate/settings' },
];
const EmployerNavItems: NavigationLinkType[] = [
{ name: 'Chat', path: '/chat', icon: <ChatIcon /> },
{ name: 'Job Analysis', path: '/employer/job-analysis', icon: <WorkIcon /> },
{ name: 'Resume Builder', path: '/employer/resume-builder', icon: <WorkIcon /> },
{ name: 'Knowledge Explorer', path: '/employer/knowledge-explorer', icon: <WorkIcon /> },
{ name: 'Find a Candidate', path: '/find-a-candidate', icon: <InfoIcon /> },
// { name: 'Dashboard', icon: <DashboardIcon />, path: '/employer/dashboard' },
// { name: 'Search', icon: <SearchIcon />, path: '/employer/search' },
// { name: 'Saved', icon: <BookmarkIcon />, path: '/employer/saved' },
// { name: 'Jobs', icon: <WorkIcon />, path: '/employer/jobs' },
// { name: 'Company', icon: <BusinessIcon />, path: '/employer/company' },
// { name: 'Analytics', icon: <BarChartIcon />, path: '/employer/analytics' },
// { name: 'Settings', icon: <SettingsIcon />, path: '/employer/settings' },
{ label: 'Chat', path: '/chat', icon: <ChatIcon /> },
{ label: 'Job Analysis', path: '/employer/job-analysis', icon: <WorkIcon /> },
{ label: 'Resume Builder', path: '/employer/resume-builder', icon: <WorkIcon /> },
{ label: 'Knowledge Explorer', path: '/employer/knowledge-explorer', icon: <WorkIcon /> },
{ label: 'Find a Candidate', path: '/find-a-candidate', icon: <InfoIcon /> },
// { label: 'Dashboard', icon: <DashboardIcon />, path: '/employer/dashboard' },
// { label: 'Search', icon: <SearchIcon />, path: '/employer/search' },
// { label: 'Saved', icon: <BookmarkIcon />, path: '/employer/saved' },
// { label: 'Jobs', icon: <WorkIcon />, path: '/employer/jobs' },
// { label: 'Company', icon: <BusinessIcon />, path: '/employer/company' },
// { label: 'Analytics', icon: <BarChartIcon />, path: '/employer/analytics' },
// { label: 'Settings', icon: <SettingsIcon />, path: '/employer/settings' },
];
// Navigation links based on user type

View File

@ -170,7 +170,7 @@ interface HeaderProps {
navigationLinks: NavigationLinkType[];
currentPath: string;
sessionId?: string | null;
setSnack: SetSnackType,
setSnack: SetSnackType;
}
const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
@ -190,13 +190,13 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
const name = (user?.firstName || user?.email || '');
const navLinks : NavigationLinkType[] = [
{name: "Home", path: "/", label: <BackstoryLogo/>},
const mainNavSections: NavigationLinkType[] = [
{ path: '/', label: <BackstoryLogo /> },
...navigationLinks
];
// State for page navigation
const [ currentTab, setCurrentTab ] = useState<string>("/");
// State for page navigation - only for main navigation
const [currentTab, setCurrentTab] = useState<string | false>("/");
const [userMenuTab, setUserMenuTab] = useState<string>("");
// State for mobile drawer
@ -206,6 +206,26 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
const [userMenuAnchor, setUserMenuAnchor] = useState<null | HTMLElement>(null);
const userMenuOpen = Boolean(userMenuAnchor);
// Helper function to determine which action page we're in
const getTailSection = (pathname: string): string | false => {
// Handle home page
if (pathname === '/') return '/';
// Split path and check against main sections
const segments = pathname.split('/').filter(Boolean);
if (segments.length === 0) return '/';
const lastSegment = `/${segments[segments.length - 1]}`;
// Check if this matches any of our main navigation sections
const matchingSection = mainNavSections.find(section =>
section.path === lastSegment ||
(section.path !== '/' && pathname.endsWith(section.path))
);
return matchingSection ? matchingSection.path : false; // Return false for routes that shouldn't show in main nav
};
// User menu items
const userMenuItems = [
{
@ -244,15 +264,13 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
];
useEffect(() => {
const parts = location.pathname.split('/');
let tab = '/';
if (parts.length > 1) {
tab = `/${parts[1]}`;
const mainSection = getTailSection(location.pathname);
// Only update if the section is different from current tab
if (mainSection !== currentTab) {
setCurrentTab(mainSection); // mainSection is either a string or false
}
if (tab !== currentTab) {
setCurrentTab(tab);
}
}, [location, currentTab]);
}, [location.pathname, currentTab]);
const handleUserMenuOpen = (event: React.MouseEvent<HTMLElement>) => {
setUserMenuAnchor(event.currentTarget);
@ -274,28 +292,34 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
setMobileOpen(!mobileOpen);
};
const handleTabChange = (event: React.SyntheticEvent, newValue: string | false) => {
if (newValue !== false) {
setCurrentTab(newValue);
navigate(newValue);
}
};
// Render desktop navigation links
const renderNavLinks = () => {
return (
<Tabs value={currentTab} onChange={(e, newValue) => setCurrentTab(newValue)}
<Tabs
value={currentTab}
onChange={handleTabChange}
indicatorColor="secondary"
textColor="inherit"
variant="fullWidth"
allowScrollButtonsMobile
aria-label="Backstory navigation"
>
{navLinks.map((link) => (
<Tab
sx={{
minWidth: link.path === '/' ? "max-content" : "auto",
}}
key={link.name}
value={link.path}
label={link.label ? link.label : link.name}
onClick={() => {
navigate(link.path);
}}
/>
>
{mainNavSections.map((section) => (
<Tab
sx={{
minWidth: section.path === '/' ? "max-content" : "auto",
}}
key={section.path}
value={section.path}
label={section.label}
/>
))}
</Tabs>
);
@ -308,33 +332,21 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
<MobileMenuTabs
orientation="vertical"
value={currentTab}
onChange={(e, newValue) => setCurrentTab(newValue)}
onChange={handleTabChange}
>
{navLinks.map((link) => (
{mainNavSections.map((section) => (
<Tab
key={link.name}
value={link.path}
key={section.path || '/'}
value={section.path}
label={
<MenuItemBox>
{link.path === '/' ? (
<Avatar
sx={{ width: 20, height: 20 }}
variant="rounded"
alt="Backstory logo"
src="/logo192.png"
/>
) : (
link.icon && link.icon
)}
<Typography variant="body2">
{link.path === '/' ? 'Backstory' : (link.label && typeof link.label === 'object' ? link.name : (link.label || link.name))}
</Typography>
{section.label}
</MenuItemBox>
}
onClick={(e) => {
handleDrawerToggle();
setCurrentTab(link.path);
navigate(link.path);
setCurrentTab(section.path);
navigate(section.path);
}}
/>
))}
@ -458,8 +470,6 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
>
<Container maxWidth="xl">
<Toolbar disableGutters>
{/* Logo Section */}
{/* Navigation Links - Desktop */}
<NavLinksContainer>
{renderNavLinks()}
@ -482,22 +492,22 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
</IconButton>
</Tooltip>
{sessionId && <CopyBubble
tooltip="Copy link"
color="inherit"
aria-label="copy link"
edge="end"
sx={{
width: 36,
height: 36,
opacity: 1,
bgcolor: 'inherit',
'&:hover': { bgcolor: 'action.hover', opacity: 1 },
}}
content={`${window.location.origin}${window.location.pathname}?id=${sessionId}`}
onClick={() => { navigate(`${window.location.pathname}?id=${sessionId}`); setSnack("Link copied!") }}
size="large"
/>}
{sessionId && <CopyBubble
tooltip="Copy link"
color="inherit"
aria-label="copy link"
edge="end"
sx={{
width: 36,
height: 36,
opacity: 1,
bgcolor: 'inherit',
'&:hover': { bgcolor: 'action.hover', opacity: 1 },
}}
content={`${window.location.origin}${window.location.pathname}?id=${sessionId}`}
onClick={() => { navigate(`${window.location.pathname}?id=${sessionId}`); setSnack("Link copied!") }}
size="large"
/>}
</UserActionsContainer>
{/* Mobile Navigation Drawer */}
@ -507,18 +517,16 @@ const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile
keepMounted: true,
}}
>
{renderDrawerContent()}
</MobileDrawer>
</Toolbar>
</Container>
<Beta sx={{ left: "-90px", "& .mobile": { right: "-72px" } }} onClick={() => { navigate('/docs/beta'); }} />
<Beta sx={{ left: "-90px", "& .mobile": { right: "-72px" } }} onClick={() => { navigate('/docs/beta'); }} />
</StyledAppBar>
);
};
export {
Header
};
export { Header };

View File

@ -1,19 +1,66 @@
import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
import * as Types from 'types/types';
// Assuming you're using React Router
import { useLocation, useNavigate } from 'react-router-dom';
import { useAuth } from 'hooks/AuthContext';
// ============================
// Local Storage Keys
// Storage Keys
// ============================
const STORAGE_KEYS = {
SELECTED_CANDIDATE_ID: 'selectedCandidateId',
SELECTED_JOB_ID: 'selectedJobId',
SELECTED_EMPLOYER_ID: 'selectedEmployerId'
SELECTED_EMPLOYER_ID: 'selectedEmployerId',
LAST_ROUTE: 'lastVisitedRoute',
ROUTE_STATE: 'routeState',
ACTIVE_TAB: 'activeTab',
APPLIED_FILTERS: 'appliedFilters',
SIDEBAR_COLLAPSED: 'sidebarCollapsed'
} as const;
// ============================
// Local Storage Utilities
// Route State Interface
// ============================
interface RouteState {
lastRoute: string | null;
activeTab: string | null;
appliedFilters: Record<string, any>;
sidebarCollapsed: boolean;
}
// ============================
// Enhanced App State Interface
// ============================
export interface AppState {
selectedCandidate: Types.Candidate | null;
selectedJob: Types.Job | null;
selectedEmployer: Types.Employer | null;
routeState: RouteState;
isInitializing: boolean;
}
export interface AppStateActions {
setSelectedCandidate: (candidate: Types.Candidate | null) => void;
setSelectedJob: (job: Types.Job | null) => void;
setSelectedEmployer: (employer: Types.Employer | null) => void;
clearSelections: () => void;
// Route management
saveCurrentRoute: () => void;
restoreLastRoute: () => void;
setActiveTab: (tab: string) => void;
setFilters: (filters: Record<string, any>) => void;
setSidebarCollapsed: (collapsed: boolean) => void;
clearRouteState: () => void;
}
export type AppStateContextType = AppState & AppStateActions;
// ============================
// Storage Utilities
// ============================
function getStoredId(key: string): string | null {
@ -37,42 +84,62 @@ function setStoredId(key: string, id: string | null): void {
}
}
// ============================
// App State Interface
// ============================
export interface AppState {
selectedCandidate: Types.Candidate | null;
selectedJob: Types.Job | null;
selectedEmployer: Types.Employer | null;
isInitializing: boolean;
// Add more global state as needed:
// currentView: string;
// filters: Record<string, any>;
// searchQuery: string;
function getStoredObject<T>(key: string, defaultValue: T): T {
try {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : defaultValue;
} catch (error) {
console.warn(`Failed to read ${key} from localStorage:`, error);
return defaultValue;
}
}
export interface AppStateActions {
setSelectedCandidate: (candidate: Types.Candidate | null) => void;
setSelectedJob: (job: Types.Job | null) => void;
setSelectedEmployer: (employer: Types.Employer | null) => void;
clearSelections: () => void;
// Future actions can be added here
function setStoredObject(key: string, value: any): void {
try {
localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.warn(`Failed to write ${key} to localStorage:`, error);
}
}
export type AppStateContextType = AppState & AppStateActions;
// ============================
// Route State Management
// ============================
function getInitialRouteState(): RouteState {
return {
lastRoute: getStoredId(STORAGE_KEYS.LAST_ROUTE),
activeTab: getStoredId(STORAGE_KEYS.ACTIVE_TAB),
appliedFilters: getStoredObject(STORAGE_KEYS.APPLIED_FILTERS, {}),
sidebarCollapsed: getStoredObject(STORAGE_KEYS.SIDEBAR_COLLAPSED, false)
};
}
function persistRouteState(routeState: RouteState): void {
setStoredId(STORAGE_KEYS.LAST_ROUTE, routeState.lastRoute);
setStoredId(STORAGE_KEYS.ACTIVE_TAB, routeState.activeTab);
setStoredObject(STORAGE_KEYS.APPLIED_FILTERS, routeState.appliedFilters);
setStoredObject(STORAGE_KEYS.SIDEBAR_COLLAPSED, routeState.sidebarCollapsed);
}
// ============================
// App State Hook
// Enhanced App State Hook
// ============================
export function useAppStateLogic(): AppStateContextType {
const location = useLocation();
const navigate = useNavigate();
const { apiClient } = useAuth();
// Entity state
const [selectedCandidate, setSelectedCandidateState] = useState<Types.Candidate | null>(null);
const [selectedJob, setSelectedJobState] = useState<Types.Job | null>(null);
const [selectedEmployer, setSelectedEmployerState] = useState<Types.Employer | null>(null);
const [isInitializing, setIsInitializing] = useState<boolean>(true);
// Route state
const [routeState, setRouteStateState] = useState<RouteState>(getInitialRouteState);
// ============================
// Initialization Effect
// ============================
@ -82,7 +149,7 @@ export function useAppStateLogic(): AppStateContextType {
setIsInitializing(true);
try {
// Get stored IDs
// Get stored entity IDs
const candidateId = getStoredId(STORAGE_KEYS.SELECTED_CANDIDATE_ID);
const jobId = getStoredId(STORAGE_KEYS.SELECTED_JOB_ID);
const employerId = getStoredId(STORAGE_KEYS.SELECTED_EMPLOYER_ID);
@ -94,13 +161,11 @@ export function useAppStateLogic(): AppStateContextType {
promises.push(
(async () => {
try {
// Assuming apiClient.getCandidate exists
const candidate = await apiClient.getCandidate(candidateId);
if (candidate) {
setSelectedCandidateState(candidate);
console.log('Restored candidate from storage:', candidate);
} else {
// Data not available, clear stored ID
setStoredId(STORAGE_KEYS.SELECTED_CANDIDATE_ID, null);
console.log('Candidate not found, cleared from storage');
}
@ -116,13 +181,11 @@ export function useAppStateLogic(): AppStateContextType {
promises.push(
(async () => {
try {
// Assuming apiClient.getJob exists
const job = await apiClient.getJob(jobId);
if (job) {
setSelectedJobState(job);
console.log('Restored job from storage:', job);
} else {
// Data not available, clear stored ID
setStoredId(STORAGE_KEYS.SELECTED_JOB_ID, null);
console.log('Job not found, cleared from storage');
}
@ -138,13 +201,11 @@ export function useAppStateLogic(): AppStateContextType {
promises.push(
(async () => {
try {
// Assuming apiClient.getEmployer exists
const employer = await apiClient.getEmployer(employerId);
if (employer) {
setSelectedEmployerState(employer);
console.log('Restored employer from storage:', employer);
} else {
// Data not available, clear stored ID
setStoredId(STORAGE_KEYS.SELECTED_EMPLOYER_ID, null);
console.log('Employer not found, cleared from storage');
}
@ -170,13 +231,29 @@ export function useAppStateLogic(): AppStateContextType {
}, []);
// ============================
// State Setters with Persistence
// Auto-save current route
// ============================
useEffect(() => {
// Don't save certain routes (login, register, etc.)
const excludedRoutes = ['/login', '/register', '/verify-email', '/reset-password'];
const shouldSaveRoute = !excludedRoutes.some(route => location.pathname.startsWith(route));
if (shouldSaveRoute && !isInitializing) {
setRouteStateState(prev => {
const newState = { ...prev, lastRoute: location.pathname };
persistRouteState(newState);
return newState;
});
}
}, [location.pathname, isInitializing]);
// ============================
// Entity State Setters with Persistence
// ============================
const setSelectedCandidate = useCallback((candidate: Types.Candidate | null) => {
setSelectedCandidateState(candidate);
// Persist ID to localStorage
setStoredId(STORAGE_KEYS.SELECTED_CANDIDATE_ID, candidate?.id || null);
if (candidate) {
@ -188,8 +265,6 @@ export function useAppStateLogic(): AppStateContextType {
const setSelectedJob = useCallback((job: Types.Job | null) => {
setSelectedJobState(job);
// Persist ID to localStorage
setStoredId(STORAGE_KEYS.SELECTED_JOB_ID, job?.id || null);
if (job) {
@ -201,8 +276,6 @@ export function useAppStateLogic(): AppStateContextType {
const setSelectedEmployer = useCallback((employer: Types.Employer | null) => {
setSelectedEmployerState(employer);
// Persist ID to localStorage
setStoredId(STORAGE_KEYS.SELECTED_EMPLOYER_ID, employer?.id || null);
if (employer) {
@ -217,7 +290,6 @@ export function useAppStateLogic(): AppStateContextType {
setSelectedJobState(null);
setSelectedEmployerState(null);
// Clear all from localStorage
setStoredId(STORAGE_KEYS.SELECTED_CANDIDATE_ID, null);
setStoredId(STORAGE_KEYS.SELECTED_JOB_ID, null);
setStoredId(STORAGE_KEYS.SELECTED_EMPLOYER_ID, null);
@ -225,15 +297,83 @@ export function useAppStateLogic(): AppStateContextType {
console.log('Cleared all selections');
}, []);
// ============================
// Route State Actions
// ============================
const saveCurrentRoute = useCallback(() => {
setRouteStateState(prev => {
const newState = { ...prev, lastRoute: location.pathname };
persistRouteState(newState);
return newState;
});
}, [location.pathname]);
const restoreLastRoute = useCallback(() => {
if (routeState.lastRoute && routeState.lastRoute !== location.pathname) {
navigate(routeState.lastRoute);
}
}, [routeState.lastRoute, location.pathname, navigate]);
const setActiveTab = useCallback((tab: string) => {
setRouteStateState(prev => {
const newState = { ...prev, activeTab: tab };
persistRouteState(newState);
return newState;
});
}, []);
const setFilters = useCallback((filters: Record<string, any>) => {
setRouteStateState(prev => {
const newState = { ...prev, appliedFilters: filters };
persistRouteState(newState);
return newState;
});
}, []);
const setSidebarCollapsed = useCallback((collapsed: boolean) => {
setRouteStateState(prev => {
const newState = { ...prev, sidebarCollapsed: collapsed };
persistRouteState(newState);
return newState;
});
}, []);
const clearRouteState = useCallback(() => {
const clearedState: RouteState = {
lastRoute: null,
activeTab: null,
appliedFilters: {},
sidebarCollapsed: false
};
setRouteStateState(clearedState);
// Clear from localStorage
localStorage.removeItem(STORAGE_KEYS.LAST_ROUTE);
localStorage.removeItem(STORAGE_KEYS.ACTIVE_TAB);
localStorage.removeItem(STORAGE_KEYS.APPLIED_FILTERS);
localStorage.removeItem(STORAGE_KEYS.SIDEBAR_COLLAPSED);
console.log('Cleared all route state');
}, []);
return {
selectedCandidate,
selectedJob,
selectedEmployer,
routeState,
isInitializing,
setSelectedCandidate,
setSelectedJob,
setSelectedEmployer,
clearSelections
clearSelections,
saveCurrentRoute,
restoreLastRoute,
setActiveTab,
setFilters,
setSidebarCollapsed,
clearRouteState
};
}
@ -262,72 +402,45 @@ export function useAppState() {
}
// ============================
// Convenience Hooks for Specific State
// Convenience Hooks
// ============================
/**
* Hook specifically for candidate selection
* Useful when a component only cares about candidate state
*/
export function useSelectedCandidate() {
const { selectedCandidate, setSelectedCandidate } = useAppState();
return { selectedCandidate, setSelectedCandidate };
}
/**
* Hook specifically for job selection
*/
export function useSelectedJob() {
const { selectedJob, setSelectedJob } = useAppState();
return { selectedJob, setSelectedJob };
}
/**
* Hook specifically for employer selection
*/
export function useSelectedEmployer() {
const { selectedEmployer, setSelectedEmployer } = useAppState();
return { selectedEmployer, setSelectedEmployer };
}
/**
* Hook to check if the app is still initializing
*/
export function useRouteState() {
const {
routeState,
setActiveTab,
setFilters,
setSidebarCollapsed,
restoreLastRoute,
clearRouteState
} = useAppState();
return {
routeState,
setActiveTab,
setFilters,
setSidebarCollapsed,
restoreLastRoute,
clearRouteState
};
}
export function useAppInitializing() {
const { isInitializing } = useAppState();
return isInitializing;
}
// ============================
// Development Utilities
// ============================
/**
* Debug utility to log current app state (development only)
*/
export function useAppStateDebug() {
const appState = useAppState();
useEffect(() => {
if (process.env.NODE_ENV === 'development') {
console.group('🔍 App State Debug');
console.log('Is Initializing:', appState.isInitializing);
console.log('Selected Candidate:', appState.selectedCandidate);
console.log('Selected Job:', appState.selectedJob);
console.log('Selected Employer:', appState.selectedEmployer);
console.groupEnd();
}
}, [appState.selectedCandidate, appState.selectedJob, appState.selectedEmployer, appState.isInitializing]);
return appState;
}
/**
* Utility to manually clear all localStorage for this app (development/debugging)
*/
export function clearAppLocalStorage() {
setStoredId(STORAGE_KEYS.SELECTED_CANDIDATE_ID, null);
setStoredId(STORAGE_KEYS.SELECTED_JOB_ID, null);
setStoredId(STORAGE_KEYS.SELECTED_EMPLOYER_ID, null);
console.log('Cleared all app localStorage');
}

View File

@ -34,7 +34,6 @@ const CandidateListingPage = (props: BackstoryPageProps) => {
}
return result;
});
console.log(candidates);
setCandidates(candidates);
} catch (err) {
setSnack("" + err);