fix: before admin stations removal
This commit is contained in:
13
frontend/src/features/settings/api/preferences.api.ts
Normal file
13
frontend/src/features/settings/api/preferences.api.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @ai-summary API client for user preferences endpoints
|
||||
* @ai-context Handles unit system, currency, and timezone preferences sync
|
||||
*/
|
||||
|
||||
import { apiClient } from '../../../core/api/client';
|
||||
import { UserPreferences, UpdatePreferencesRequest } from '../types/preferences.types';
|
||||
|
||||
export const preferencesApi = {
|
||||
getPreferences: () => apiClient.get<UserPreferences>('/user/preferences'),
|
||||
updatePreferences: (data: UpdatePreferencesRequest) =>
|
||||
apiClient.put<UserPreferences>('/user/preferences', data),
|
||||
};
|
||||
61
frontend/src/features/settings/hooks/usePreferences.ts
Normal file
61
frontend/src/features/settings/hooks/usePreferences.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @ai-summary React hooks for user preferences management
|
||||
* @ai-context Handles unit system, currency, and timezone preference sync with backend
|
||||
*/
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useAuth0 } from '@auth0/auth0-react';
|
||||
import { preferencesApi } from '../api/preferences.api';
|
||||
import { UpdatePreferencesRequest } from '../types/preferences.types';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
interface ApiError {
|
||||
response?: {
|
||||
data?: {
|
||||
error?: string;
|
||||
message?: string;
|
||||
};
|
||||
};
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export const usePreferences = () => {
|
||||
const { isAuthenticated, isLoading } = useAuth0();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ['user-preferences'],
|
||||
queryFn: async () => {
|
||||
const response = await preferencesApi.getPreferences();
|
||||
return response.data;
|
||||
},
|
||||
enabled: isAuthenticated && !isLoading,
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||
gcTime: 10 * 60 * 1000, // 10 minutes cache time
|
||||
retry: (failureCount, error: any) => {
|
||||
// Retry 401s a few times (auth token might be refreshing)
|
||||
if (error?.response?.status === 401 && failureCount < 3) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnMount: false,
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdatePreferences = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (data: UpdatePreferencesRequest) => preferencesApi.updatePreferences(data),
|
||||
onSuccess: (response) => {
|
||||
queryClient.setQueryData(['user-preferences'], response.data);
|
||||
// Don't show toast for unit system changes - context handles UI feedback
|
||||
},
|
||||
onError: (error: ApiError) => {
|
||||
const message = error.response?.data?.message || error.response?.data?.error || 'Failed to update preferences';
|
||||
toast.error(message);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useSettingsPersistence, SettingsState } from './useSettingsPersistence';
|
||||
import { useUnits } from '../../../core/units/UnitsContext';
|
||||
|
||||
const defaultSettings: SettingsState = {
|
||||
darkMode: false,
|
||||
@@ -13,10 +14,12 @@ const defaultSettings: SettingsState = {
|
||||
|
||||
export const useSettings = () => {
|
||||
const { loadSettings, saveSettings } = useSettingsPersistence();
|
||||
const { unitSystem: contextUnitSystem, setUnitSystem: setContextUnitSystem } = useUnits();
|
||||
const [settings, setSettings] = useState<SettingsState>(defaultSettings);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// Load settings from localStorage on mount
|
||||
useEffect(() => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
@@ -33,6 +36,13 @@ export const useSettings = () => {
|
||||
}
|
||||
}, [loadSettings]);
|
||||
|
||||
// Sync unitSystem from context (which may load from backend)
|
||||
useEffect(() => {
|
||||
if (contextUnitSystem && contextUnitSystem !== settings.unitSystem) {
|
||||
setSettings(prev => ({ ...prev, unitSystem: contextUnitSystem }));
|
||||
}
|
||||
}, [contextUnitSystem, settings.unitSystem]);
|
||||
|
||||
const updateSetting = <K extends keyof SettingsState>(
|
||||
key: K,
|
||||
value: SettingsState[K]
|
||||
@@ -42,6 +52,11 @@ export const useSettings = () => {
|
||||
const newSettings = { ...settings, [key]: value };
|
||||
setSettings(newSettings);
|
||||
saveSettings(newSettings);
|
||||
|
||||
// Sync unitSystem changes to context (which syncs to backend)
|
||||
if (key === 'unitSystem' && typeof value === 'string') {
|
||||
setContextUnitSystem(value as 'imperial' | 'metric');
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to save settings');
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ export const MobileSettingsScreen: React.FC = () => {
|
||||
<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'}
|
||||
Currently using {settings.unitSystem === 'imperial' ? 'Miles, Gallons, MPG, USD' : 'Km, Liters, L/100km, EUR'}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
|
||||
22
frontend/src/features/settings/types/preferences.types.ts
Normal file
22
frontend/src/features/settings/types/preferences.types.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @ai-summary Type definitions for user preferences
|
||||
* @ai-context Types for unit system, currency, and timezone preferences
|
||||
*/
|
||||
|
||||
import { UnitSystem } from '../../../core/units/units.types';
|
||||
|
||||
export interface UserPreferences {
|
||||
id: string;
|
||||
userId: string;
|
||||
unitSystem: UnitSystem;
|
||||
currencyCode: string;
|
||||
timeZone: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface UpdatePreferencesRequest {
|
||||
unitSystem?: UnitSystem;
|
||||
currencyCode?: string;
|
||||
timeZone?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user