KevIsDev
commited on
Commit
·
70b723d
1
Parent(s):
294adfd
fix: debounce profile update notifications to prevent toast spam
Browse files
app/components/@settings/tabs/profile/ProfileTab.tsx
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { useState } from 'react';
|
2 |
import { useStore } from '@nanostores/react';
|
3 |
import { classNames } from '~/utils/classNames';
|
4 |
import { profileStore, updateProfile } from '~/lib/stores/profile';
|
@@ -7,6 +7,32 @@ import { toast } from 'react-toastify';
|
|
7 |
export default function ProfileTab() {
|
8 |
const profile = useStore(profileStore);
|
9 |
const [isUploading, setIsUploading] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
const handleAvatarUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
12 |
const file = e.target.files?.[0];
|
@@ -41,17 +67,6 @@ export default function ProfileTab() {
|
|
41 |
}
|
42 |
};
|
43 |
|
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 |
-
|
55 |
return (
|
56 |
<div className="max-w-2xl mx-auto">
|
57 |
<div className="space-y-6">
|
|
|
1 |
+
import { useState, useCallback, useEffect } from 'react';
|
2 |
import { useStore } from '@nanostores/react';
|
3 |
import { classNames } from '~/utils/classNames';
|
4 |
import { profileStore, updateProfile } from '~/lib/stores/profile';
|
|
|
7 |
export default function ProfileTab() {
|
8 |
const profile = useStore(profileStore);
|
9 |
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]);
|
36 |
|
37 |
const handleAvatarUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
38 |
const file = e.target.files?.[0];
|
|
|
67 |
}
|
68 |
};
|
69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
return (
|
71 |
<div className="max-w-2xl mx-auto">
|
72 |
<div className="space-y-6">
|