Add unit preferences to user settings

This commit is contained in:
gpt-engineer-app[bot]
2025-09-28 21:26:09 +00:00
parent 93278a5f24
commit 8f13796567
10 changed files with 451 additions and 13 deletions

View File

@@ -11,8 +11,9 @@ import { Separator } from '@/components/ui/separator';
import { Switch } from '@/components/ui/switch';
import { useToast } from '@/hooks/use-toast';
import { useAuth } from '@/hooks/useAuth';
import { useUnitPreferences } from '@/hooks/useUnitPreferences';
import { supabase } from '@/integrations/supabase/client';
import { MapPin, Calendar, Globe, Accessibility } from 'lucide-react';
import { MapPin, Calendar, Globe, Accessibility, Ruler } from 'lucide-react';
const locationSchema = z.object({
preferred_pronouns: z.string().max(20).optional(),
timezone: z.string(),
@@ -35,6 +36,7 @@ export function LocationTab() {
const {
toast
} = useToast();
const { preferences: unitPreferences, updatePreferences: updateUnitPreferences } = useUnitPreferences();
const [loading, setLoading] = useState(false);
const [parks, setParks] = useState<any[]>([]);
const [accessibility, setAccessibility] = useState<AccessibilityOptions>({
@@ -115,10 +117,13 @@ export function LocationTab() {
if (accessibilityError) throw accessibilityError;
// Save unit preferences
await updateUnitPreferences(unitPreferences);
await refreshProfile();
toast({
title: 'Settings saved',
description: 'Your location, personal information, and accessibility settings have been updated.'
description: 'Your location, personal information, accessibility, and unit preferences have been updated.'
});
} catch (error: any) {
toast({
@@ -243,6 +248,58 @@ export function LocationTab() {
<Separator />
{/* Unit Preferences */}
<div className="space-y-4">
<div className="flex items-center gap-2">
<Ruler className="w-5 h-5" />
<h3 className="text-lg font-medium">Units & Measurements</h3>
</div>
<Card>
<CardHeader>
<CardDescription>
Choose your preferred measurement system for displaying distances, speeds, and other measurements.
</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<div className="space-y-3">
<Label>Measurement System</Label>
<Select
value={unitPreferences.measurement_system}
onValueChange={(value: 'metric' | 'imperial') =>
updateUnitPreferences({ measurement_system: value })
}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="metric">Metric (km/h, meters, cm)</SelectItem>
<SelectItem value="imperial">Imperial (mph, feet, inches)</SelectItem>
</SelectContent>
</Select>
</div>
<div className="flex items-center justify-between">
<div className="space-y-1">
<Label>Auto-detect from location</Label>
<p className="text-sm text-muted-foreground">
Automatically set measurement system based on your location when you first visit
</p>
</div>
<Switch
checked={unitPreferences.auto_detect}
onCheckedChange={(checked) =>
updateUnitPreferences({ auto_detect: checked })
}
/>
</div>
</CardContent>
</Card>
</div>
<Separator />
{/* Accessibility Options */}
<div className="space-y-4">
<div className="flex items-center gap-2">

View File

@@ -0,0 +1,100 @@
import { useMemo } from 'react';
import { useAuth } from '@/hooks/useAuth';
import {
convertSpeed,
convertDistance,
convertHeight,
getSpeedUnit,
getDistanceUnit,
getHeightUnit,
getShortDistanceUnit,
type MeasurementSystem,
type UnitPreferences
} from '@/lib/units';
interface MeasurementDisplayProps {
value: number;
type: 'speed' | 'distance' | 'height' | 'short_distance';
showBothUnits?: boolean;
className?: string;
}
export function MeasurementDisplay({
value,
type,
showBothUnits = false,
className = ""
}: MeasurementDisplayProps) {
const { profile } = useAuth();
const unitPreferences = useMemo(() => {
// Get unit preferences from user profile or default to metric
const defaultPrefs: UnitPreferences = {
measurement_system: 'metric',
temperature: 'celsius',
auto_detect: true
};
// If no profile or no preferences, use default
if (!profile) return defaultPrefs;
// Try to get preferences from profile (this will be populated from user_preferences)
const storedPrefs = (profile as any)?.unit_preferences;
if (storedPrefs && typeof storedPrefs === 'object') {
return { ...defaultPrefs, ...storedPrefs };
}
return defaultPrefs;
}, [profile]);
const { displayValue, unit, alternateDisplay } = useMemo(() => {
const system = unitPreferences.measurement_system;
let displayValue: number;
let unit: string;
let alternateValue: number;
let alternateUnit: string;
switch (type) {
case 'speed':
displayValue = convertSpeed(value, system);
unit = getSpeedUnit(system);
alternateValue = convertSpeed(value, system === 'metric' ? 'imperial' : 'metric');
alternateUnit = getSpeedUnit(system === 'metric' ? 'imperial' : 'metric');
break;
case 'distance':
displayValue = convertDistance(value, system);
unit = getDistanceUnit(system);
alternateValue = convertDistance(value, system === 'metric' ? 'imperial' : 'metric');
alternateUnit = getDistanceUnit(system === 'metric' ? 'imperial' : 'metric');
break;
case 'height':
displayValue = convertHeight(value, system);
unit = getHeightUnit(system);
alternateValue = convertHeight(value, system === 'metric' ? 'imperial' : 'metric');
alternateUnit = getHeightUnit(system === 'metric' ? 'imperial' : 'metric');
break;
case 'short_distance':
displayValue = convertDistance(value, system);
unit = getShortDistanceUnit(system);
alternateValue = convertDistance(value, system === 'metric' ? 'imperial' : 'metric');
alternateUnit = getShortDistanceUnit(system === 'metric' ? 'imperial' : 'metric');
break;
default:
displayValue = value;
unit = '';
alternateValue = value;
alternateUnit = '';
}
const alternateDisplay = showBothUnits ? ` (${alternateValue} ${alternateUnit})` : '';
return { displayValue, unit, alternateDisplay };
}, [value, type, unitPreferences.measurement_system, showBothUnits]);
return (
<span className={className} title={showBothUnits ? undefined : alternateDisplay ? `${alternateValue} ${alternateUnit}` : undefined}>
{displayValue} {unit}{alternateDisplay}
</span>
);
}