import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { supabase } from '@/lib/supabaseClient'; import { useAuth } from './useAuth'; import { useUserRole } from './useUserRole'; import { useToast } from './use-toast'; import { useCallback, useMemo } from 'react'; import type { Json } from '@/integrations/supabase/types'; import { handleError } from '@/lib/errorHandler'; interface AdminSetting { id: string; setting_key: string; setting_value: unknown; category: string; description: string; } export function useAdminSettings() { const { user } = useAuth(); const { isSuperuser } = useUserRole(); const { toast } = useToast(); const queryClient = useQueryClient(); const { data: settings, isLoading, error } = useQuery({ queryKey: ['admin-settings'], queryFn: async () => { const { data, error } = await supabase .from('admin_settings') .select('*') .order('category', { ascending: true }); if (error) throw error; return data as AdminSetting[]; }, enabled: !!user && isSuperuser() }); // Memoize settings into a stable map to prevent cascading re-renders const settingsMap = useMemo(() => { if (!settings) return {}; return Object.fromEntries( settings.map(s => [s.setting_key, s.setting_value]) ); }, [settings]); const updateSettingMutation = useMutation({ mutationFn: async ({ key, value }: { key: string; value: unknown }) => { const { error } = await supabase .from('admin_settings') .update({ setting_value: value as Json, updated_by: user?.id, updated_at: new Date().toISOString() }) .eq('setting_key', key); if (error) throw error; return { key, value }; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['admin-settings'] }); toast({ title: "Setting Updated", description: "The setting has been saved successfully.", }); }, onError: (error: Error, variables) => { handleError(error, { action: 'Update Admin Setting', userId: user?.id, metadata: { settingKey: variables.key, attemptedValue: variables.value } }); } }); const getSettingValue = useCallback((key: string, defaultValue: unknown = null) => { return settingsMap[key] ?? defaultValue; }, [settingsMap]); const updateSetting = async (key: string, value: unknown) => { return updateSettingMutation.mutateAsync({ key, value }); }; // Helper functions for common settings (memoized with useCallback for stable references) const getAutoFlagThreshold = useCallback(() => { return parseInt(String(getSettingValue('moderation.auto_flag_threshold', '3'))); }, [getSettingValue]); const getRequireApproval = useCallback(() => { const value = getSettingValue('moderation.require_approval', 'true'); return value === true || value === 'true'; }, [getSettingValue]); const getBanDurations = useCallback(() => { const value = getSettingValue('moderation.ban_durations', ['1d', '7d', '30d', 'permanent']); return Array.isArray(value) ? value : JSON.parse(String(value || '[]')); }, [getSettingValue]); const getEmailAlertsEnabled = useCallback(() => { const value = getSettingValue('notifications.email_alerts', 'true'); return value === true || value === 'true'; }, [getSettingValue]); const getReportThreshold = useCallback(() => { return parseInt(String(getSettingValue('notifications.report_threshold', '5'))); }, [getSettingValue]); const getAuditRetentionDays = useCallback(() => { return parseInt(String(getSettingValue('system.audit_retention_days', '365'))); }, [getSettingValue]); const getAutoCleanupEnabled = useCallback(() => { const value = getSettingValue('system.auto_cleanup', 'false'); return value === true || value === 'true'; }, [getSettingValue]); const getAdminPanelRefreshMode = useCallback((): 'auto' | 'manual' => { const value = getSettingValue('system.admin_panel_refresh_mode', 'auto'); // Remove quotes if they exist (JSON string stored in DB) const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : String(value); return (cleanValue === 'manual' ? 'manual' : 'auto') as 'auto' | 'manual'; }, [getSettingValue]); const getAdminPanelPollInterval = useCallback(() => { const value = getSettingValue('system.admin_panel_poll_interval', 30); return parseInt(value?.toString() || '30') * 1000; // Convert to milliseconds }, [getSettingValue]); /** * Get auto-refresh strategy setting * Returns: 'merge' | 'replace' | 'notify' */ const getAutoRefreshStrategy = useCallback((): 'merge' | 'replace' | 'notify' => { const value = getSettingValue('auto_refresh_strategy', 'merge'); const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : value; return cleanValue as 'merge' | 'replace' | 'notify'; }, [getSettingValue]); /** * Get preserve interaction state setting * Returns: boolean */ const getPreserveInteractionState = useCallback((): boolean => { const value = getSettingValue('preserve_interaction_state', 'true'); const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : value; return cleanValue === 'true' || cleanValue === true; }, [getSettingValue]); const getNotificationRecipients = useCallback(() => { return getSettingValue('notifications.recipients', []); }, [getSettingValue]); const getUseRealtimeQueue = useCallback((): boolean => { const value = getSettingValue('system.use_realtime_queue', 'true'); const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : value; return cleanValue === 'true' || cleanValue === true; }, [getSettingValue]); const getRefreshOnTabVisible = useCallback((): boolean => { const value = getSettingValue('system.refresh_on_tab_visible', 'false'); const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : value; return cleanValue === 'true' || cleanValue === true; }, [getSettingValue]); const getSetting = useCallback((key: string) => { return settings?.find(s => s.setting_key === key); }, [settings]); const getSettingsByCategory = useCallback((category: string) => { return settings?.filter(s => s.category === category) || []; }, [settings]); return useMemo(() => ({ settings, isLoading, error, updateSetting, isUpdating: updateSettingMutation.isPending, getSetting, getSettingValue, getSettingsByCategory, // Helper functions getAutoFlagThreshold, getRequireApproval, getBanDurations, getEmailAlertsEnabled, getNotificationRecipients, getReportThreshold, getAuditRetentionDays, getAutoCleanupEnabled, getAdminPanelRefreshMode, getAdminPanelPollInterval, getAutoRefreshStrategy, getPreserveInteractionState, getUseRealtimeQueue, getRefreshOnTabVisible, }), [ settings, isLoading, error, updateSetting, updateSettingMutation.isPending, getSetting, getSettingValue, getSettingsByCategory, getAutoFlagThreshold, getRequireApproval, getBanDurations, getEmailAlertsEnabled, getNotificationRecipients, getReportThreshold, getAuditRetentionDays, getAutoCleanupEnabled, getAdminPanelRefreshMode, getAdminPanelPollInterval, getAutoRefreshStrategy, getPreserveInteractionState, getUseRealtimeQueue, getRefreshOnTabVisible, ]); }