Mobile Work

This commit is contained in:
Eric Gullickson
2025-09-19 11:33:31 -05:00
parent 040da4c759
commit 3588372cef
7 changed files with 189 additions and 13 deletions

View File

@@ -1,5 +1,6 @@
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import { safeStorage } from '../utils/safe-storage';
export type MobileScreen = 'Dashboard' | 'Vehicles' | 'Log Fuel' | 'Settings';
export type VehicleSubScreen = 'list' | 'detail' | 'add' | 'edit';
@@ -193,13 +194,20 @@ export const useNavigationStore = create<NavigationState>()(
}),
{
name: 'motovaultpro-mobile-navigation',
storage: createJSONStorage(() => localStorage),
storage: createJSONStorage(() => safeStorage),
partialize: (state) => ({
activeScreen: state.activeScreen,
vehicleSubScreen: state.vehicleSubScreen,
selectedVehicleId: state.selectedVehicleId,
formStates: state.formStates,
}),
onRehydrateStorage: () => (state) => {
if (state) {
console.log('[Navigation] State rehydrated successfully');
} else {
console.warn('[Navigation] State rehydration failed, using defaults');
}
},
}
)
);

View File

@@ -5,6 +5,7 @@
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import { UnitSystem, UnitPreferences } from './units.types';
import { safeStorage } from '../utils/safe-storage';
import {
formatDistanceBySystem,
formatVolumeBySystem,
@@ -48,18 +49,26 @@ export const UnitsProvider: React.FC<UnitsProviderProps> = ({
}) => {
const [unitSystem, setUnitSystem] = useState<UnitSystem>(initialSystem);
// Load unit preference from localStorage on mount
// Load unit preference from storage on mount
useEffect(() => {
const stored = localStorage.getItem('motovaultpro-unit-system');
if (stored === 'imperial' || stored === 'metric') {
setUnitSystem(stored);
try {
const stored = safeStorage.getItem('motovaultpro-unit-system');
if (stored === 'imperial' || stored === 'metric') {
setUnitSystem(stored);
}
} catch (error) {
console.warn('[Units] Failed to load unit system preference:', error);
}
}, []);
// Save unit preference to localStorage when changed
// Save unit preference to storage when changed
const handleSetUnitSystem = (system: UnitSystem) => {
setUnitSystem(system);
localStorage.setItem('motovaultpro-unit-system', system);
try {
safeStorage.setItem('motovaultpro-unit-system', system);
} catch (error) {
console.warn('[Units] Failed to save unit system preference:', error);
}
};
// Generate preferences object based on current system

View File

@@ -0,0 +1,107 @@
/**
* @ai-summary Safe localStorage wrapper for mobile browsers
* @ai-context Prevents errors when localStorage is blocked in mobile browsers
*/
// Safe localStorage wrapper that won't crash on mobile browsers
const createSafeStorage = () => {
let isAvailable = false;
// Test localStorage availability
try {
const testKey = '__motovaultpro_storage_test__';
localStorage.setItem(testKey, 'test');
localStorage.removeItem(testKey);
isAvailable = true;
} catch (error) {
console.warn('[Storage] localStorage not available, using memory fallback:', error);
isAvailable = false;
}
// Memory fallback when localStorage is blocked
const memoryStorage = new Map<string, string>();
return {
getItem: (key: string): string | null => {
try {
if (isAvailable) {
return localStorage.getItem(key);
} else {
return memoryStorage.get(key) || null;
}
} catch (error) {
console.warn('[Storage] getItem failed, using memory fallback:', error);
return memoryStorage.get(key) || null;
}
},
setItem: (key: string, value: string): void => {
try {
if (isAvailable) {
localStorage.setItem(key, value);
} else {
memoryStorage.set(key, value);
}
} catch (error) {
console.warn('[Storage] setItem failed, using memory fallback:', error);
memoryStorage.set(key, value);
}
},
removeItem: (key: string): void => {
try {
if (isAvailable) {
localStorage.removeItem(key);
} else {
memoryStorage.delete(key);
}
} catch (error) {
console.warn('[Storage] removeItem failed, using memory fallback:', error);
memoryStorage.delete(key);
}
},
// For zustand createJSONStorage compatibility
key: (index: number): string | null => {
try {
if (isAvailable) {
return localStorage.key(index);
} else {
const keys = Array.from(memoryStorage.keys());
return keys[index] || null;
}
} catch (error) {
console.warn('[Storage] key access failed:', error);
return null;
}
},
get length(): number {
try {
if (isAvailable) {
return localStorage.length;
} else {
return memoryStorage.size;
}
} catch (error) {
console.warn('[Storage] length access failed:', error);
return 0;
}
},
clear: (): void => {
try {
if (isAvailable) {
localStorage.clear();
} else {
memoryStorage.clear();
}
} catch (error) {
console.warn('[Storage] clear failed:', error);
memoryStorage.clear();
}
}
};
};
export const safeStorage = createSafeStorage();