/** * Settings tab - notifications, app info * Server selection is handled via the global header selector */ import { View, ScrollView, Pressable, Switch, Alert, ActivityIndicator } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useRouter } from 'expo-router'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { ChevronRight, LogOut } from 'lucide-react-native'; import { useAuthStore } from '@/lib/authStore'; import { Text } from '@/components/ui/text'; import { Card } from '@/components/ui/card'; import { cn } from '@/lib/utils'; import { api } from '@/lib/api'; import { colors } from '@/lib/theme'; import Constants from 'expo-constants'; function SettingsRow({ label, value, onPress, showChevron, leftIcon, rightIcon, destructive, }: { label: string; value?: string; onPress?: () => void; showChevron?: boolean; leftIcon?: React.ReactNode; rightIcon?: React.ReactNode; destructive?: boolean; }) { const content = ( {leftIcon && {leftIcon}} {label} {value && {value}} {rightIcon} {showChevron && ( )} ); if (onPress) { return ( {content} ); } return content; } function SettingsToggle({ label, description, value, onValueChange, disabled, isLoading, }: { label: string; description?: string; value: boolean; onValueChange: (value: boolean) => void; disabled?: boolean; isLoading?: boolean; }) { return ( {label} {description && ( {description} )} {isLoading ? ( ) : ( )} ); } function SettingsSection({ title, children, }: { title: string; children: React.ReactNode; }) { return ( {title} {children} ); } function Divider() { return ; } export default function SettingsScreen() { const router = useRouter(); const queryClient = useQueryClient(); const { activeServerId, activeServer, isLoading: isAuthLoading, logout, } = useAuthStore(); const appVersion = Constants.expoConfig?.version || '1.0.0'; // Fetch notification preferences const { data: preferences, isLoading: isLoadingPrefs, error: prefsError, } = useQuery({ queryKey: ['notifications', 'preferences'], queryFn: api.notifications.getPreferences, staleTime: 1000 * 60, // 1 minute enabled: !!activeServerId, }); // Update mutation for quick toggle const updateMutation = useMutation({ mutationFn: api.notifications.updatePreferences, onMutate: async (newData) => { await queryClient.cancelQueries({ queryKey: ['notifications', 'preferences'], }); const previousData = queryClient.getQueryData([ 'notifications', 'preferences', ]); queryClient.setQueryData( ['notifications', 'preferences'], (old: typeof preferences) => (old ? { ...old, ...newData } : old) ); return { previousData }; }, onError: (_err, _newData, context) => { if (context?.previousData) { queryClient.setQueryData( ['notifications', 'preferences'], context.previousData ); } }, onSettled: () => { void queryClient.invalidateQueries({ queryKey: ['notifications', 'preferences'], }); }, }); const handleDisconnect = () => { Alert.alert( 'Disconnect from Server', 'Are you sure you want to disconnect? You will need to scan a QR code to reconnect.', [ { text: 'Cancel', style: 'cancel' }, { text: 'Disconnect', style: 'destructive', onPress: () => { void (async () => { await queryClient.cancelQueries(); await logout(); queryClient.clear(); })(); }, }, ] ); }; const handleTogglePush = (value: boolean) => { updateMutation.mutate({ pushEnabled: value }); }; const navigateToNotificationSettings = () => { router.push('/settings/notifications'); }; // Count enabled notification events for summary const enabledEventCount = preferences ? [ preferences.onViolationDetected, preferences.onStreamStarted, preferences.onStreamStopped, preferences.onConcurrentStreams, preferences.onNewDevice, preferences.onTrustScoreChanged, preferences.onServerDown, preferences.onServerUp, ].filter(Boolean).length : 0; return ( {/* Connected Server Info */} {activeServer && ( } destructive /> )} {/* Notification Settings */} {activeServerId && ( {prefsError ? ( Failed to load notification settings ) : ( <> Configure which events trigger notifications, quiet hours, and filters. )} )} {/* App Info */} {/* Loading indicator */} {isAuthLoading && ( )} ); }