Skip to content

Commit 70b723d

Browse files
committed
fix: debounce profile update notifications to prevent toast spam
a new toast was being triggered for every character input.
1 parent 294adfd commit 70b723d

File tree

1 file changed

+27
-12
lines changed

1 file changed

+27
-12
lines changed

app/components/@settings/tabs/profile/ProfileTab.tsx

+27-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from 'react';
1+
import { useState, useCallback, useEffect } from 'react';
22
import { useStore } from '@nanostores/react';
33
import { classNames } from '~/utils/classNames';
44
import { profileStore, updateProfile } from '~/lib/stores/profile';
@@ -7,6 +7,32 @@ import { toast } from 'react-toastify';
77
export default function ProfileTab() {
88
const profile = useStore(profileStore);
99
const [isUploading, setIsUploading] = useState(false);
10+
const [toastTimeout, setToastTimeout] = useState<NodeJS.Timeout | null>(null);
11+
12+
const handleProfileUpdate = useCallback(
13+
(field: 'username' | 'bio', value: string) => {
14+
updateProfile({ [field]: value });
15+
16+
if (toastTimeout) {
17+
clearTimeout(toastTimeout);
18+
}
19+
20+
const timeout = setTimeout(() => {
21+
toast.success(`${field.charAt(0).toUpperCase() + field.slice(1)} updated`);
22+
}, 1000);
23+
24+
setToastTimeout(timeout);
25+
},
26+
[toastTimeout],
27+
);
28+
29+
useEffect(() => {
30+
return () => {
31+
if (toastTimeout) {
32+
clearTimeout(toastTimeout);
33+
}
34+
};
35+
}, [toastTimeout]);
1036

1137
const handleAvatarUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
1238
const file = e.target.files?.[0];
@@ -41,17 +67,6 @@ export default function ProfileTab() {
4167
}
4268
};
4369

44-
const handleProfileUpdate = (field: 'username' | 'bio', value: string) => {
45-
updateProfile({ [field]: value });
46-
47-
// Only show toast for completed typing (after 1 second of no typing)
48-
const debounceToast = setTimeout(() => {
49-
toast.success(`${field.charAt(0).toUpperCase() + field.slice(1)} updated`);
50-
}, 1000);
51-
52-
return () => clearTimeout(debounceToast);
53-
};
54-
5570
return (
5671
<div className="max-w-2xl mx-auto">
5772
<div className="space-y-6">

0 commit comments

Comments
 (0)