CI 2891 failed on an unhandled ReferenceError: the 2s
setTimeout(() => setSaveState('idle')) in the settings tabs fired after
jsdom teardown. Replace the three uncleaned timers with one
useSavedBadgeReset effect hook that clears on unmount.
This commit is contained in:
@@ -57,6 +57,16 @@ function prefValue<T>(prefs: Preference[], key: string, fallback: T): T {
|
||||
return p.value as T;
|
||||
}
|
||||
|
||||
// The reset must not outlive the tab: an uncleared setTimeout fires into a
|
||||
// torn-down environment (unmount, or jsdom teardown under vitest).
|
||||
function useSavedBadgeReset(saveState: SaveState, setSaveState: (s: SaveState) => void): void {
|
||||
useEffect(() => {
|
||||
if (saveState !== 'saved') return undefined;
|
||||
const timer = setTimeout(() => setSaveState('idle'), 2000);
|
||||
return () => clearTimeout(timer);
|
||||
}, [saveState, setSaveState]);
|
||||
}
|
||||
|
||||
// ─── Main Page ────────────────────────────────────────────────────────────────
|
||||
|
||||
export function SettingsPage(): React.ReactElement {
|
||||
@@ -111,6 +121,7 @@ function ProfileTab({
|
||||
const [image, setImage] = useState(session?.user.image ?? '');
|
||||
const [saveState, setSaveState] = useState<SaveState>('idle');
|
||||
const [errorMsg, setErrorMsg] = useState('');
|
||||
useSavedBadgeReset(saveState, setSaveState);
|
||||
|
||||
// Sync from session when it loads
|
||||
useEffect(() => {
|
||||
@@ -131,7 +142,6 @@ function ProfileTab({
|
||||
return;
|
||||
}
|
||||
setSaveState('saved');
|
||||
setTimeout(() => setSaveState('idle'), 2000);
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : 'Failed to update profile';
|
||||
setErrorMsg(message);
|
||||
@@ -194,6 +204,7 @@ function AppearanceTab(): React.ReactElement {
|
||||
const [defaultModel, setDefaultModel] = useState('');
|
||||
const [saveState, setSaveState] = useState<SaveState>('idle');
|
||||
const [errorMsg, setErrorMsg] = useState('');
|
||||
useSavedBadgeReset(saveState, setSaveState);
|
||||
|
||||
useEffect(() => {
|
||||
api<Preference[]>('/api/memory/preferences?category=appearance')
|
||||
@@ -239,7 +250,6 @@ function AppearanceTab(): React.ReactElement {
|
||||
: []),
|
||||
]);
|
||||
setSaveState('saved');
|
||||
setTimeout(() => setSaveState('idle'), 2000);
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : 'Failed to save preferences';
|
||||
setErrorMsg(message);
|
||||
@@ -323,6 +333,7 @@ function NotificationsTab(): React.ReactElement {
|
||||
const [emailDigest, setEmailDigest] = useState(false);
|
||||
const [saveState, setSaveState] = useState<SaveState>('idle');
|
||||
const [errorMsg, setErrorMsg] = useState('');
|
||||
useSavedBadgeReset(saveState, setSaveState);
|
||||
|
||||
useEffect(() => {
|
||||
api<Preference[]>('/api/memory/preferences?category=communication')
|
||||
@@ -369,7 +380,6 @@ function NotificationsTab(): React.ReactElement {
|
||||
}),
|
||||
]);
|
||||
setSaveState('saved');
|
||||
setTimeout(() => setSaveState('idle'), 2000);
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : 'Failed to save preferences';
|
||||
setErrorMsg(message);
|
||||
|
||||
Reference in New Issue
Block a user