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">