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