import { useState, useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { Button } from '@/components/ui/button'; import { Label } from '@/components/ui/label'; import { Switch } from '@/components/ui/switch'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Separator } from '@/components/ui/separator'; import { handleError, handleSuccess, AppError } from '@/lib/errorHandler'; import { logger } from '@/lib/logger'; import { useAuth } from '@/hooks/useAuth'; import { useProfile } from '@/hooks/useProfile'; import { supabase } from '@/integrations/supabase/client'; import { Eye, UserX, Shield, Search } from 'lucide-react'; import { BlockedUsers } from '@/components/privacy/BlockedUsers'; import type { PrivacySettings, PrivacyFormData } from '@/types/privacy'; import { privacyFormSchema, privacySettingsSchema, DEFAULT_PRIVACY_SETTINGS } from '@/lib/privacyValidation'; import { z } from 'zod'; export function PrivacyTab() { const { user } = useAuth(); const { data: profile, refreshProfile } = useProfile(user?.id); const [loading, setLoading] = useState(false); const [preferences, setPreferences] = useState(null); const form = useForm({ resolver: zodResolver(privacyFormSchema), defaultValues: { privacy_level: (profile?.privacy_level === 'public' || profile?.privacy_level === 'private') ? profile.privacy_level : 'public', show_pronouns: profile?.show_pronouns || false, ...DEFAULT_PRIVACY_SETTINGS } }); useEffect(() => { fetchPreferences(); }, [user]); const fetchPreferences = async () => { if (!user) return; try { const { data, error } = await supabase .from('user_preferences') .select('privacy_settings') .eq('user_id', user.id) .maybeSingle(); if (error && error.code !== 'PGRST116') { logger.error('Failed to fetch privacy preferences', { userId: user.id, action: 'fetch_privacy_preferences', error: error.message, errorCode: error.code }); throw error; } if (data?.privacy_settings) { const parseResult = privacySettingsSchema.safeParse(data.privacy_settings); if (parseResult.success) { setPreferences(parseResult.data); form.reset({ privacy_level: (profile?.privacy_level === 'public' || profile?.privacy_level === 'private') ? profile.privacy_level : 'public', show_pronouns: profile?.show_pronouns || false, ...parseResult.data }); } else { console.warn('Invalid privacy settings, reinitializing with defaults', { errors: parseResult.error.issues }); await initializePreferences(); } } else { await initializePreferences(); } } catch (error) { logger.error('Error fetching privacy preferences', { userId: user.id, action: 'fetch_privacy_preferences', error: error instanceof Error ? error.message : String(error) }); handleError(error, { action: 'Load privacy settings', userId: user.id }); } }; const initializePreferences = async () => { if (!user) return; try { const { error } = await supabase .from('user_preferences') .insert([{ user_id: user.id, privacy_settings: DEFAULT_PRIVACY_SETTINGS }]); if (error) { logger.error('Failed to initialize privacy preferences', { userId: user.id, action: 'initialize_privacy_preferences', error: error.message }); throw error; } setPreferences(DEFAULT_PRIVACY_SETTINGS); form.reset({ privacy_level: (profile?.privacy_level === 'public' || profile?.privacy_level === 'private') ? profile.privacy_level : 'public', show_pronouns: profile?.show_pronouns || false, ...DEFAULT_PRIVACY_SETTINGS }); } catch (error) { logger.error('Error initializing privacy preferences', { userId: user.id, action: 'initialize_privacy_preferences', error: error instanceof Error ? error.message : String(error) }); handleError(error, { action: 'Initialize privacy settings', userId: user.id }); } }; const onSubmit = async (data: PrivacyFormData) => { if (!user) return; setLoading(true); try { // Validate the form data const validated = privacyFormSchema.parse(data); // Update profile privacy settings const { error: profileError } = await supabase .from('profiles') .update({ privacy_level: validated.privacy_level, show_pronouns: validated.show_pronouns, updated_at: new Date().toISOString() }) .eq('user_id', user.id); if (profileError) { logger.error('Failed to update profile privacy', { userId: user.id, action: 'update_profile_privacy', error: profileError.message, errorCode: profileError.code }); throw profileError; } // Extract privacy settings (exclude profile fields) const { privacy_level, show_pronouns, ...privacySettings } = validated; // Update user preferences const { error: prefsError } = await supabase .from('user_preferences') .upsert([{ user_id: user.id, privacy_settings: privacySettings, updated_at: new Date().toISOString() }]); if (prefsError) { logger.error('Failed to update privacy preferences', { userId: user.id, action: 'update_privacy_preferences', error: prefsError.message, errorCode: prefsError.code }); throw prefsError; } // Log to audit trail await supabase.from('profile_audit_log').insert([{ user_id: user.id, changed_by: user.id, action: 'privacy_settings_updated', changes: { previous: preferences, updated: privacySettings, timestamp: new Date().toISOString() } as any }]); await refreshProfile(); setPreferences(privacySettings); logger.info('Privacy settings updated successfully', { userId: user.id, action: 'update_privacy_settings' }); handleSuccess( 'Privacy settings updated', 'Your privacy preferences have been successfully saved.' ); } catch (error) { logger.error('Failed to update privacy settings', { userId: user.id, action: 'update_privacy_settings', error: error instanceof Error ? error.message : String(error) }); if (error instanceof z.ZodError) { handleError( new AppError( 'Invalid privacy settings', 'VALIDATION_ERROR', error.issues.map(e => e.message).join(', ') ), { action: 'Validate privacy settings', userId: user.id } ); } else { handleError(error, { action: 'Update privacy settings', userId: user.id }); } } finally { setLoading(false); } }; return (
{/* Profile Visibility + Activity & Content Grid */}
{/* Profile Visibility */}
Profile Visibility
Control who can see your profile and personal information.

Display your preferred pronouns on your profile

form.setValue('show_pronouns', checked)} />

Display your location on your profile

form.setValue('show_location', checked)} />

Display your birth date on your profile

form.setValue('show_age', checked)} />

Display your profile picture

form.setValue('show_avatar', checked)} />

Display your profile bio/description

form.setValue('show_bio', checked)} />

Display your ride counts and park visits

form.setValue('show_activity_stats', checked)} />

Display your home park preference

form.setValue('show_home_park', checked)} />
{/* Activity & Content */}
Activity & Content
Control the visibility of your activities and content.

This affects the visibility of your reviews, ride credits, and top lists.

{/* Search & Discovery */}
Search & Discovery
Control how others can find and discover your profile.

Allow your profile to appear in search results

form.setValue('search_visibility', checked)} />
{/* Blocked Users */}
Blocked Users
Manage users you have blocked from interacting with you.
{/* Save Button */}
); }