# State Management & Navigation Consistency Solutions ## Overview This document addresses critical state management issues in mobile navigation, including context loss during screen transitions, form state persistence, and navigation consistency between mobile and desktop platforms. ## Issues Identified ### 1. Mobile State Reset Issues **Location**: `frontend/src/App.tsx` mobile navigation logic **Problem**: Navigation between screens resets critical state: - `selectedVehicle` resets when switching screens - `showAddVehicle` form state lost during navigation - User context not maintained across screen transitions - Mobile navigation doesn't preserve history ### 2. Navigation Paradigm Split **Mobile**: State-based navigation without URLs (`activeScreen` state) **Desktop**: URL-based routing with React Router **Impact**: Inconsistent user experience and different development patterns ### 3. State Persistence Gaps - User context not persisted (requires re-authentication overhead) - Form data lost when navigating away - Mobile navigation state not preserved across app restarts - Settings changes not immediately reflected across screens ## Solution Architecture ### Enhanced Mobile State Management #### 1. Navigation State Persistence **File**: `frontend/src/core/store/navigation.ts` (new) ```tsx import { create } from 'zustand'; import { persist } from 'zustand/middleware'; export type MobileScreen = 'dashboard' | 'vehicles' | 'fuel' | 'settings'; export type VehicleSubScreen = 'list' | 'detail' | 'add' | 'edit'; interface NavigationState { // Current navigation state activeScreen: MobileScreen; vehicleSubScreen: VehicleSubScreen; selectedVehicleId: string | null; // Navigation history for back button navigationHistory: { screen: MobileScreen; vehicleSubScreen?: VehicleSubScreen; selectedVehicleId?: string | null; timestamp: number; }[]; // Form state preservation formStates: Record; // Actions navigateToScreen: (screen: MobileScreen) => void; navigateToVehicleSubScreen: (subScreen: VehicleSubScreen, vehicleId?: string) => void; goBack: () => void; saveFormState: (formId: string, state: any) => void; restoreFormState: (formId: string) => any; clearFormState: (formId: string) => void; } export const useNavigationStore = create()( persist( (set, get) => ({ // Initial state activeScreen: 'vehicles', vehicleSubScreen: 'list', selectedVehicleId: null, navigationHistory: [], formStates: {}, // Navigation actions navigateToScreen: (screen) => { const currentState = get(); const historyEntry = { screen: currentState.activeScreen, vehicleSubScreen: currentState.vehicleSubScreen, selectedVehicleId: currentState.selectedVehicleId, timestamp: Date.now(), }; set({ activeScreen: screen, vehicleSubScreen: screen === 'vehicles' ? 'list' : currentState.vehicleSubScreen, selectedVehicleId: screen === 'vehicles' ? currentState.selectedVehicleId : null, navigationHistory: [...currentState.navigationHistory, historyEntry].slice(-10), // Keep last 10 }); }, navigateToVehicleSubScreen: (subScreen, vehicleId = null) => { const currentState = get(); const historyEntry = { screen: currentState.activeScreen, vehicleSubScreen: currentState.vehicleSubScreen, selectedVehicleId: currentState.selectedVehicleId, timestamp: Date.now(), }; set({ vehicleSubScreen: subScreen, selectedVehicleId: vehicleId || currentState.selectedVehicleId, navigationHistory: [...currentState.navigationHistory, historyEntry].slice(-10), }); }, goBack: () => { const currentState = get(); const lastEntry = currentState.navigationHistory[currentState.navigationHistory.length - 1]; if (lastEntry) { set({ activeScreen: lastEntry.screen, vehicleSubScreen: lastEntry.vehicleSubScreen || 'list', selectedVehicleId: lastEntry.selectedVehicleId, navigationHistory: currentState.navigationHistory.slice(0, -1), }); } }, // Form state management saveFormState: (formId, state) => { set((current) => ({ formStates: { ...current.formStates, [formId]: { ...state, timestamp: Date.now() }, }, })); }, restoreFormState: (formId) => { const state = get().formStates[formId]; // Return state if it's less than 1 hour old if (state && Date.now() - state.timestamp < 3600000) { return state; } return null; }, clearFormState: (formId) => { set((current) => { const newFormStates = { ...current.formStates }; delete newFormStates[formId]; return { formStates: newFormStates }; }); }, }), { name: 'motovaultpro-mobile-navigation', partialize: (state) => ({ activeScreen: state.activeScreen, vehicleSubScreen: state.vehicleSubScreen, selectedVehicleId: state.selectedVehicleId, formStates: state.formStates, // Don't persist navigation history - rebuild on app start }), } ) ); ``` #### 2. Enhanced User Context Persistence **File**: `frontend/src/core/store/user.ts` (new) ```tsx import { create } from 'zustand'; import { persist } from 'zustand/middleware'; interface UserPreferences { unitSystem: 'imperial' | 'metric'; darkMode: boolean; notifications: { email: boolean; push: boolean; maintenance: boolean; }; } interface UserState { // User data (persisted subset) userProfile: { id: string; name: string; email: string; picture: string; } | null; preferences: UserPreferences; // Session data (not persisted) isOnline: boolean; lastSyncTimestamp: number; // Actions setUserProfile: (profile: any) => void; updatePreferences: (preferences: Partial) => void; setOnlineStatus: (isOnline: boolean) => void; updateLastSync: () => void; clearUserData: () => void; } export const useUserStore = create()( persist( (set) => ({ // Initial state userProfile: null, preferences: { unitSystem: 'imperial', darkMode: false, notifications: { email: true, push: true, maintenance: true, }, }, isOnline: true, lastSyncTimestamp: 0, // Actions setUserProfile: (profile) => { if (profile) { set({ userProfile: { id: profile.sub, name: profile.name, email: profile.email, picture: profile.picture, }, }); } }, updatePreferences: (newPreferences) => { set((state) => ({ preferences: { ...state.preferences, ...newPreferences }, })); }, setOnlineStatus: (isOnline) => set({ isOnline }), updateLastSync: () => set({ lastSyncTimestamp: Date.now() }), clearUserData: () => set({ userProfile: null, preferences: { unitSystem: 'imperial', darkMode: false, notifications: { email: true, push: true, maintenance: true, }, }, }), }), { name: 'motovaultpro-user-context', partialize: (state) => ({ userProfile: state.userProfile, preferences: state.preferences, // Don't persist session data }), } ) ); ``` #### 3. Smart Form State Hook **File**: `frontend/src/core/hooks/useFormState.ts` (new) ```tsx import { useState, useEffect, useCallback } from 'react'; import { useNavigationStore } from '../store/navigation'; export interface UseFormStateOptions { formId: string; defaultValues: Record; autoSave?: boolean; saveDelay?: number; } export const useFormState = >({ formId, defaultValues, autoSave = true, saveDelay = 1000, }: UseFormStateOptions) => { const { saveFormState, restoreFormState, clearFormState } = useNavigationStore(); const [formData, setFormData] = useState(defaultValues as T); const [hasChanges, setHasChanges] = useState(false); const [isRestored, setIsRestored] = useState(false); // Restore form state on mount useEffect(() => { const restoredState = restoreFormState(formId); if (restoredState && !isRestored) { setFormData({ ...defaultValues, ...restoredState }); setHasChanges(true); setIsRestored(true); } }, [formId, restoreFormState, defaultValues, isRestored]); // Auto-save with debounce useEffect(() => { if (!autoSave || !hasChanges) return; const timer = setTimeout(() => { saveFormState(formId, formData); }, saveDelay); return () => clearTimeout(timer); }, [formData, hasChanges, autoSave, saveDelay, formId, saveFormState]); const updateFormData = useCallback((updates: Partial) => { setFormData((current) => ({ ...current, ...updates })); setHasChanges(true); }, []); const resetForm = useCallback(() => { setFormData(defaultValues as T); setHasChanges(false); clearFormState(formId); }, [defaultValues, formId, clearFormState]); const submitForm = useCallback(() => { setHasChanges(false); clearFormState(formId); }, [formId, clearFormState]); return { formData, updateFormData, resetForm, submitForm, hasChanges, isRestored, }; }; ``` ### Implementation in App.tsx #### Updated Mobile Navigation Logic **File**: `frontend/src/App.tsx` (modifications) ```tsx import { useNavigationStore } from './core/store/navigation'; import { useUserStore } from './core/store/user'; // Replace existing mobile detection and state management const MobileApp: React.FC = () => { const { user, isAuthenticated } = useAuth0(); const { activeScreen, vehicleSubScreen, selectedVehicleId, navigateToScreen, navigateToVehicleSubScreen, goBack, } = useNavigationStore(); const { setUserProfile } = useUserStore(); // Update user profile when authenticated useEffect(() => { if (isAuthenticated && user) { setUserProfile(user); } }, [isAuthenticated, user, setUserProfile]); // Handle mobile back button useEffect(() => { const handlePopState = (event: PopStateEvent) => { event.preventDefault(); goBack(); }; window.addEventListener('popstate', handlePopState); return () => window.removeEventListener('popstate', handlePopState); }, [goBack]); const handleVehicleSelect = (vehicleId: string) => { navigateToVehicleSubScreen('detail', vehicleId); }; const handleAddVehicle = () => { navigateToVehicleSubScreen('add'); }; const handleBackToList = () => { navigateToVehicleSubScreen('list'); }; // Render screens based on navigation state const renderActiveScreen = () => { switch (activeScreen) { case 'vehicles': return renderVehiclesScreen(); case 'fuel': return ; case 'dashboard': return ; case 'settings': return ; default: return renderVehiclesScreen(); } }; const renderVehiclesScreen = () => { switch (vehicleSubScreen) { case 'list': return ( ); case 'detail': return ( ); case 'add': return ( ); default: return ( ); } }; return (
{renderActiveScreen()}
); }; ``` #### Enhanced Add Vehicle Form with State Persistence **File**: `frontend/src/features/vehicles/mobile/AddVehicleScreen.tsx` (example usage) ```tsx import React from 'react'; import { useFormState } from '../../../core/hooks/useFormState'; interface AddVehicleScreenProps { onBack: () => void; onVehicleAdded: () => void; } export const AddVehicleScreen: React.FC = ({ onBack, onVehicleAdded, }) => { const { formData, updateFormData, resetForm, submitForm, hasChanges, isRestored, } = useFormState({ formId: 'add-vehicle', defaultValues: { year: '', make: '', model: '', trim: '', vin: '', licensePlate: '', nickname: '', }, }); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { // Submit vehicle data await submitVehicle(formData); submitForm(); // Clear saved state onVehicleAdded(); } catch (error) { // Handle error, form state is preserved console.error('Error adding vehicle:', error); } }; return (

Add Vehicle

{isRestored && ( Draft restored )}
updateFormData({ year: e.target.value })} className="w-full p-3 border rounded-lg" /> {/* More form fields... */}
{hasChanges && (

Changes are being saved automatically

)}
); }; ``` ## Integration with Existing Systems ### 1. Zustand Store Integration **File**: `frontend/src/core/store/index.ts` (existing file modifications) ```tsx // Export new stores alongside existing ones export { useNavigationStore } from './navigation'; export { useUserStore } from './user'; // Keep existing store exports export { useAppStore } from './app'; ``` ### 2. Auth0 Integration Enhancement **File**: `frontend/src/core/auth/Auth0Provider.tsx` (modifications) ```tsx import { useUserStore } from '../store/user'; // Inside the Auth0Provider component const { setUserProfile, clearUserData } = useUserStore(); // Update user profile on authentication useEffect(() => { if (isAuthenticated && user) { setUserProfile(user); } else if (!isAuthenticated) { clearUserData(); } }, [isAuthenticated, user, setUserProfile, clearUserData]); ``` ### 3. Unit System Integration **File**: `frontend/src/shared-minimal/utils/units.ts` (modifications) ```tsx import { useUserStore } from '../../core/store/user'; // Update existing unit hooks to use new store export const useUnitSystem = () => { const { preferences, updatePreferences } = useUserStore(); const toggleUnitSystem = () => { const newSystem = preferences.unitSystem === 'imperial' ? 'metric' : 'imperial'; updatePreferences({ unitSystem: newSystem }); }; return { unitSystem: preferences.unitSystem, toggleUnitSystem, }; }; ``` ## Testing Requirements ### State Persistence Tests - ✅ Navigation state persists across app restarts - ✅ Selected vehicle context maintained during navigation - ✅ Form state preserved when navigating away and returning - ✅ User preferences persist and sync across screens - ✅ Navigation history works correctly with back button ### Mobile Navigation Tests - ✅ Screen transitions maintain context - ✅ Bottom navigation reflects current state accurately - ✅ Add vehicle form preserves data during interruptions - ✅ Settings changes reflect immediately across screens - ✅ Authentication state managed correctly ### Integration Tests - ✅ New stores integrate properly with existing components - ✅ Auth0 integration works with enhanced user persistence - ✅ Unit system changes sync between old and new systems - ✅ No conflicts with existing Zustand store patterns ## Migration Strategy ### Phase 1: Store Creation 1. Create new navigation and user stores 2. Implement form state management hook 3. Test stores in isolation ### Phase 2: Mobile App Integration 1. Update App.tsx to use new navigation store 2. Modify mobile screens to use form state hook 3. Test mobile navigation and persistence ### Phase 3: System Integration 1. Integrate with existing Auth0 provider 2. Update unit system to use new user store 3. Ensure backward compatibility ### Phase 4: Enhancement & Optimization 1. Add advanced features like offline persistence 2. Optimize performance and storage usage 3. Add error handling and recovery mechanisms ## Success Criteria Upon completion: 1. **Navigation Consistency**: Mobile navigation maintains context across all transitions 2. **State Persistence**: All user data, preferences, and form states persist appropriately 3. **Form Recovery**: Users can navigate away from forms and return without data loss 4. **User Context**: User preferences and settings sync immediately across all screens 5. **Back Navigation**: Mobile back button works correctly with navigation history 6. **Integration**: New state management integrates seamlessly with existing systems This enhanced state management system will provide a robust foundation for consistent mobile and desktop experiences while maintaining all existing functionality.