Visual edit in Lovable

This commit is contained in:
gpt-engineer-app[bot]
2025-09-28 20:21:46 +00:00
parent 3457bca7cf
commit c337aac428

View File

@@ -13,25 +13,27 @@ import { useToast } from '@/hooks/use-toast';
import { useAuth } from '@/hooks/useAuth';
import { supabase } from '@/integrations/supabase/client';
import { MapPin, Calendar, Globe, Accessibility } from 'lucide-react';
const locationSchema = z.object({
preferred_pronouns: z.string().max(20).optional(),
timezone: z.string(),
preferred_language: z.string(),
location_id: z.string().optional()
});
type LocationFormData = z.infer<typeof locationSchema>;
interface AccessibilityOptions {
font_size: 'small' | 'medium' | 'large';
high_contrast: boolean;
reduced_motion: boolean;
}
export function LocationTab() {
const { user, profile, refreshProfile } = useAuth();
const { toast } = useToast();
const {
user,
profile,
refreshProfile
} = useAuth();
const {
toast
} = useToast();
const [loading, setLoading] = useState(false);
const [locations, setLocations] = useState<any[]>([]);
const [accessibility, setAccessibility] = useState<AccessibilityOptions>({
@@ -39,7 +41,6 @@ export function LocationTab() {
high_contrast: false,
reduced_motion: false
});
const form = useForm<LocationFormData>({
resolver: zodResolver(locationSchema),
defaultValues: {
@@ -49,41 +50,33 @@ export function LocationTab() {
location_id: profile?.location_id || ''
}
});
useEffect(() => {
fetchLocations();
fetchAccessibilityPreferences();
}, [user]);
const fetchLocations = async () => {
try {
const { data, error } = await supabase
.from('locations')
.select('id, name, city, state_province, country')
.order('name');
const {
data,
error
} = await supabase.from('locations').select('id, name, city, state_province, country').order('name');
if (error) throw error;
setLocations(data || []);
} catch (error) {
console.error('Error fetching locations:', error);
}
};
const fetchAccessibilityPreferences = async () => {
if (!user) return;
try {
const { data, error } = await supabase
.from('user_preferences')
.select('accessibility_options')
.eq('user_id', user.id)
.maybeSingle();
const {
data,
error
} = await supabase.from('user_preferences').select('accessibility_options').eq('user_id', user.id).maybeSingle();
if (error && error.code !== 'PGRST116') {
console.error('Error fetching accessibility preferences:', error);
return;
}
if (data?.accessibility_options) {
setAccessibility(data.accessibility_options as any);
}
@@ -91,25 +84,20 @@ export function LocationTab() {
console.error('Error fetching accessibility preferences:', error);
}
};
const onSubmit = async (data: LocationFormData) => {
if (!user) return;
setLoading(true);
try {
const { error } = await supabase
.from('profiles')
.update({
preferred_pronouns: data.preferred_pronouns || null,
timezone: data.timezone,
preferred_language: data.preferred_language,
location_id: data.location_id || null,
updated_at: new Date().toISOString()
})
.eq('user_id', user.id);
const {
error
} = await supabase.from('profiles').update({
preferred_pronouns: data.preferred_pronouns || null,
timezone: data.timezone,
preferred_language: data.preferred_language,
location_id: data.location_id || null,
updated_at: new Date().toISOString()
}).eq('user_id', user.id);
if (error) throw error;
await refreshProfile();
toast({
title: 'Information updated',
@@ -125,21 +113,17 @@ export function LocationTab() {
setLoading(false);
}
};
const saveAccessibilityPreferences = async () => {
if (!user) return;
try {
const { error } = await supabase
.from('user_preferences')
.upsert([{
user_id: user.id,
accessibility_options: accessibility as any,
updated_at: new Date().toISOString()
}]);
const {
error
} = await supabase.from('user_preferences').upsert([{
user_id: user.id,
accessibility_options: accessibility as any,
updated_at: new Date().toISOString()
}]);
if (error) throw error;
toast({
title: 'Accessibility preferences saved',
description: 'Your accessibility settings have been updated.'
@@ -152,28 +136,14 @@ export function LocationTab() {
});
}
};
const updateAccessibility = (key: keyof AccessibilityOptions, value: any) => {
setAccessibility(prev => ({ ...prev, [key]: value }));
setAccessibility(prev => ({
...prev,
[key]: value
}));
};
const timezones = [
'UTC',
'America/New_York',
'America/Chicago',
'America/Denver',
'America/Los_Angeles',
'America/Toronto',
'Europe/London',
'Europe/Berlin',
'Europe/Paris',
'Asia/Tokyo',
'Asia/Shanghai',
'Australia/Sydney'
];
return (
<div className="space-y-8">
const timezones = ['UTC', 'America/New_York', 'America/Chicago', 'America/Denver', 'America/Los_Angeles', 'America/Toronto', 'Europe/London', 'Europe/Berlin', 'Europe/Paris', 'Asia/Tokyo', 'Asia/Shanghai', 'Australia/Sydney'];
return <div className="space-y-8">
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
{/* Location Settings */}
<div className="space-y-4">
@@ -191,22 +161,17 @@ export function LocationTab() {
<CardContent className="space-y-6">
<div className="space-y-2">
<Label htmlFor="location_id">Home Location</Label>
<Select
value={form.watch('location_id')}
onValueChange={(value) => form.setValue('location_id', value)}
>
<Select value={form.watch('location_id')} onValueChange={value => form.setValue('location_id', value)}>
<SelectTrigger>
<SelectValue placeholder="Select your location" />
</SelectTrigger>
<SelectContent>
{locations.map((location) => (
<SelectItem key={location.id} value={location.id}>
{locations.map(location => <SelectItem key={location.id} value={location.id}>
{location.name}
{location.city && `, ${location.city}`}
{location.state_province && `, ${location.state_province}`}
{location.country && `, ${location.country}`}
</SelectItem>
))}
</SelectItem>)}
</SelectContent>
</Select>
<p className="text-sm text-muted-foreground">
@@ -216,19 +181,14 @@ export function LocationTab() {
<div className="space-y-2">
<Label htmlFor="timezone">Timezone</Label>
<Select
value={form.watch('timezone')}
onValueChange={(value) => form.setValue('timezone', value)}
>
<Select value={form.watch('timezone')} onValueChange={value => form.setValue('timezone', value)}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
{timezones.map((tz) => (
<SelectItem key={tz} value={tz}>
{timezones.map(tz => <SelectItem key={tz} value={tz}>
{tz}
</SelectItem>
))}
</SelectItem>)}
</SelectContent>
</Select>
<p className="text-sm text-muted-foreground">
@@ -258,34 +218,13 @@ export function LocationTab() {
<div className="space-y-2">
<Label htmlFor="preferred_pronouns">Preferred Pronouns</Label>
<Input
id="preferred_pronouns"
{...form.register('preferred_pronouns')}
placeholder="e.g., they/them, she/her, he/him"
/>
<Input id="preferred_pronouns" {...form.register('preferred_pronouns')} placeholder="e.g., they/them, she/her, he/him" />
<p className="text-sm text-muted-foreground">
How you'd like others to refer to you.
</p>
</div>
<div className="space-y-2">
<Label htmlFor="preferred_language">Preferred Language</Label>
<Select
value={form.watch('preferred_language')}
onValueChange={(value) => form.setValue('preferred_language', value)}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="en">English</SelectItem>
<SelectItem value="es">Español</SelectItem>
<SelectItem value="fr">Français</SelectItem>
<SelectItem value="de">Deutsch</SelectItem>
<SelectItem value="it">Italiano</SelectItem>
</SelectContent>
</Select>
</div>
</CardContent>
</Card>
</div>
@@ -297,7 +236,7 @@ export function LocationTab() {
</div>
</form>
<Separator />
{/* Accessibility Options */}
<div className="space-y-4">
@@ -315,12 +254,7 @@ export function LocationTab() {
<CardContent className="space-y-6">
<div className="space-y-3">
<Label>Font Size</Label>
<Select
value={accessibility.font_size}
onValueChange={(value: 'small' | 'medium' | 'large') =>
updateAccessibility('font_size', value)
}
>
<Select value={accessibility.font_size} onValueChange={(value: 'small' | 'medium' | 'large') => updateAccessibility('font_size', value)}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
@@ -339,10 +273,7 @@ export function LocationTab() {
Increase contrast for better visibility
</p>
</div>
<Switch
checked={accessibility.high_contrast}
onCheckedChange={(checked) => updateAccessibility('high_contrast', checked)}
/>
<Switch checked={accessibility.high_contrast} onCheckedChange={checked => updateAccessibility('high_contrast', checked)} />
</div>
<div className="flex items-center justify-between">
@@ -352,10 +283,7 @@ export function LocationTab() {
Minimize animations and transitions
</p>
</div>
<Switch
checked={accessibility.reduced_motion}
onCheckedChange={(checked) => updateAccessibility('reduced_motion', checked)}
/>
<Switch checked={accessibility.reduced_motion} onCheckedChange={checked => updateAccessibility('reduced_motion', checked)} />
</div>
<div className="flex justify-end">
@@ -366,6 +294,5 @@ export function LocationTab() {
</CardContent>
</Card>
</div>
</div>
);
</div>;
}