update settings

This commit is contained in:
chark1es 2025-03-02 01:21:42 -08:00
parent b7881213ce
commit 4a33fc3ce4
4 changed files with 168 additions and 35 deletions

View file

@ -130,8 +130,8 @@ export default function AccountSecuritySettings() {
<div>
<h4 className="font-semibold text-lg mb-2">Authentication Options</h4>
<p className="text-sm opacity-70 mb-4">
IEEE UCSD uses Single Sign-On (SSO) through UCSD for authentication.
Password management is handled through your UCSD account.
IEEE UCSD uses Single Sign-On (SSO) for authentication.
Password management is handled through your IEEEUCSD account.
</p>
<div className="alert alert-info">

View file

@ -1,14 +1,24 @@
import { useState, useEffect } from 'react';
import { Authentication } from '../../../scripts/pocketbase/Authentication';
import { Update } from '../../../scripts/pocketbase/Update';
import { Collections } from '../../../schemas/pocketbase/schema';
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 [saving, setSaving] = useState(false);
// Load saved preferences from localStorage on component mount
// Load saved preferences on component mount
useEffect(() => {
const loadPreferences = async () => {
try {
// First check localStorage for immediate UI updates
const savedTheme = localStorage.getItem('theme') || 'dark';
const savedFontSize = localStorage.getItem('fontSize') || 'medium';
const savedColorBlindMode = localStorage.getItem('colorBlindMode') === 'true';
@ -33,6 +43,68 @@ export default function DisplaySettings() {
if (savedReducedMotion) {
document.documentElement.classList.add('reduced-motion');
}
// 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);
// 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);
}
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);
}
}
if (user && user.accessibility_settings) {
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 (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 (accessibilityPrefs.reducedMotion) {
document.documentElement.classList.add('reduced-motion');
} else {
document.documentElement.classList.remove('reduced-motion');
}
}
} catch (e) {
console.error('Error parsing accessibility settings:', e);
}
}
} catch (error) {
console.error('Error loading preferences:', error);
setErrorMessage('Failed to load display preferences');
}
};
loadPreferences();
}, []);
// Apply font size to document
@ -116,8 +188,37 @@ export default function DisplaySettings() {
};
// Handle form submission
const handleSubmit = (e: React.FormEvent) => {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setSaving(true);
setSuccessMessage('');
setErrorMessage('');
try {
const user = auth.getCurrentUser();
if (!user) throw new Error('User not authenticated');
// Save display preferences to user record
const displayPreferences = {
theme,
fontSize
};
// Save accessibility settings to user record
const accessibilitySettings = {
colorBlindMode,
reducedMotion
};
// Update user record
await update.updateFields(
Collections.USERS,
user.id,
{
display_preferences: JSON.stringify(displayPreferences),
accessibility_settings: JSON.stringify(accessibilitySettings)
}
);
// Show success message
setSuccessMessage('Display settings saved successfully!');
@ -126,6 +227,12 @@ export default function DisplaySettings() {
setTimeout(() => {
setSuccessMessage('');
}, 3000);
} catch (error) {
console.error('Error saving display settings:', error);
setErrorMessage('Failed to save display settings to your profile');
} finally {
setSaving(false);
}
};
return (
@ -138,6 +245,14 @@ export default function DisplaySettings() {
</div>
)}
{errorMessage && (
<div className="alert alert-error mb-4">
<div>
<span>{errorMessage}</span>
</div>
</div>
)}
<form onSubmit={handleSubmit} className="space-y-6">
{/* Theme Selection */}
<div className="form-control">
@ -260,8 +375,12 @@ export default function DisplaySettings() {
</div>
<div className="form-control mt-6">
<button type="submit" className="btn btn-primary">
Save Settings
<button
type="submit"
className={`btn btn-primary ${saving ? 'loading' : ''}`}
disabled={saving}
>
{saving ? 'Saving...' : 'Save Settings'}
</button>
</div>
</form>

View file

@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
import { Authentication } from '../../../scripts/pocketbase/Authentication';
import { Update } from '../../../scripts/pocketbase/Update';
import { Collections, type User } from '../../../schemas/pocketbase/schema';
import allMajors from '../../../data/allUCSDMajors.txt?raw';
export default function UserProfileSettings() {
const auth = Authentication.getInstance();
@ -19,6 +20,9 @@ export default function UserProfileSettings() {
const [successMessage, setSuccessMessage] = useState('');
const [errorMessage, setErrorMessage] = useState('');
// Parse the majors list from the text file
const majorsList = allMajors.split('\n').filter(major => major.trim() !== '');
useEffect(() => {
const loadUserData = async () => {
try {
@ -164,13 +168,19 @@ export default function UserProfileSettings() {
<label className="label">
<span className="label-text">Major</span>
</label>
<input
type="text"
<select
name="major"
value={formData.major}
onChange={handleInputChange}
className="input input-bordered w-full"
/>
className="select select-bordered w-full"
>
<option value="">Select a major</option>
{majorsList.map((major, index) => (
<option key={index} value={major}>
{major}
</option>
))}
</select>
</div>
<div className="form-control">

View file

@ -30,6 +30,10 @@ export interface User extends BaseRecord {
graduation_year?: number;
major?: string;
zelle_information?: string;
last_login?: string;
notification_preferences?: string; // JSON string of notification settings
display_preferences?: string; // JSON string of display settings (theme, font size, etc.)
accessibility_settings?: string; // JSON string of accessibility settings (color blind mode, reduced motion)
}
/**