From 03b0e677ed92b867badb9f3b51ec8bb688df2177 Mon Sep 17 00:00:00 2001 From: chark1es Date: Sun, 2 Mar 2025 01:42:36 -0800 Subject: [PATCH] add default settings --- .../dashboard/SettingsSection.astro | 3 + .../AccountSecuritySettings.tsx | 28 +- .../SettingsSection/DisplaySettings.tsx | 324 +++++++++--------- .../SettingsSection/NotificationSettings.tsx | 83 +++-- .../SettingsSection/UserProfileSettings.tsx | 85 +++-- 5 files changed, 265 insertions(+), 258 deletions(-) diff --git a/src/components/dashboard/SettingsSection.astro b/src/components/dashboard/SettingsSection.astro index 8723219..4bf2322 100644 --- a/src/components/dashboard/SettingsSection.astro +++ b/src/components/dashboard/SettingsSection.astro @@ -4,6 +4,7 @@ import UserProfileSettings from "./SettingsSection/UserProfileSettings"; import AccountSecuritySettings from "./SettingsSection/AccountSecuritySettings"; import NotificationSettings from "./SettingsSection/NotificationSettings"; import DisplaySettings from "./SettingsSection/DisplaySettings"; +import { Toaster } from "react-hot-toast"; ---
@@ -12,6 +13,8 @@ import DisplaySettings from "./SettingsSection/DisplaySettings";

Manage your account settings and preferences

+ +
-
- You must be logged in to access this page. -
+
+ You must be logged in to access this page.
); } @@ -134,11 +134,9 @@ export default function AccountSecuritySettings() { Password management is handled through your IEEEUCSD account.

-
-
- To change your password, please visit the UCSD SSO portal. -
-
+

+ To change your password, please use the "Forgot Password" option on the login page. +

{/* Account Actions */} @@ -153,14 +151,10 @@ export default function AccountSecuritySettings() { Sign Out -
-
- - If you need to delete your account or have other account-related issues, - please contact an IEEE UCSD administrator. - -
-
+

+ If you need to delete your account or have other account-related issues, + please contact an IEEE UCSD administrator. +

diff --git a/src/components/dashboard/SettingsSection/DisplaySettings.tsx b/src/components/dashboard/SettingsSection/DisplaySettings.tsx index 3ff9635..113ca71 100644 --- a/src/components/dashboard/SettingsSection/DisplaySettings.tsx +++ b/src/components/dashboard/SettingsSection/DisplaySettings.tsx @@ -2,16 +2,27 @@ import { useState, useEffect } from 'react'; import { Authentication } from '../../../scripts/pocketbase/Authentication'; import { Update } from '../../../scripts/pocketbase/Update'; import { Collections } from '../../../schemas/pocketbase/schema'; +import { toast } from 'react-hot-toast'; + +// Default display preferences +const DEFAULT_DISPLAY_PREFERENCES = { + theme: 'dark', + fontSize: 'medium' +}; + +// Default accessibility settings +const DEFAULT_ACCESSIBILITY_SETTINGS = { + colorBlindMode: false, + reducedMotion: false +}; export default function DisplaySettings() { const auth = Authentication.getInstance(); const update = Update.getInstance(); - const [theme, setTheme] = useState('dark'); - const [fontSize, setFontSize] = useState('medium'); - const [colorBlindMode, setColorBlindMode] = useState(false); - const [reducedMotion, setReducedMotion] = useState(false); - const [successMessage, setSuccessMessage] = useState(''); - const [errorMessage, setErrorMessage] = useState(''); + const [theme, setTheme] = useState(DEFAULT_DISPLAY_PREFERENCES.theme); + const [fontSize, setFontSize] = useState(DEFAULT_DISPLAY_PREFERENCES.fontSize); + const [colorBlindMode, setColorBlindMode] = useState(DEFAULT_ACCESSIBILITY_SETTINGS.colorBlindMode); + const [reducedMotion, setReducedMotion] = useState(DEFAULT_ACCESSIBILITY_SETTINGS.reducedMotion); const [saving, setSaving] = useState(false); // Load saved preferences on component mount @@ -19,18 +30,20 @@ export default function DisplaySettings() { const loadPreferences = async () => { try { // First check localStorage for immediate UI updates - const savedTheme = localStorage.getItem('theme') || 'dark'; - const savedFontSize = localStorage.getItem('fontSize') || 'medium'; + const savedTheme = localStorage.getItem('theme') || DEFAULT_DISPLAY_PREFERENCES.theme; + // Ensure theme is either light or dark + const validTheme = ['light', 'dark'].includes(savedTheme) ? savedTheme : DEFAULT_DISPLAY_PREFERENCES.theme; + const savedFontSize = localStorage.getItem('fontSize') || DEFAULT_DISPLAY_PREFERENCES.fontSize; const savedColorBlindMode = localStorage.getItem('colorBlindMode') === 'true'; const savedReducedMotion = localStorage.getItem('reducedMotion') === 'true'; - setTheme(savedTheme); + setTheme(validTheme); setFontSize(savedFontSize); setColorBlindMode(savedColorBlindMode); setReducedMotion(savedReducedMotion); // Apply theme to document - document.documentElement.setAttribute('data-theme', savedTheme); + document.documentElement.setAttribute('data-theme', validTheme); // Apply font size applyFontSize(savedFontSize); @@ -46,67 +59,116 @@ export default function DisplaySettings() { // Then check if user has saved preferences in their profile const user = auth.getCurrentUser(); - if (user && user.display_preferences) { - try { - const userPrefs = JSON.parse(user.display_preferences); + if (user) { + let needsDisplayPrefsUpdate = false; + let needsAccessibilityUpdate = false; - // Only update if values exist and are different from localStorage - if (userPrefs.theme && userPrefs.theme !== savedTheme) { - setTheme(userPrefs.theme); - localStorage.setItem('theme', userPrefs.theme); - document.documentElement.setAttribute('data-theme', userPrefs.theme); - } + // Check and handle display preferences + if (user.display_preferences && typeof user.display_preferences === 'string' && user.display_preferences.trim() !== '') { + try { + const userPrefs = JSON.parse(user.display_preferences); - if (userPrefs.fontSize && userPrefs.fontSize !== savedFontSize) { - setFontSize(userPrefs.fontSize); - localStorage.setItem('fontSize', userPrefs.fontSize); - applyFontSize(userPrefs.fontSize); + // Only update if values exist and are different from localStorage + if (userPrefs.theme && ['light', 'dark'].includes(userPrefs.theme) && userPrefs.theme !== validTheme) { + setTheme(userPrefs.theme); + localStorage.setItem('theme', userPrefs.theme); + document.documentElement.setAttribute('data-theme', userPrefs.theme); + } else if (!['light', 'dark'].includes(userPrefs.theme)) { + // If theme is not valid, mark for update + needsDisplayPrefsUpdate = true; + } + + if (userPrefs.fontSize && userPrefs.fontSize !== savedFontSize) { + setFontSize(userPrefs.fontSize); + localStorage.setItem('fontSize', userPrefs.fontSize); + applyFontSize(userPrefs.fontSize); + } + } catch (e) { + console.error('Error parsing display preferences:', e); + needsDisplayPrefsUpdate = true; } - } catch (e) { - console.error('Error parsing display preferences:', e); + } else { + needsDisplayPrefsUpdate = true; } - } - if (user && user.accessibility_settings) { - try { - const accessibilityPrefs = JSON.parse(user.accessibility_settings); + // Check and handle accessibility settings + if (user.accessibility_settings && typeof user.accessibility_settings === 'string' && user.accessibility_settings.trim() !== '') { + try { + const accessibilityPrefs = JSON.parse(user.accessibility_settings); - if (typeof accessibilityPrefs.colorBlindMode === 'boolean' && - accessibilityPrefs.colorBlindMode !== savedColorBlindMode) { - setColorBlindMode(accessibilityPrefs.colorBlindMode); - localStorage.setItem('colorBlindMode', accessibilityPrefs.colorBlindMode.toString()); + if (typeof accessibilityPrefs.colorBlindMode === 'boolean' && + accessibilityPrefs.colorBlindMode !== savedColorBlindMode) { + setColorBlindMode(accessibilityPrefs.colorBlindMode); + localStorage.setItem('colorBlindMode', accessibilityPrefs.colorBlindMode.toString()); - if (accessibilityPrefs.colorBlindMode) { - document.documentElement.classList.add('color-blind-mode'); - } else { - document.documentElement.classList.remove('color-blind-mode'); + if (accessibilityPrefs.colorBlindMode) { + document.documentElement.classList.add('color-blind-mode'); + } else { + document.documentElement.classList.remove('color-blind-mode'); + } } - } - if (typeof accessibilityPrefs.reducedMotion === 'boolean' && - accessibilityPrefs.reducedMotion !== savedReducedMotion) { - setReducedMotion(accessibilityPrefs.reducedMotion); - localStorage.setItem('reducedMotion', accessibilityPrefs.reducedMotion.toString()); + if (typeof accessibilityPrefs.reducedMotion === 'boolean' && + accessibilityPrefs.reducedMotion !== savedReducedMotion) { + setReducedMotion(accessibilityPrefs.reducedMotion); + localStorage.setItem('reducedMotion', accessibilityPrefs.reducedMotion.toString()); - if (accessibilityPrefs.reducedMotion) { - document.documentElement.classList.add('reduced-motion'); - } else { - document.documentElement.classList.remove('reduced-motion'); + if (accessibilityPrefs.reducedMotion) { + document.documentElement.classList.add('reduced-motion'); + } else { + document.documentElement.classList.remove('reduced-motion'); + } } + } catch (e) { + console.error('Error parsing accessibility settings:', e); + needsAccessibilityUpdate = true; } - } catch (e) { - console.error('Error parsing accessibility settings:', e); + } else { + needsAccessibilityUpdate = true; + } + + // Initialize default settings if needed + if (needsDisplayPrefsUpdate || needsAccessibilityUpdate) { + await initializeDefaultSettings(user.id, needsDisplayPrefsUpdate, needsAccessibilityUpdate); } } } catch (error) { console.error('Error loading preferences:', error); - setErrorMessage('Failed to load display preferences'); + toast.error('Failed to load display preferences'); } }; loadPreferences(); }, []); + // Initialize default settings if not set + const initializeDefaultSettings = async (userId: string, updateDisplayPrefs: boolean, updateAccessibility: boolean) => { + try { + const updateData: any = {}; + + if (updateDisplayPrefs) { + updateData.display_preferences = JSON.stringify({ + theme, + fontSize + }); + } + + if (updateAccessibility) { + updateData.accessibility_settings = JSON.stringify({ + colorBlindMode, + reducedMotion + }); + } + + if (Object.keys(updateData).length > 0) { + await update.updateFields(Collections.USERS, userId, updateData); + console.log('Initialized default display and accessibility settings'); + } + } catch (error) { + console.error('Error initializing default settings:', error); + } + }; + // Apply font size to document const applyFontSize = (size: string) => { const htmlElement = document.documentElement; @@ -191,8 +253,6 @@ export default function DisplaySettings() { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setSaving(true); - setSuccessMessage(''); - setErrorMessage(''); try { const user = auth.getCurrentUser(); @@ -221,15 +281,10 @@ export default function DisplaySettings() { ); // Show success message - setSuccessMessage('Display settings saved successfully!'); - - // Clear success message after 3 seconds - setTimeout(() => { - setSuccessMessage(''); - }, 3000); + toast.success('Display settings saved successfully!'); } catch (error) { console.error('Error saving display settings:', error); - setErrorMessage('Failed to save display settings to your profile'); + toast.error('Failed to save display settings to your profile'); } finally { setSaving(false); } @@ -237,114 +292,71 @@ export default function DisplaySettings() { return (
- {successMessage && ( -
-
- {successMessage} -
-
- )} - - {errorMessage && ( -
-
- {errorMessage} -
-
- )} -
- {/* Theme Selection */} -
- - - + {/* Theme Settings */} +
+

Theme

+
+ + +
- {/* Font Size */} -
- - - + {/* Font Size Settings */} +
+

Font Size

+
+ + +
- {/* Accessibility Options */} -
- + {/* Accessibility Settings */} +
+

Accessibility

-
+
+
+
- {/* Preview */} -
- -
-
-
-

Theme Preview

-

This is how your content will look with the selected settings.

-
- - - -
-
-
-
-
+

+ These settings are saved to your browser and your IEEE UCSD account. They will be applied whenever you log in. +

-
+