From 8e9d4e4f12d2e8c63db52273ee48f7a931211f30 Mon Sep 17 00:00:00 2001 From: Sumeet2005 Date: Tue, 30 Sep 2025 19:16:25 +0530 Subject: [PATCH] fix: implement responsive Settings page toggle buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Settings section to Dashboard with Dark Mode and High Contrast toggles - Implement proper state management using React useState hooks - Add localStorage persistence for settings across browser sessions - Add proper onChange event handlers for Material-UI Switch components - Apply theme changes immediately when toggles are clicked - Fix unresponsive toggle button issue mentioned in GitHub issue Toggle buttons now: ✅ Respond to user clicks (were unresponsive) ✅ Save state to localStorage (persist across sessions) ✅ Apply visual changes immediately (dark theme, contrast) ✅ Show current status with visual indicators Closes #[issue-number] --- frontend/src/components/Dashboard.tsx | 243 +++++++++++++++++++++----- frontend/src/components/Settings.tsx | 179 +++++++++++++++++++ 2 files changed, 381 insertions(+), 41 deletions(-) create mode 100644 frontend/src/components/Settings.tsx diff --git a/frontend/src/components/Dashboard.tsx b/frontend/src/components/Dashboard.tsx index 0ba062de0..7b3c7dfd7 100644 --- a/frontend/src/components/Dashboard.tsx +++ b/frontend/src/components/Dashboard.tsx @@ -28,7 +28,10 @@ import { MenuItem, Accordion, AccordionSummary, - AccordionDetails + AccordionDetails, + FormControlLabel, + Switch, + Divider } from '@mui/material'; import { TrendingUp, @@ -38,7 +41,8 @@ import { ExpandMore, Upload, Person, - AccountBalance + AccountBalance, + Settings as SettingsIcon } from '@mui/icons-material'; interface DashboardStats { @@ -69,7 +73,7 @@ const Dashboard: React.FC = () => { const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [testResult, setTestResult] = useState(null); - + // New state for enhanced features const [customDialogOpen, setCustomDialogOpen] = useState(false); const [bulkDialogOpen, setBulkDialogOpen] = useState(false); @@ -79,6 +83,10 @@ const Dashboard: React.FC = () => { const [bulkTransactions, setBulkTransactions] = useState([]); const [bulkResults, setBulkResults] = useState([]); + // Settings state + const [isDarkMode, setIsDarkMode] = useState(false); + const [isHighContrast, setIsHighContrast] = useState(false); + // Updated API URL to match our working backend const API_BASE = 'http://localhost:8000'; @@ -88,19 +96,73 @@ const Dashboard: React.FC = () => { return () => clearInterval(interval); }, []); + // Load settings from localStorage + useEffect(() => { + const savedDarkMode = localStorage.getItem('darkMode'); + const savedHighContrast = localStorage.getItem('highContrast'); + + if (savedDarkMode !== null) { + setIsDarkMode(JSON.parse(savedDarkMode)); + } + + if (savedHighContrast !== null) { + setIsHighContrast(JSON.parse(savedHighContrast)); + } + }, []); + + // Apply dark mode theme + useEffect(() => { + if (isDarkMode) { + document.documentElement.classList.add('dark'); + document.body.style.backgroundColor = '#121212'; + document.body.style.color = '#ffffff'; + } else { + document.documentElement.classList.remove('dark'); + document.body.style.backgroundColor = '#ffffff'; + document.body.style.color = '#000000'; + } + }, [isDarkMode]); + + // Apply high contrast + useEffect(() => { + if (isHighContrast) { + document.documentElement.classList.add('high-contrast'); + document.body.style.filter = 'contrast(150%)'; + } else { + document.documentElement.classList.remove('high-contrast'); + document.body.style.filter = 'none'; + } + }, [isHighContrast]); + + // Handle Dark Mode toggle + const handleDarkModeToggle = (event: React.ChangeEvent) => { + const newValue = event.target.checked; + setIsDarkMode(newValue); + localStorage.setItem('darkMode', JSON.stringify(newValue)); + console.log(`Dark Mode ${newValue ? 'enabled' : 'disabled'}`); + }; + + // Handle High Contrast toggle + const handleHighContrastToggle = (event: React.ChangeEvent) => { + const newValue = event.target.checked; + setIsHighContrast(newValue); + localStorage.setItem('highContrast', JSON.stringify(newValue)); + console.log(`High Contrast ${newValue ? 'enabled' : 'disabled'}`); + }; + const fetchDashboardData = async () => { try { // Fetch dashboard stats const statsResponse = await fetch(`${API_BASE}/api/stats`); const statsData = await statsResponse.json(); - + // Add missing fields with defaults const enhancedStats = { ...statsData, pending_alerts: statsData.recent_alerts || 0, fraud_rate: statsData.fraud_rate || 0 }; - + setStats(enhancedStats); setLoading(false); } catch (err) { @@ -124,15 +186,15 @@ const Dashboard: React.FC = () => { const response = await fetch(`${API_BASE}/api/predict`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ + body: JSON.stringify({ amount: amount, merchant: merchant, card_type: 'credit' }) }); - + const result = await response.json(); - + // Convert result to Transaction interface const transaction: Transaction = { id: result.transaction_id || Date.now(), @@ -145,7 +207,7 @@ const Dashboard: React.FC = () => { timestamp: new Date().toISOString(), transaction_type: 'credit_card' }; - + setTestResult(transaction); } catch (err) { setError(`Failed to test fraud detection: ${err}`); @@ -163,15 +225,15 @@ const Dashboard: React.FC = () => { const response = await fetch(`${API_BASE}/api/predict`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ + body: JSON.stringify({ amount: parseFloat(customAmount), merchant: customMerchant, transaction_type: customTransactionType }) }); - + const result = await response.json(); - + const transaction: Transaction = { id: Date.now(), transaction_id: result.transaction_id, @@ -183,7 +245,7 @@ const Dashboard: React.FC = () => { timestamp: new Date().toISOString(), transaction_type: customTransactionType }; - + setTestResult(transaction); setCustomDialogOpen(false); setCustomAmount(''); @@ -208,7 +270,7 @@ const Dashboard: React.FC = () => { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(transaction) }); - + const result = await response.json(); results.push({ ...transaction, @@ -224,7 +286,7 @@ const Dashboard: React.FC = () => { }); } } - + setBulkResults(results); }; @@ -278,15 +340,15 @@ const Dashboard: React.FC = () => { - - - - - -