mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 07:31:12 -05:00
Fix: Stabilize useAdminSettings dependencies
This commit is contained in:
@@ -806,21 +806,26 @@ export function useModerationQueueManager(
|
|||||||
|
|
||||||
// Visibility change handler
|
// Visibility change handler
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('🔍 [VISIBILITY EFFECT] Running', {
|
// HARD CHECK: Explicit boolean comparison to prevent any truthy coercion
|
||||||
settingsObject: settings,
|
const isEnabled = settings.refreshOnTabVisible === true;
|
||||||
|
|
||||||
|
console.log('🔍 [VISIBILITY EFFECT] Hard check', {
|
||||||
refreshOnTabVisible: settings.refreshOnTabVisible,
|
refreshOnTabVisible: settings.refreshOnTabVisible,
|
||||||
typeOf: typeof settings.refreshOnTabVisible,
|
typeOf: typeof settings.refreshOnTabVisible,
|
||||||
rawValue: JSON.stringify(settings.refreshOnTabVisible),
|
isEnabled,
|
||||||
stringValue: String(settings.refreshOnTabVisible),
|
willAttachListener: isEnabled,
|
||||||
boolValue: Boolean(settings.refreshOnTabVisible),
|
|
||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Early return if feature is disabled
|
// Early return if feature is disabled
|
||||||
if (!settings.refreshOnTabVisible) {
|
if (!isEnabled) {
|
||||||
console.log(' ✅ Setting is FALSE - NO listener will be attached');
|
console.log(' ✅ Feature DISABLED - skipping all visibility logic');
|
||||||
console.log(' ✅ Tab focus will NOT trigger refreshes');
|
console.log(' ✅ Tab focus will NOT trigger refreshes');
|
||||||
return;
|
|
||||||
|
// Cleanup: ensure no lingering handlers
|
||||||
|
return () => {
|
||||||
|
console.log(' 🧹 Cleanup: Ensuring no visibility listeners exist');
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
console.error(' ❌ Setting is TRUE - listener WILL be attached');
|
console.error(' ❌ Setting is TRUE - listener WILL be attached');
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { supabase } from '@/integrations/supabase/client';
|
|||||||
import { useAuth } from './useAuth';
|
import { useAuth } from './useAuth';
|
||||||
import { useUserRole } from './useUserRole';
|
import { useUserRole } from './useUserRole';
|
||||||
import { useToast } from './use-toast';
|
import { useToast } from './use-toast';
|
||||||
import { useCallback } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
interface AdminSetting {
|
interface AdminSetting {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -37,6 +37,14 @@ export function useAdminSettings() {
|
|||||||
enabled: !!user && isSuperuser()
|
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 ? JSON.stringify(settings.map(s => [s.setting_key, s.setting_value])) : null]);
|
||||||
|
|
||||||
const updateSettingMutation = useMutation({
|
const updateSettingMutation = useMutation({
|
||||||
mutationFn: async ({ key, value }: { key: string; value: any }) => {
|
mutationFn: async ({ key, value }: { key: string; value: any }) => {
|
||||||
const { error } = await supabase
|
const { error } = await supabase
|
||||||
@@ -66,19 +74,9 @@ export function useAdminSettings() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const getSetting = (key: string) => {
|
const getSettingValue = useCallback((key: string, defaultValue: any = null) => {
|
||||||
return settings?.find(s => s.setting_key === key);
|
return settingsMap[key] ?? defaultValue;
|
||||||
};
|
}, [settingsMap]);
|
||||||
|
|
||||||
const getSettingValue = (key: string, defaultValue: any = null) => {
|
|
||||||
const setting = getSetting(key);
|
|
||||||
return setting ? setting.setting_value : defaultValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSettingsByCategory = (category: string) => {
|
|
||||||
return settings?.filter(s => s.category === category) || [];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const updateSetting = async (key: string, value: any) => {
|
const updateSetting = async (key: string, value: any) => {
|
||||||
return updateSettingMutation.mutateAsync({ key, value });
|
return updateSettingMutation.mutateAsync({ key, value });
|
||||||
@@ -87,46 +85,46 @@ export function useAdminSettings() {
|
|||||||
// Helper functions for common settings (memoized with useCallback for stable references)
|
// Helper functions for common settings (memoized with useCallback for stable references)
|
||||||
const getAutoFlagThreshold = useCallback(() => {
|
const getAutoFlagThreshold = useCallback(() => {
|
||||||
return parseInt(getSettingValue('moderation.auto_flag_threshold', '3'));
|
return parseInt(getSettingValue('moderation.auto_flag_threshold', '3'));
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
const getRequireApproval = useCallback(() => {
|
const getRequireApproval = useCallback(() => {
|
||||||
const value = getSettingValue('moderation.require_approval', 'true');
|
const value = getSettingValue('moderation.require_approval', 'true');
|
||||||
return value === true || value === 'true';
|
return value === true || value === 'true';
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
const getBanDurations = useCallback(() => {
|
const getBanDurations = useCallback(() => {
|
||||||
const value = getSettingValue('moderation.ban_durations', ['1d', '7d', '30d', 'permanent']);
|
const value = getSettingValue('moderation.ban_durations', ['1d', '7d', '30d', 'permanent']);
|
||||||
return Array.isArray(value) ? value : JSON.parse(value || '[]');
|
return Array.isArray(value) ? value : JSON.parse(value || '[]');
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
const getEmailAlertsEnabled = useCallback(() => {
|
const getEmailAlertsEnabled = useCallback(() => {
|
||||||
const value = getSettingValue('notifications.email_alerts', 'true');
|
const value = getSettingValue('notifications.email_alerts', 'true');
|
||||||
return value === true || value === 'true';
|
return value === true || value === 'true';
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
const getReportThreshold = useCallback(() => {
|
const getReportThreshold = useCallback(() => {
|
||||||
return parseInt(getSettingValue('notifications.report_threshold', '5'));
|
return parseInt(getSettingValue('notifications.report_threshold', '5'));
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
const getAuditRetentionDays = useCallback(() => {
|
const getAuditRetentionDays = useCallback(() => {
|
||||||
return parseInt(getSettingValue('system.audit_retention_days', '365'));
|
return parseInt(getSettingValue('system.audit_retention_days', '365'));
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
const getAutoCleanupEnabled = useCallback(() => {
|
const getAutoCleanupEnabled = useCallback(() => {
|
||||||
const value = getSettingValue('system.auto_cleanup', 'false');
|
const value = getSettingValue('system.auto_cleanup', 'false');
|
||||||
return value === true || value === 'true';
|
return value === true || value === 'true';
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
const getAdminPanelRefreshMode = useCallback(() => {
|
const getAdminPanelRefreshMode = useCallback(() => {
|
||||||
const value = getSettingValue('system.admin_panel_refresh_mode', 'auto');
|
const value = getSettingValue('system.admin_panel_refresh_mode', 'auto');
|
||||||
// Remove quotes if they exist (JSON string stored in DB)
|
// Remove quotes if they exist (JSON string stored in DB)
|
||||||
return typeof value === 'string' ? value.replace(/"/g, '') : value;
|
return typeof value === 'string' ? value.replace(/"/g, '') : value;
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
const getAdminPanelPollInterval = useCallback(() => {
|
const getAdminPanelPollInterval = useCallback(() => {
|
||||||
const value = getSettingValue('system.admin_panel_poll_interval', 30);
|
const value = getSettingValue('system.admin_panel_poll_interval', 30);
|
||||||
return parseInt(value?.toString() || '30') * 1000; // Convert to milliseconds
|
return parseInt(value?.toString() || '30') * 1000; // Convert to milliseconds
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get auto-refresh strategy setting
|
* Get auto-refresh strategy setting
|
||||||
@@ -136,7 +134,7 @@ export function useAdminSettings() {
|
|||||||
const value = getSettingValue('auto_refresh_strategy', 'merge');
|
const value = getSettingValue('auto_refresh_strategy', 'merge');
|
||||||
const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : value;
|
const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : value;
|
||||||
return cleanValue as 'merge' | 'replace' | 'notify';
|
return cleanValue as 'merge' | 'replace' | 'notify';
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get preserve interaction state setting
|
* Get preserve interaction state setting
|
||||||
@@ -146,22 +144,30 @@ export function useAdminSettings() {
|
|||||||
const value = getSettingValue('preserve_interaction_state', 'true');
|
const value = getSettingValue('preserve_interaction_state', 'true');
|
||||||
const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : value;
|
const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : value;
|
||||||
return cleanValue === 'true' || cleanValue === true;
|
return cleanValue === 'true' || cleanValue === true;
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
const getNotificationRecipients = useCallback(() => {
|
const getNotificationRecipients = useCallback(() => {
|
||||||
return getSettingValue('notifications.recipients', []);
|
return getSettingValue('notifications.recipients', []);
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
const getUseRealtimeQueue = useCallback((): boolean => {
|
const getUseRealtimeQueue = useCallback((): boolean => {
|
||||||
const value = getSettingValue('system.use_realtime_queue', 'true');
|
const value = getSettingValue('system.use_realtime_queue', 'true');
|
||||||
const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : value;
|
const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : value;
|
||||||
return cleanValue === 'true' || cleanValue === true;
|
return cleanValue === 'true' || cleanValue === true;
|
||||||
}, [settings]);
|
}, [getSettingValue]);
|
||||||
|
|
||||||
const getRefreshOnTabVisible = useCallback((): boolean => {
|
const getRefreshOnTabVisible = useCallback((): boolean => {
|
||||||
const value = getSettingValue('system.refresh_on_tab_visible', 'false');
|
const value = getSettingValue('system.refresh_on_tab_visible', 'false');
|
||||||
const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : value;
|
const cleanValue = typeof value === 'string' ? value.replace(/"/g, '') : value;
|
||||||
return cleanValue === 'true' || cleanValue === true;
|
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]);
|
}, [settings]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user