Files
motovaultpro/docs/changes/mobile-optimization-v1/06-CODE-EXAMPLES.md
Eric Gullickson a052040e3a Initial Commit
2025-09-17 16:09:15 -05:00

40 KiB

Code Examples & Implementation Snippets

Overview

This document provides concrete code examples and implementation snippets for all mobile optimization improvements. These examples can be directly used during implementation with minimal modifications.

Mobile Settings Implementation

Complete Mobile Settings Screen

File: frontend/src/features/settings/mobile/MobileSettingsScreen.tsx

import React, { useState } from 'react';
import { useAuth0 } from '@auth0/auth0-react';
import {
  GlassCard,
  MobileContainer,
  MobilePill
} from '../../../shared-minimal/components/mobile';
import { useSettings } from '../hooks/useSettings';

interface ToggleSwitchProps {
  enabled: boolean;
  onChange: () => void;
  label: string;
  description?: string;
}

const ToggleSwitch: React.FC<ToggleSwitchProps> = ({
  enabled,
  onChange,
  label,
  description
}) => (
  <div className="flex items-center justify-between py-2">
    <div>
      <p className="font-medium text-slate-800">{label}</p>
      {description && (
        <p className="text-sm text-slate-500">{description}</p>
      )}
    </div>
    <button
      onClick={onChange}
      className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
        enabled ? 'bg-blue-600' : 'bg-gray-200'
      }`}
    >
      <span
        className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
          enabled ? 'translate-x-6' : 'translate-x-1'
        }`}
      />
    </button>
  </div>
);

interface ModalProps {
  isOpen: boolean;
  onClose: () => void;
  title: string;
  children: React.ReactNode;
}

const Modal: React.FC<ModalProps> = ({ isOpen, onClose, title, children }) => {
  if (!isOpen) return null;

  return (
    <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
      <div className="bg-white rounded-lg p-6 max-w-sm w-full">
        <h3 className="text-lg font-semibold text-slate-800 mb-4">{title}</h3>
        {children}
        <div className="flex justify-end mt-4">
          <button
            onClick={onClose}
            className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg font-medium"
          >
            Close
          </button>
        </div>
      </div>
    </div>
  );
};

export const MobileSettingsScreen: React.FC = () => {
  const { user, logout } = useAuth0();
  const { settings, updateSetting } = useSettings();
  const [showDataExport, setShowDataExport] = useState(false);
  const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);

  const handleLogout = () => {
    logout({
      logoutParams: {
        returnTo: window.location.origin
      }
    });
  };

  const handleExportData = () => {
    // Implement data export functionality
    console.log('Exporting user data...');
    setShowDataExport(false);
  };

  const handleDeleteAccount = () => {
    // Implement account deletion
    console.log('Deleting account...');
    setShowDeleteConfirm(false);
  };

  return (
    <MobileContainer>
      <div className="space-y-4 pb-20">
        {/* Header */}
        <div className="text-center mb-6">
          <h1 className="text-2xl font-bold text-slate-800">Settings</h1>
          <p className="text-slate-500 mt-2">Manage your account and preferences</p>
        </div>

        {/* Account Section */}
        <GlassCard>
          <div className="p-4">
            <h2 className="text-lg font-semibold text-slate-800 mb-4">Account</h2>
            <div className="flex items-center space-x-3">
              {user?.picture && (
                <img
                  src={user.picture}
                  alt="Profile"
                  className="w-12 h-12 rounded-full"
                />
              )}
              <div>
                <p className="font-medium text-slate-800">{user?.name}</p>
                <p className="text-sm text-slate-500">{user?.email}</p>
              </div>
            </div>
            <div className="pt-3 mt-3 border-t border-slate-200">
              <p className="text-sm text-slate-600">
                Member since {user?.updated_at ? new Date(user.updated_at).toLocaleDateString() : 'Unknown'}
              </p>
            </div>
          </div>
        </GlassCard>

        {/* Notifications Section */}
        <GlassCard>
          <div className="p-4">
            <h2 className="text-lg font-semibold text-slate-800 mb-4">Notifications</h2>
            <div className="space-y-3">
              <ToggleSwitch
                enabled={settings.notifications.email}
                onChange={() => updateSetting('notifications', {
                  ...settings.notifications,
                  email: !settings.notifications.email
                })}
                label="Email Notifications"
                description="Receive updates via email"
              />
              <ToggleSwitch
                enabled={settings.notifications.push}
                onChange={() => updateSetting('notifications', {
                  ...settings.notifications,
                  push: !settings.notifications.push
                })}
                label="Push Notifications"
                description="Receive mobile push notifications"
              />
              <ToggleSwitch
                enabled={settings.notifications.maintenance}
                onChange={() => updateSetting('notifications', {
                  ...settings.notifications,
                  maintenance: !settings.notifications.maintenance
                })}
                label="Maintenance Reminders"
                description="Get reminded about vehicle maintenance"
              />
            </div>
          </div>
        </GlassCard>

        {/* Appearance & Units Section */}
        <GlassCard>
          <div className="p-4">
            <h2 className="text-lg font-semibold text-slate-800 mb-4">Appearance & Units</h2>
            <div className="space-y-4">
              <ToggleSwitch
                enabled={settings.darkMode}
                onChange={() => updateSetting('darkMode', !settings.darkMode)}
                label="Dark Mode"
                description="Switch to dark theme"
              />

              <div className="flex items-center justify-between">
                <div>
                  <p className="font-medium text-slate-800">Unit System</p>
                  <p className="text-sm text-slate-500">
                    Currently using {settings.unitSystem === 'imperial' ? 'Miles & Gallons' : 'Kilometers & Liters'}
                  </p>
                </div>
                <MobilePill
                  label={settings.unitSystem === 'imperial' ? 'Metric' : 'Imperial'}
                  onClick={() => updateSetting('unitSystem', settings.unitSystem === 'imperial' ? 'metric' : 'imperial')}
                  variant="secondary"
                />
              </div>
            </div>
          </div>
        </GlassCard>

        {/* Data Management Section */}
        <GlassCard>
          <div className="p-4">
            <h2 className="text-lg font-semibold text-slate-800 mb-4">Data Management</h2>
            <div className="space-y-3">
              <button
                onClick={() => setShowDataExport(true)}
                className="w-full text-left p-3 bg-blue-50 text-blue-700 rounded-lg font-medium"
              >
                Export My Data
              </button>
              <p className="text-sm text-slate-500">
                Download a copy of all your vehicle and fuel data
              </p>
            </div>
          </div>
        </GlassCard>

        {/* Account Actions Section */}
        <GlassCard>
          <div className="p-4">
            <h2 className="text-lg font-semibold text-slate-800 mb-4">Account Actions</h2>
            <div className="space-y-3">
              <button
                onClick={handleLogout}
                className="w-full py-3 px-4 bg-gray-100 text-gray-700 rounded-lg text-left font-medium"
              >
                Sign Out
              </button>
              <button
                onClick={() => setShowDeleteConfirm(true)}
                className="w-full py-3 px-4 bg-red-50 text-red-600 rounded-lg text-left font-medium"
              >
                Delete Account
              </button>
            </div>
          </div>
        </GlassCard>

        {/* Data Export Modal */}
        <Modal
          isOpen={showDataExport}
          onClose={() => setShowDataExport(false)}
          title="Export Data"
        >
          <p className="text-slate-600 mb-4">
            This will create a downloadable file containing all your vehicle data, fuel logs, and preferences.
          </p>
          <div className="flex space-x-3">
            <button
              onClick={() => setShowDataExport(false)}
              className="flex-1 py-2 px-4 bg-gray-200 text-gray-700 rounded-lg font-medium"
            >
              Cancel
            </button>
            <button
              onClick={handleExportData}
              className="flex-1 py-2 px-4 bg-blue-600 text-white rounded-lg font-medium"
            >
              Export
            </button>
          </div>
        </Modal>

        {/* Delete Account Confirmation */}
        <Modal
          isOpen={showDeleteConfirm}
          onClose={() => setShowDeleteConfirm(false)}
          title="Delete Account"
        >
          <p className="text-slate-600 mb-4">
            This action cannot be undone. All your data will be permanently deleted.
          </p>
          <div className="flex space-x-3">
            <button
              onClick={() => setShowDeleteConfirm(false)}
              className="flex-1 py-2 px-4 bg-gray-200 text-gray-700 rounded-lg font-medium"
            >
              Cancel
            </button>
            <button
              onClick={handleDeleteAccount}
              className="flex-1 py-2 px-4 bg-red-600 text-white rounded-lg font-medium"
            >
              Delete
            </button>
          </div>
        </Modal>
      </div>
    </MobileContainer>
  );
};

State Management Examples

Enhanced Navigation Store

File: frontend/src/core/store/navigation.ts

import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';

export type MobileScreen = 'dashboard' | 'vehicles' | 'fuel' | 'settings';
export type VehicleSubScreen = 'list' | 'detail' | 'add' | 'edit';

interface NavigationHistory {
  screen: MobileScreen;
  vehicleSubScreen?: VehicleSubScreen;
  selectedVehicleId?: string | null;
  timestamp: number;
  metadata?: Record<string, any>;
}

interface FormState {
  data: Record<string, any>;
  timestamp: number;
  isDirty: boolean;
}

interface NavigationState {
  // Current navigation state
  activeScreen: MobileScreen;
  vehicleSubScreen: VehicleSubScreen;
  selectedVehicleId: string | null;

  // Navigation history for back button
  navigationHistory: NavigationHistory[];

  // Form state preservation
  formStates: Record<string, FormState>;

  // Loading and error states
  isNavigating: boolean;
  navigationError: string | null;

  // Actions
  navigateToScreen: (screen: MobileScreen, metadata?: Record<string, any>) => void;
  navigateToVehicleSubScreen: (subScreen: VehicleSubScreen, vehicleId?: string, metadata?: Record<string, any>) => void;
  goBack: () => boolean;
  canGoBack: () => boolean;
  saveFormState: (formId: string, data: any, isDirty?: boolean) => void;
  restoreFormState: (formId: string) => FormState | null;
  clearFormState: (formId: string) => void;
  clearAllFormStates: () => void;
  setNavigationError: (error: string | null) => void;
}

export const useNavigationStore = create<NavigationState>()(
  persist(
    (set, get) => ({
      // Initial state
      activeScreen: 'vehicles',
      vehicleSubScreen: 'list',
      selectedVehicleId: null,
      navigationHistory: [],
      formStates: {},
      isNavigating: false,
      navigationError: null,

      // Navigation actions
      navigateToScreen: (screen, metadata = {}) => {
        const currentState = get();

        set({ isNavigating: true, navigationError: null });

        try {
          const historyEntry: NavigationHistory = {
            screen: currentState.activeScreen,
            vehicleSubScreen: currentState.vehicleSubScreen,
            selectedVehicleId: currentState.selectedVehicleId,
            timestamp: Date.now(),
            metadata,
          };

          set({
            activeScreen: screen,
            vehicleSubScreen: screen === 'vehicles' ? 'list' : currentState.vehicleSubScreen,
            selectedVehicleId: screen === 'vehicles' ? currentState.selectedVehicleId : null,
            navigationHistory: [...currentState.navigationHistory, historyEntry].slice(-10),
            isNavigating: false,
          });
        } catch (error) {
          set({
            navigationError: error instanceof Error ? error.message : 'Navigation failed',
            isNavigating: false
          });
        }
      },

      navigateToVehicleSubScreen: (subScreen, vehicleId = null, metadata = {}) => {
        const currentState = get();

        set({ isNavigating: true, navigationError: null });

        try {
          const historyEntry: NavigationHistory = {
            screen: currentState.activeScreen,
            vehicleSubScreen: currentState.vehicleSubScreen,
            selectedVehicleId: currentState.selectedVehicleId,
            timestamp: Date.now(),
            metadata,
          };

          set({
            vehicleSubScreen: subScreen,
            selectedVehicleId: vehicleId || currentState.selectedVehicleId,
            navigationHistory: [...currentState.navigationHistory, historyEntry].slice(-10),
            isNavigating: false,
          });
        } catch (error) {
          set({
            navigationError: error instanceof Error ? error.message : 'Navigation failed',
            isNavigating: false
          });
        }
      },

      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),
            isNavigating: false,
            navigationError: null,
          });
          return true;
        }
        return false;
      },

      canGoBack: () => {
        return get().navigationHistory.length > 0;
      },

      // Form state management
      saveFormState: (formId, data, isDirty = true) => {
        const currentState = get();
        const formState: FormState = {
          data,
          timestamp: Date.now(),
          isDirty,
        };

        set({
          formStates: {
            ...currentState.formStates,
            [formId]: formState,
          },
        });
      },

      restoreFormState: (formId) => {
        const state = get().formStates[formId];
        const maxAge = 2 * 60 * 60 * 1000; // 2 hours

        if (state && Date.now() - state.timestamp < maxAge) {
          return state;
        }

        // Clean up old state
        if (state) {
          get().clearFormState(formId);
        }

        return null;
      },

      clearFormState: (formId) => {
        const currentState = get();
        const newFormStates = { ...currentState.formStates };
        delete newFormStates[formId];
        set({ formStates: newFormStates });
      },

      clearAllFormStates: () => {
        set({ formStates: {} });
      },

      setNavigationError: (error) => {
        set({ navigationError: error });
      },
    }),
    {
      name: 'motovaultpro-mobile-navigation',
      storage: createJSONStorage(() => localStorage),
      partialize: (state) => ({
        activeScreen: state.activeScreen,
        vehicleSubScreen: state.vehicleSubScreen,
        selectedVehicleId: state.selectedVehicleId,
        formStates: state.formStates,
      }),
    }
  )
);

Form State Hook Implementation

File: frontend/src/core/hooks/useFormState.ts

import { useState, useEffect, useCallback, useRef } from 'react';
import { useNavigationStore } from '../store/navigation';
import { debounce } from 'lodash';

export interface UseFormStateOptions<T> {
  formId: string;
  defaultValues: T;
  autoSave?: boolean;
  saveDelay?: number;
  onRestore?: (data: T) => void;
  onSave?: (data: T) => void;
  validate?: (data: T) => Record<string, string> | null;
}

export interface FormStateReturn<T> {
  formData: T;
  updateFormData: (updates: Partial<T>) => void;
  setFormData: (data: T) => void;
  resetForm: () => void;
  submitForm: () => Promise<void>;
  hasChanges: boolean;
  isRestored: boolean;
  isSaving: boolean;
  errors: Record<string, string>;
  isValid: boolean;
}

export const useFormState = <T extends Record<string, any>>({
  formId,
  defaultValues,
  autoSave = true,
  saveDelay = 1000,
  onRestore,
  onSave,
  validate,
}: UseFormStateOptions<T>): FormStateReturn<T> => {
  const { saveFormState, restoreFormState, clearFormState } = useNavigationStore();
  const [formData, setFormDataState] = useState<T>(defaultValues);
  const [hasChanges, setHasChanges] = useState(false);
  const [isRestored, setIsRestored] = useState(false);
  const [isSaving, setIsSaving] = useState(false);
  const [errors, setErrors] = useState<Record<string, string>>({});

  const initialDataRef = useRef<T>(defaultValues);
  const formDataRef = useRef<T>(formData);

  // Update ref when formData changes
  useEffect(() => {
    formDataRef.current = formData;
  }, [formData]);

  // Validation
  const validateForm = useCallback((data: T) => {
    if (!validate) return {};

    const validationErrors = validate(data);
    return validationErrors || {};
  }, [validate]);

  // Restore form state on mount
  useEffect(() => {
    const restoredState = restoreFormState(formId);
    if (restoredState && !isRestored) {
      const restoredData = { ...defaultValues, ...restoredState.data };
      setFormDataState(restoredData);
      setHasChanges(restoredState.isDirty);
      setIsRestored(true);

      if (onRestore) {
        onRestore(restoredData);
      }
    }
  }, [formId, restoreFormState, defaultValues, isRestored, onRestore]);

  // Auto-save with debounce
  const debouncedSave = useCallback(
    debounce(async (data: T, isDirty: boolean) => {
      if (!autoSave || !isDirty) return;

      try {
        setIsSaving(true);
        saveFormState(formId, data, isDirty);

        if (onSave) {
          await onSave(data);
        }
      } catch (error) {
        console.warn('Form auto-save failed:', error);
      } finally {
        setIsSaving(false);
      }
    }, saveDelay),
    [autoSave, saveDelay, formId, saveFormState, onSave]
  );

  // Trigger auto-save when form data changes
  useEffect(() => {
    if (hasChanges) {
      const validationErrors = validateForm(formData);
      setErrors(validationErrors);
      debouncedSave(formData, hasChanges);
    }
  }, [formData, hasChanges, validateForm, debouncedSave]);

  const updateFormData = useCallback((updates: Partial<T>) => {
    setFormDataState((current) => {
      const updated = { ...current, ...updates };
      const hasActualChanges = JSON.stringify(updated) !== JSON.stringify(initialDataRef.current);
      setHasChanges(hasActualChanges);
      return updated;
    });
  }, []);

  const setFormData = useCallback((data: T) => {
    setFormDataState(data);
    const hasActualChanges = JSON.stringify(data) !== JSON.stringify(initialDataRef.current);
    setHasChanges(hasActualChanges);
  }, []);

  const resetForm = useCallback(() => {
    setFormDataState(defaultValues);
    setHasChanges(false);
    setErrors({});
    clearFormState(formId);
    initialDataRef.current = { ...defaultValues };
  }, [defaultValues, formId, clearFormState]);

  const submitForm = useCallback(async () => {
    const validationErrors = validateForm(formDataRef.current);
    setErrors(validationErrors);

    if (Object.keys(validationErrors).length > 0) {
      throw new Error('Form validation failed');
    }

    try {
      setHasChanges(false);
      clearFormState(formId);
      initialDataRef.current = { ...formDataRef.current };

      if (onSave) {
        await onSave(formDataRef.current);
      }
    } catch (error) {
      setHasChanges(true); // Restore changes state on error
      throw error;
    }
  }, [validateForm, formId, clearFormState, onSave]);

  const isValid = Object.keys(errors).length === 0;

  return {
    formData,
    updateFormData,
    setFormData,
    resetForm,
    submitForm,
    hasChanges,
    isRestored,
    isSaving,
    errors,
    isValid,
  };
};

Token Management Examples

Enhanced API Client with 401 Retry

File: frontend/src/core/api/enhancedClient.ts

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';

interface TokenManager {
  refreshToken(): Promise<string>;
  isRefreshing(): boolean;
  addFailedRequest(request: () => Promise<any>): void;
}

class AuthTokenManager implements TokenManager {
  private static instance: AuthTokenManager;
  private _isRefreshing = false;
  private failedQueue: Array<{
    resolve: (token: string) => void;
    reject: (error: Error) => void;
  }> = [];
  private getAccessTokenSilently: any;

  constructor(getAccessTokenSilently: any) {
    this.getAccessTokenSilently = getAccessTokenSilently;
  }

  static getInstance(getAccessTokenSilently?: any): AuthTokenManager {
    if (!AuthTokenManager.instance && getAccessTokenSilently) {
      AuthTokenManager.instance = new AuthTokenManager(getAccessTokenSilently);
    }
    return AuthTokenManager.instance;
  }

  async refreshToken(): Promise<string> {
    if (this._isRefreshing) {
      return new Promise((resolve, reject) => {
        this.failedQueue.push({ resolve, reject });
      });
    }

    this._isRefreshing = true;

    try {
      const token = await this.getAccessTokenSilently({
        cacheMode: 'off',
        timeoutInSeconds: 20,
      });

      // Process queued requests
      this.failedQueue.forEach(({ resolve }) => resolve(token));
      this.failedQueue = [];

      return token;
    } catch (error) {
      // Reject queued requests
      this.failedQueue.forEach(({ reject }) => reject(error as Error));
      this.failedQueue = [];
      throw error;
    } finally {
      this._isRefreshing = false;
    }
  }

  isRefreshing(): boolean {
    return this._isRefreshing;
  }

  addFailedRequest(callback: () => Promise<any>): void {
    this.failedQueue.push({
      resolve: () => callback(),
      reject: (error) => Promise.reject(error),
    });
  }
}

export const createEnhancedApiClient = (getAccessTokenSilently: any): AxiosInstance => {
  const tokenManager = AuthTokenManager.getInstance(getAccessTokenSilently);

  const client = axios.create({
    baseURL: process.env.REACT_APP_API_URL || '/api',
    timeout: 10000,
    headers: {
      'Content-Type': 'application/json',
    },
  });

  // Request interceptor - inject tokens
  client.interceptors.request.use(
    async (config) => {
      try {
        // Don't add token if already refreshing or if this is a retry
        if (!config._retry && !tokenManager.isRefreshing()) {
          const token = await getAccessTokenSilently({
            cacheMode: 'on',
            timeoutInSeconds: 15,
          });

          if (token) {
            config.headers = config.headers || {};
            config.headers.Authorization = `Bearer ${token}`;
          }
        }
      } catch (error) {
        console.warn('Token acquisition failed, proceeding without token:', error);
      }

      return config;
    },
    (error) => Promise.reject(error)
  );

  // Response interceptor - handle 401s with token refresh retry
  client.interceptors.response.use(
    (response: AxiosResponse) => response,
    async (error) => {
      const originalRequest = error.config;

      // Handle 401 responses with token refresh
      if (error.response?.status === 401 && !originalRequest._retry) {
        originalRequest._retry = true;

        try {
          console.log('401 detected, attempting token refresh...');
          const newToken = await tokenManager.refreshToken();

          // Update the failed request with new token
          originalRequest.headers = originalRequest.headers || {};
          originalRequest.headers.Authorization = `Bearer ${newToken}`;

          // Retry the original request
          return client(originalRequest);
        } catch (refreshError) {
          console.error('Token refresh failed:', refreshError);

          // Clear any stored tokens and redirect to login
          localStorage.clear();
          window.location.href = '/';

          return Promise.reject(refreshError);
        }
      }

      // Enhanced mobile error handling
      if (error.code === 'ECONNABORTED' || error.message.includes('timeout')) {
        const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
          navigator.userAgent
        );

        if (isMobile) {
          error.message = 'Connection timeout. Please check your network and try again.';
        }
      }

      return Promise.reject(error);
    }
  );

  return client;
};

// Usage example
export const useApiClient = () => {
  const { getAccessTokenSilently } = useAuth0();

  return useMemo(() => {
    return createEnhancedApiClient(getAccessTokenSilently);
  }, [getAccessTokenSilently]);
};

Mobile Component Examples

Enhanced Add Vehicle Form with State Persistence

File: frontend/src/features/vehicles/mobile/EnhancedAddVehicleScreen.tsx

import React, { useCallback } from 'react';
import { ArrowLeft, Save } from 'lucide-react';
import { useFormState } from '../../../core/hooks/useFormState';
import { useNavigationStore } from '../../../core/store/navigation';
import { GlassCard, MobileContainer, MobilePill } from '../../../shared-minimal/components/mobile';

interface VehicleFormData {
  year: string;
  make: string;
  model: string;
  trim: string;
  vin: string;
  licensePlate: string;
  nickname: string;
  color: string;
}

interface EnhancedAddVehicleScreenProps {
  onVehicleAdded: () => void;
}

export const EnhancedAddVehicleScreen: React.FC<EnhancedAddVehicleScreenProps> = ({
  onVehicleAdded,
}) => {
  const { goBack } = useNavigationStore();

  const validateForm = useCallback((data: VehicleFormData) => {
    const errors: Record<string, string> = {};

    if (!data.year || parseInt(data.year) < 1900 || parseInt(data.year) > new Date().getFullYear() + 1) {
      errors.year = 'Please enter a valid year';
    }

    if (!data.make.trim()) {
      errors.make = 'Make is required';
    }

    if (!data.model.trim()) {
      errors.model = 'Model is required';
    }

    if (data.vin && data.vin.length !== 17) {
      errors.vin = 'VIN must be 17 characters';
    }

    if (!data.vin.trim() && !data.licensePlate.trim()) {
      errors.licensePlate = 'Either VIN or License Plate is required';
    }

    return Object.keys(errors).length > 0 ? errors : null;
  }, []);

  const {
    formData,
    updateFormData,
    resetForm,
    submitForm,
    hasChanges,
    isRestored,
    isSaving,
    errors,
    isValid,
  } = useFormState<VehicleFormData>({
    formId: 'add-vehicle',
    defaultValues: {
      year: '',
      make: '',
      model: '',
      trim: '',
      vin: '',
      licensePlate: '',
      nickname: '',
      color: '',
    },
    validate: validateForm,
    onRestore: (data) => {
      console.log('Form data restored:', data);
    },
  });

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    if (!isValid) {
      return;
    }

    try {
      // Simulate API call
      await new Promise(resolve => setTimeout(resolve, 1000));

      await submitForm();
      onVehicleAdded();
    } catch (error) {
      console.error('Error adding vehicle:', error);
      // Form state is preserved on error
    }
  };

  const handleBack = () => {
    if (hasChanges) {
      const confirmLeave = window.confirm(
        'You have unsaved changes. Are you sure you want to leave? Your changes will be saved as a draft.'
      );
      if (!confirmLeave) return;
    }

    goBack();
  };

  return (
    <MobileContainer>
      <div className="space-y-4 pb-20">
        {/* Header */}
        <div className="flex items-center justify-between mb-6">
          <div className="flex items-center">
            <button onClick={handleBack} className="mr-4">
              <ArrowLeft className="w-6 h-6 text-slate-700" />
            </button>
            <div>
              <h1 className="text-xl font-bold text-slate-800">Add Vehicle</h1>
              {isRestored && (
                <p className="text-sm text-blue-600">Draft restored</p>
              )}
            </div>
          </div>

          {isSaving && (
            <div className="flex items-center text-sm text-blue-600">
              <Save className="w-4 h-4 mr-1" />
              Saving...
            </div>
          )}
        </div>

        <form onSubmit={handleSubmit} className="space-y-4">
          {/* Basic Information */}
          <GlassCard>
            <div className="p-4">
              <h2 className="text-lg font-semibold text-slate-800 mb-4">Basic Information</h2>

              <div className="space-y-4">
                <div>
                  <label className="block text-sm font-medium text-slate-700 mb-1">
                    Year *
                  </label>
                  <input
                    type="number"
                    placeholder="2023"
                    value={formData.year}
                    onChange={(e) => updateFormData({ year: e.target.value })}
                    className={`w-full p-3 border rounded-lg ${
                      errors.year ? 'border-red-300' : 'border-slate-300'
                    }`}
                  />
                  {errors.year && (
                    <p className="text-sm text-red-600 mt-1">{errors.year}</p>
                  )}
                </div>

                <div>
                  <label className="block text-sm font-medium text-slate-700 mb-1">
                    Make *
                  </label>
                  <input
                    type="text"
                    placeholder="Toyota"
                    value={formData.make}
                    onChange={(e) => updateFormData({ make: e.target.value })}
                    className={`w-full p-3 border rounded-lg ${
                      errors.make ? 'border-red-300' : 'border-slate-300'
                    }`}
                  />
                  {errors.make && (
                    <p className="text-sm text-red-600 mt-1">{errors.make}</p>
                  )}
                </div>

                <div>
                  <label className="block text-sm font-medium text-slate-700 mb-1">
                    Model *
                  </label>
                  <input
                    type="text"
                    placeholder="Camry"
                    value={formData.model}
                    onChange={(e) => updateFormData({ model: e.target.value })}
                    className={`w-full p-3 border rounded-lg ${
                      errors.model ? 'border-red-300' : 'border-slate-300'
                    }`}
                  />
                  {errors.model && (
                    <p className="text-sm text-red-600 mt-1">{errors.model}</p>
                  )}
                </div>

                <div>
                  <label className="block text-sm font-medium text-slate-700 mb-1">
                    Trim
                  </label>
                  <input
                    type="text"
                    placeholder="LE, XLE, etc."
                    value={formData.trim}
                    onChange={(e) => updateFormData({ trim: e.target.value })}
                    className="w-full p-3 border border-slate-300 rounded-lg"
                  />
                </div>
              </div>
            </div>
          </GlassCard>

          {/* Identification */}
          <GlassCard>
            <div className="p-4">
              <h2 className="text-lg font-semibold text-slate-800 mb-4">Identification</h2>

              <div className="space-y-4">
                <div>
                  <label className="block text-sm font-medium text-slate-700 mb-1">
                    VIN
                  </label>
                  <input
                    type="text"
                    placeholder="17-character VIN"
                    value={formData.vin}
                    onChange={(e) => updateFormData({ vin: e.target.value.toUpperCase() })}
                    maxLength={17}
                    className={`w-full p-3 border rounded-lg font-mono text-sm ${
                      errors.vin ? 'border-red-300' : 'border-slate-300'
                    }`}
                  />
                  {errors.vin && (
                    <p className="text-sm text-red-600 mt-1">{errors.vin}</p>
                  )}
                </div>

                <div>
                  <label className="block text-sm font-medium text-slate-700 mb-1">
                    License Plate
                  </label>
                  <input
                    type="text"
                    placeholder="ABC-123"
                    value={formData.licensePlate}
                    onChange={(e) => updateFormData({ licensePlate: e.target.value.toUpperCase() })}
                    className={`w-full p-3 border rounded-lg ${
                      errors.licensePlate ? 'border-red-300' : 'border-slate-300'
                    }`}
                  />
                  {errors.licensePlate && (
                    <p className="text-sm text-red-600 mt-1">{errors.licensePlate}</p>
                  )}
                </div>

                <div>
                  <label className="block text-sm font-medium text-slate-700 mb-1">
                    Nickname
                  </label>
                  <input
                    type="text"
                    placeholder="My Daily Driver"
                    value={formData.nickname}
                    onChange={(e) => updateFormData({ nickname: e.target.value })}
                    className="w-full p-3 border border-slate-300 rounded-lg"
                  />
                </div>
              </div>
            </div>
          </GlassCard>

          {/* Form Actions */}
          <div className="flex space-x-3 pt-4">
            <button
              type="button"
              onClick={resetForm}
              className="flex-1 py-3 bg-gray-200 text-gray-700 rounded-lg font-medium"
            >
              Clear All
            </button>
            <button
              type="submit"
              disabled={!isValid}
              className={`flex-1 py-3 rounded-lg font-medium ${
                isValid
                  ? 'bg-blue-600 text-white'
                  : 'bg-gray-300 text-gray-500 cursor-not-allowed'
              }`}
            >
              Add Vehicle
            </button>
          </div>

          {hasChanges && (
            <p className="text-sm text-blue-600 text-center bg-blue-50 p-2 rounded-lg">
              Changes are being saved automatically
            </p>
          )}
        </form>
      </div>
    </MobileContainer>
  );
};

App Integration Examples

Updated App.tsx with Enhanced Navigation

File: frontend/src/App.tsx (key sections)

import React, { useEffect } from 'react';
import { useAuth0 } from '@auth0/auth0-react';
import { useNavigationStore } from './core/store/navigation';
import { useUserStore } from './core/store/user';
import { MobileSettingsScreen } from './features/settings/mobile/MobileSettingsScreen';
import { EnhancedAddVehicleScreen } from './features/vehicles/mobile/EnhancedAddVehicleScreen';

const MobileApp: React.FC = () => {
  const { user, isAuthenticated, isLoading } = useAuth0();
  const {
    activeScreen,
    vehicleSubScreen,
    selectedVehicleId,
    navigateToScreen,
    navigateToVehicleSubScreen,
    goBack,
    canGoBack,
    navigationError,
  } = useNavigationStore();

  const { setUserProfile } = useUserStore();

  // Update user profile when authenticated
  useEffect(() => {
    if (isAuthenticated && user) {
      setUserProfile(user);
    }
  }, [isAuthenticated, user, setUserProfile]);

  // Handle mobile back button and navigation errors
  useEffect(() => {
    const handlePopState = (event: PopStateEvent) => {
      event.preventDefault();
      if (canGoBack()) {
        goBack();
      }
    };

    const handleNavigationError = () => {
      if (navigationError) {
        console.error('Navigation error:', navigationError);
        // Could show toast notification here
      }
    };

    window.addEventListener('popstate', handlePopState);
    handleNavigationError();

    return () => {
      window.removeEventListener('popstate', handlePopState);
    };
  }, [goBack, canGoBack, navigationError]);

  const handleVehicleSelect = useCallback((vehicleId: string) => {
    navigateToVehicleSubScreen('detail', vehicleId, { source: 'vehicle-list' });
  }, [navigateToVehicleSubScreen]);

  const handleAddVehicle = useCallback(() => {
    navigateToVehicleSubScreen('add', null, { source: 'vehicle-list' });
  }, [navigateToVehicleSubScreen]);

  const handleBackToList = useCallback(() => {
    navigateToVehicleSubScreen('list', null, { source: 'back-navigation' });
  }, [navigateToVehicleSubScreen]);

  const handleVehicleAdded = useCallback(() => {
    navigateToVehicleSubScreen('list', null, { source: 'vehicle-added' });
  }, [navigateToVehicleSubScreen]);

  // Show loading screen while Auth0 initializes
  if (isLoading) {
    return (
      <div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
          <p className="text-slate-600">Loading MotoVaultPro...</p>
        </div>
      </div>
    );
  }

  // Show login screen if not authenticated
  if (!isAuthenticated) {
    return (
      <div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 flex items-center justify-center p-4">
        <div className="max-w-md w-full text-center">
          <h1 className="text-3xl font-bold text-slate-800 mb-2">MotoVaultPro</h1>
          <p className="text-slate-600 mb-8">Track your vehicles and fuel efficiency</p>
          <button
            onClick={() => loginWithRedirect()}
            className="w-full py-3 px-6 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors"
          >
            Sign In
          </button>
        </div>
      </div>
    );
  }

  // Main mobile app interface
  return (
    <div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50">
      {/* Navigation Error Banner */}
      {navigationError && (
        <div className="bg-red-100 border-l-4 border-red-500 text-red-700 p-4">
          <p className="font-medium">Navigation Error</p>
          <p className="text-sm">{navigationError}</p>
        </div>
      )}

      {/* Screen Content */}
      {renderActiveScreen()}

      {/* Bottom Navigation */}
      <BottomNavigation
        activeScreen={activeScreen}
        onScreenChange={navigateToScreen}
        hasChanges={hasUnsavedChanges()} // Could implement this to show unsaved indicators
      />
    </div>
  );

  // Screen rendering logic
  function renderActiveScreen() {
    switch (activeScreen) {
      case 'vehicles':
        return renderVehiclesScreen();
      case 'fuel':
        return <FuelScreen />;
      case 'dashboard':
        return <DashboardScreen />;
      case 'settings':
        return <MobileSettingsScreen />;
      default:
        return renderVehiclesScreen();
    }
  }

  function renderVehiclesScreen() {
    switch (vehicleSubScreen) {
      case 'list':
        return (
          <VehiclesMobileScreen
            onVehicleSelect={handleVehicleSelect}
            onAddVehicle={handleAddVehicle}
          />
        );
      case 'detail':
        return (
          <VehicleDetailMobile
            vehicleId={selectedVehicleId!}
            onBack={handleBackToList}
          />
        );
      case 'add':
        return (
          <EnhancedAddVehicleScreen
            onVehicleAdded={handleVehicleAdded}
          />
        );
      default:
        return (
          <VehiclesMobileScreen
            onVehicleSelect={handleVehicleSelect}
            onAddVehicle={handleAddVehicle}
          />
        );
    }
  }
};

These code examples provide concrete, implementable solutions for all aspects of the mobile optimization plan. Each example includes proper error handling, TypeScript types, and integration with the existing architecture.