Improved the settings page by removing individual save buttons from each preference component and adding unified save buttons per section: ## Changes Made ### Component Updates - **TimeZoneSelector**: Converted to controlled component with value/onChange props * Removed internal state management and save button * Removed success/error alerts (now handled by parent) * Added auto-detect as simple button without save - **TimeFormatSelector**: Converted to controlled component with value/onChange props * Removed internal state management and save button * Removed success/error alerts (now handled by parent) * Simplified to just radio buttons with preview ### Settings Page Improvements - Added timezone and timeFormat to local state - Created separate save handlers: * `handleSaveProfile` - for name/email changes * `handleSavePreferences` - for timezone and time format - Three clear sections with dedicated save buttons: 1. **Profile Information** → "Save Profile" button 2. **Preferences** (Language, Units, Timezone, Time Format) → "Save Preferences" button 3. **Notifications** → "Save Notification Settings" button ### User Experience Benefits - Clearer separation between different types of settings - Single save action per logical section instead of multiple buttons - Consistent save pattern across all settings cards - Reduced visual clutter with fewer buttons on page - Better organization: related settings grouped with one save action Files changed: 3 files (TimeZoneSelector, TimeFormatSelector, settings page) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
132 lines
4.3 KiB
TypeScript
132 lines
4.3 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect } from 'react';
|
|
import {
|
|
Box,
|
|
FormControl,
|
|
InputLabel,
|
|
Select,
|
|
MenuItem,
|
|
Button,
|
|
Typography,
|
|
} from '@mui/material';
|
|
import { AccessTime } from '@mui/icons-material';
|
|
import { useAuth } from '@/lib/auth/AuthContext';
|
|
import { useTranslation } from '@/hooks/useTranslation';
|
|
|
|
// Common timezones grouped by region
|
|
const TIMEZONES = {
|
|
'Americas': [
|
|
{ value: 'America/New_York', label: 'Eastern Time (US & Canada)' },
|
|
{ value: 'America/Chicago', label: 'Central Time (US & Canada)' },
|
|
{ value: 'America/Denver', label: 'Mountain Time (US & Canada)' },
|
|
{ value: 'America/Los_Angeles', label: 'Pacific Time (US & Canada)' },
|
|
{ value: 'America/Anchorage', label: 'Alaska' },
|
|
{ value: 'Pacific/Honolulu', label: 'Hawaii' },
|
|
{ value: 'America/Phoenix', label: 'Arizona' },
|
|
{ value: 'America/Toronto', label: 'Toronto' },
|
|
{ value: 'America/Vancouver', label: 'Vancouver' },
|
|
{ value: 'America/Mexico_City', label: 'Mexico City' },
|
|
{ value: 'America/Sao_Paulo', label: 'São Paulo' },
|
|
{ value: 'America/Buenos_Aires', label: 'Buenos Aires' },
|
|
],
|
|
'Europe': [
|
|
{ value: 'Europe/London', label: 'London' },
|
|
{ value: 'Europe/Paris', label: 'Paris' },
|
|
{ value: 'Europe/Berlin', label: 'Berlin' },
|
|
{ value: 'Europe/Rome', label: 'Rome' },
|
|
{ value: 'Europe/Madrid', label: 'Madrid' },
|
|
{ value: 'Europe/Amsterdam', label: 'Amsterdam' },
|
|
{ value: 'Europe/Brussels', label: 'Brussels' },
|
|
{ value: 'Europe/Vienna', label: 'Vienna' },
|
|
{ value: 'Europe/Athens', label: 'Athens' },
|
|
{ value: 'Europe/Moscow', label: 'Moscow' },
|
|
],
|
|
'Asia': [
|
|
{ value: 'Asia/Dubai', label: 'Dubai' },
|
|
{ value: 'Asia/Kolkata', label: 'India (Kolkata)' },
|
|
{ value: 'Asia/Shanghai', label: 'China (Shanghai)' },
|
|
{ value: 'Asia/Hong_Kong', label: 'Hong Kong' },
|
|
{ value: 'Asia/Singapore', label: 'Singapore' },
|
|
{ value: 'Asia/Tokyo', label: 'Tokyo' },
|
|
{ value: 'Asia/Seoul', label: 'Seoul' },
|
|
{ value: 'Asia/Bangkok', label: 'Bangkok' },
|
|
{ value: 'Asia/Jakarta', label: 'Jakarta' },
|
|
],
|
|
'Pacific': [
|
|
{ value: 'Australia/Sydney', label: 'Sydney' },
|
|
{ value: 'Australia/Melbourne', label: 'Melbourne' },
|
|
{ value: 'Australia/Brisbane', label: 'Brisbane' },
|
|
{ value: 'Pacific/Auckland', label: 'Auckland' },
|
|
{ value: 'Pacific/Fiji', label: 'Fiji' },
|
|
],
|
|
'Africa': [
|
|
{ value: 'Africa/Cairo', label: 'Cairo' },
|
|
{ value: 'Africa/Johannesburg', label: 'Johannesburg' },
|
|
{ value: 'Africa/Lagos', label: 'Lagos' },
|
|
{ value: 'Africa/Nairobi', label: 'Nairobi' },
|
|
],
|
|
};
|
|
|
|
interface TimeZoneSelectorProps {
|
|
value: string;
|
|
onChange: (timezone: string) => void;
|
|
}
|
|
|
|
export function TimeZoneSelector({ value, onChange }: TimeZoneSelectorProps) {
|
|
const { user } = useAuth();
|
|
const { t } = useTranslation('settings');
|
|
|
|
// Initialize with user's timezone on mount
|
|
useEffect(() => {
|
|
if (user?.timezone && !value) {
|
|
onChange(user.timezone);
|
|
}
|
|
}, [user?.timezone]);
|
|
|
|
const handleAutoDetect = () => {
|
|
const detectedTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
onChange(detectedTimezone);
|
|
};
|
|
|
|
return (
|
|
<Box>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
|
|
<AccessTime color="action" />
|
|
<Typography variant="subtitle1" fontWeight="600">
|
|
Time Zone
|
|
</Typography>
|
|
</Box>
|
|
|
|
<FormControl fullWidth sx={{ mb: 2 }}>
|
|
<InputLabel>Time Zone</InputLabel>
|
|
<Select
|
|
value={value || user?.timezone || 'UTC'}
|
|
onChange={(e) => onChange(e.target.value)}
|
|
label="Time Zone"
|
|
>
|
|
{Object.entries(TIMEZONES).map(([region, zones]) => [
|
|
<MenuItem key={region} disabled sx={{ fontWeight: 'bold', color: 'text.primary' }}>
|
|
{region}
|
|
</MenuItem>,
|
|
...zones.map((zone) => (
|
|
<MenuItem key={zone.value} value={zone.value} sx={{ pl: 4 }}>
|
|
{zone.label}
|
|
</MenuItem>
|
|
)),
|
|
])}
|
|
<MenuItem value="UTC">UTC (Universal Time)</MenuItem>
|
|
</Select>
|
|
</FormControl>
|
|
|
|
<Button
|
|
variant="outlined"
|
|
onClick={handleAutoDetect}
|
|
size="small"
|
|
>
|
|
Auto-Detect
|
|
</Button>
|
|
</Box>
|
|
);
|
|
}
|