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;
|
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 ────────────────────────────────────────────────────────────────
|
// ─── Main Page ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export function SettingsPage(): React.ReactElement {
|
export function SettingsPage(): React.ReactElement {
|
||||||
@@ -111,6 +121,7 @@ function ProfileTab({
|
|||||||
const [image, setImage] = useState(session?.user.image ?? '');
|
const [image, setImage] = useState(session?.user.image ?? '');
|
||||||
const [saveState, setSaveState] = useState<SaveState>('idle');
|
const [saveState, setSaveState] = useState<SaveState>('idle');
|
||||||
const [errorMsg, setErrorMsg] = useState('');
|
const [errorMsg, setErrorMsg] = useState('');
|
||||||
|
useSavedBadgeReset(saveState, setSaveState);
|
||||||
|
|
||||||
// Sync from session when it loads
|
// Sync from session when it loads
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -131,7 +142,6 @@ function ProfileTab({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSaveState('saved');
|
setSaveState('saved');
|
||||||
setTimeout(() => setSaveState('idle'), 2000);
|
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
const message = err instanceof Error ? err.message : 'Failed to update profile';
|
const message = err instanceof Error ? err.message : 'Failed to update profile';
|
||||||
setErrorMsg(message);
|
setErrorMsg(message);
|
||||||
@@ -194,6 +204,7 @@ function AppearanceTab(): React.ReactElement {
|
|||||||
const [defaultModel, setDefaultModel] = useState('');
|
const [defaultModel, setDefaultModel] = useState('');
|
||||||
const [saveState, setSaveState] = useState<SaveState>('idle');
|
const [saveState, setSaveState] = useState<SaveState>('idle');
|
||||||
const [errorMsg, setErrorMsg] = useState('');
|
const [errorMsg, setErrorMsg] = useState('');
|
||||||
|
useSavedBadgeReset(saveState, setSaveState);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api<Preference[]>('/api/memory/preferences?category=appearance')
|
api<Preference[]>('/api/memory/preferences?category=appearance')
|
||||||
@@ -239,7 +250,6 @@ function AppearanceTab(): React.ReactElement {
|
|||||||
: []),
|
: []),
|
||||||
]);
|
]);
|
||||||
setSaveState('saved');
|
setSaveState('saved');
|
||||||
setTimeout(() => setSaveState('idle'), 2000);
|
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
const message = err instanceof Error ? err.message : 'Failed to save preferences';
|
const message = err instanceof Error ? err.message : 'Failed to save preferences';
|
||||||
setErrorMsg(message);
|
setErrorMsg(message);
|
||||||
@@ -323,6 +333,7 @@ function NotificationsTab(): React.ReactElement {
|
|||||||
const [emailDigest, setEmailDigest] = useState(false);
|
const [emailDigest, setEmailDigest] = useState(false);
|
||||||
const [saveState, setSaveState] = useState<SaveState>('idle');
|
const [saveState, setSaveState] = useState<SaveState>('idle');
|
||||||
const [errorMsg, setErrorMsg] = useState('');
|
const [errorMsg, setErrorMsg] = useState('');
|
||||||
|
useSavedBadgeReset(saveState, setSaveState);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api<Preference[]>('/api/memory/preferences?category=communication')
|
api<Preference[]>('/api/memory/preferences?category=communication')
|
||||||
@@ -369,7 +380,6 @@ function NotificationsTab(): React.ReactElement {
|
|||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
setSaveState('saved');
|
setSaveState('saved');
|
||||||
setTimeout(() => setSaveState('idle'), 2000);
|
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
const message = err instanceof Error ? err.message : 'Failed to save preferences';
|
const message = err instanceof Error ? err.message : 'Failed to save preferences';
|
||||||
setErrorMsg(message);
|
setErrorMsg(message);
|
||||||
|
|||||||
Reference in New Issue
Block a user