Skip to content

Commit 6d0da66

Browse files
committed
refactor: consolidate settings saved feedback to toast notifications
Replace transient "Saved" banner with toast notifications featuring stable IDs for deduplication of rapid autosaves. Simplifies notification lifecycle and reduces custom state management.
1 parent 1bc84cf commit 6d0da66

2 files changed

Lines changed: 4 additions & 25 deletions

File tree

frontend/src/components/settings/dialogs/SkillEditDialog.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export const SkillEditDialog: React.FC<SkillEditDialogProps> = ({
147147
await skillService.updateSkill(workspaceId, skill.sources[0], skill.name, merged);
148148
await onSaved();
149149
onClose();
150-
toast.success('Skill updated');
150+
toast.success('Saved');
151151
} catch (saveError) {
152152
setError(saveError instanceof Error ? saveError.message : 'Failed to update skill');
153153
} finally {

frontend/src/pages/SettingsPage.tsx

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { useState, useCallback, useEffect, useRef, Suspense, lazy } from 'react';
22
import {
3-
Check,
43
Settings2,
54
Zap,
65
UserCircle,
@@ -17,7 +16,6 @@ import type { UserSettings, UserSettingsUpdate } from '@/types/user.types';
1716
import type { ApiFieldKey } from '@/types/settings.types';
1817
import { useDeleteAllChatsMutation } from '@/hooks/queries/useChatQueries';
1918
import { useSettingsQuery, useUpdateSettingsMutation } from '@/hooks/queries/useSettingsQueries';
20-
import { useMountEffect } from '@/hooks/useMountEffect';
2119
import { ConfirmDialog } from '@/components/ui/ConfirmDialog';
2220
import { Button } from '@/components/ui/primitives/Button';
2321
import { Spinner } from '@/components/ui/primitives/Spinner';
@@ -108,20 +106,6 @@ const SettingsPage: React.FC = () => {
108106

109107
const instantUpdateMutation = useUpdateSettingsMutation();
110108

111-
// Transient "Saved" confirmation shown after any successful auto-persist.
112-
const [showSaved, setShowSaved] = useState(false);
113-
const savedTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
114-
115-
const showSavedIndicator = useCallback(() => {
116-
setShowSaved(true);
117-
if (savedTimeoutRef.current) clearTimeout(savedTimeoutRef.current);
118-
savedTimeoutRef.current = setTimeout(() => setShowSaved(false), 2000);
119-
}, []);
120-
121-
useMountEffect(() => () => {
122-
if (savedTimeoutRef.current) clearTimeout(savedTimeoutRef.current);
123-
});
124-
125109
useEffect(() => {
126110
localSettingsRef.current = localSettings;
127111
}, [localSettings]);
@@ -170,15 +154,16 @@ const SettingsPage: React.FC = () => {
170154
const result = await instantUpdateMutation.mutateAsync(payload);
171155
setLocalSettings(result);
172156
localSettingsRef.current = result;
173-
showSavedIndicator();
157+
// Stable id collapses rapid successive autosaves into one updating toast
158+
toast.success('Saved', { id: 'settings-saved' });
174159
} catch (error) {
175160
setLocalSettings(previousSettings);
176161
localSettingsRef.current = previousSettings;
177162
toast.error(options.errorMessage || getErrorMessage(error) || 'Failed to update settings');
178163
throw error;
179164
}
180165
},
181-
[instantUpdateMutation, buildChangedPayload, showSavedIndicator],
166+
[instantUpdateMutation, buildChangedPayload],
182167
);
183168

184169
const [revealedFields, setRevealedFields] = useState<Record<ApiFieldKey, boolean>>({
@@ -386,12 +371,6 @@ const SettingsPage: React.FC = () => {
386371

387372
{/* Main content area */}
388373
<div className="relative flex-1 overflow-y-auto">
389-
{showSaved && (
390-
<div className="animate-in fade-in pointer-events-none absolute right-4 top-4 z-10 flex items-center gap-1.5 rounded-md border border-border/50 bg-surface-secondary px-2.5 py-1 text-2xs font-medium text-text-tertiary shadow-sm duration-200 dark:border-border-dark/50 dark:bg-surface-dark-secondary dark:text-text-dark-tertiary">
391-
<Check className="h-3 w-3" />
392-
Saved
393-
</div>
394-
)}
395374
<div className="mx-auto w-full max-w-3xl px-4 py-6 sm:px-6 lg:px-8">
396375
{errorMessage && (
397376
<div className="mb-5 rounded-xl border border-border p-3 dark:border-border-dark">

0 commit comments

Comments
 (0)