refactor: Unify all settings into single Save Preferences button
Simplified the settings page by consolidating all save buttons into one global "Save Preferences" button at the bottom of the page. ## Changes Made ### Unified Save Handler - Merged `handleSaveProfile` and `handleSavePreferences` into single `handleSaveAll` function - Single save handler now updates: * Profile name * Timezone * Time format (12h/24h) * Notification preferences - One API call to save all settings at once ### Removed Individual Save Buttons - Removed "Save Profile" button from Profile Information section - Removed "Save Preferences" button from Preferences section - Removed "Save Notification Settings" button from Notifications section ### Added Global Save Button - Centered "Save Preferences" button at bottom of settings - Positioned above Account Actions (Logout) section - Large, prominent button (minWidth: 200px) - Single source of truth for all settings changes ### User Experience Benefits - **Simpler**: One clear action to save all changes - **Fewer clicks**: No need to save each section separately - **Clear feedback**: Single success/error message for all updates - **Better UX**: Users can make multiple changes and save once - **Consistent**: All settings treated as unified preferences Files changed: 1 file (settings page) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -56,34 +56,7 @@ export default function SettingsPage() {
|
|||||||
}
|
}
|
||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
const handleSavePreferences = async () => {
|
const handleSaveAll = async () => {
|
||||||
setIsLoading(true);
|
|
||||||
setError(null);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await usersApi.updateProfile({
|
|
||||||
timezone,
|
|
||||||
preferences: {
|
|
||||||
...settings,
|
|
||||||
timeFormat,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
console.log('✅ Preferences updated successfully:', response);
|
|
||||||
|
|
||||||
// Refresh user to get latest data from server
|
|
||||||
await refreshUser();
|
|
||||||
|
|
||||||
setSuccessMessage('Preferences saved successfully!');
|
|
||||||
} catch (err: any) {
|
|
||||||
console.error('❌ Failed to update preferences:', err);
|
|
||||||
console.error('Error response:', err.response);
|
|
||||||
setError(err.response?.data?.message || err.message || 'Failed to save preferences. Please try again.');
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSaveProfile = async () => {
|
|
||||||
// Validate name
|
// Validate name
|
||||||
if (!name || name.trim() === '') {
|
if (!name || name.trim() === '') {
|
||||||
setNameError('Name cannot be empty');
|
setNameError('Name cannot be empty');
|
||||||
@@ -97,17 +70,22 @@ export default function SettingsPage() {
|
|||||||
try {
|
try {
|
||||||
const response = await usersApi.updateProfile({
|
const response = await usersApi.updateProfile({
|
||||||
name: name.trim(),
|
name: name.trim(),
|
||||||
|
timezone,
|
||||||
|
preferences: {
|
||||||
|
...settings,
|
||||||
|
timeFormat,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
console.log('✅ Profile updated successfully:', response);
|
console.log('✅ All settings saved successfully:', response);
|
||||||
|
|
||||||
// Refresh user to get latest data from server
|
// Refresh user to get latest data from server
|
||||||
await refreshUser();
|
await refreshUser();
|
||||||
|
|
||||||
setSuccessMessage('Profile updated successfully!');
|
setSuccessMessage('Settings saved successfully!');
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error('❌ Failed to update profile:', err);
|
console.error('❌ Failed to save settings:', err);
|
||||||
console.error('Error response:', err.response);
|
console.error('Error response:', err.response);
|
||||||
setError(err.response?.data?.message || err.message || 'Failed to update profile. Please try again.');
|
setError(err.response?.data?.message || err.message || 'Failed to save settings. Please try again.');
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -172,15 +150,6 @@ export default function SettingsPage() {
|
|||||||
disabled
|
disabled
|
||||||
helperText="Email cannot be changed"
|
helperText="Email cannot be changed"
|
||||||
/>
|
/>
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
startIcon={isLoading ? <CircularProgress size={20} color="inherit" /> : <Save />}
|
|
||||||
onClick={handleSaveProfile}
|
|
||||||
disabled={isLoading}
|
|
||||||
sx={{ alignSelf: 'flex-start' }}
|
|
||||||
>
|
|
||||||
{isLoading ? 'Saving...' : 'Save Profile'}
|
|
||||||
</Button>
|
|
||||||
</Box>
|
</Box>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -206,15 +175,6 @@ export default function SettingsPage() {
|
|||||||
<Divider />
|
<Divider />
|
||||||
<TimeFormatSelector value={timeFormat} onChange={setTimeFormat} />
|
<TimeFormatSelector value={timeFormat} onChange={setTimeFormat} />
|
||||||
</Box>
|
</Box>
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
startIcon={isLoading ? <CircularProgress size={20} color="inherit" /> : <Save />}
|
|
||||||
onClick={handleSavePreferences}
|
|
||||||
disabled={isLoading}
|
|
||||||
sx={{ mt: 3, alignSelf: 'flex-start' }}
|
|
||||||
>
|
|
||||||
{isLoading ? 'Saving...' : 'Save Preferences'}
|
|
||||||
</Button>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
@@ -252,15 +212,6 @@ export default function SettingsPage() {
|
|||||||
label="Email Updates"
|
label="Email Updates"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
startIcon={isLoading ? <CircularProgress size={20} color="inherit" /> : <Save />}
|
|
||||||
onClick={handleSavePreferences}
|
|
||||||
disabled={isLoading}
|
|
||||||
sx={{ mt: 2, alignSelf: 'flex-start' }}
|
|
||||||
>
|
|
||||||
{isLoading ? 'Saving...' : 'Save Notification Settings'}
|
|
||||||
</Button>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
@@ -358,6 +309,26 @@ export default function SettingsPage() {
|
|||||||
</Box>
|
</Box>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Global Save Button */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.4, delay: 0.44 }}
|
||||||
|
>
|
||||||
|
<Box sx={{ mb: 3, display: 'flex', justifyContent: 'center' }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
size="large"
|
||||||
|
startIcon={isLoading ? <CircularProgress size={20} color="inherit" /> : <Save />}
|
||||||
|
onClick={handleSaveAll}
|
||||||
|
disabled={isLoading}
|
||||||
|
sx={{ minWidth: 200 }}
|
||||||
|
>
|
||||||
|
{isLoading ? 'Saving...' : 'Save Preferences'}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
{/* Account Actions */}
|
{/* Account Actions */}
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
|||||||
Reference in New Issue
Block a user