1
- import { useState } from 'react' ;
1
+ import { useState , useCallback , useEffect } from 'react' ;
2
2
import { useStore } from '@nanostores/react' ;
3
3
import { classNames } from '~/utils/classNames' ;
4
4
import { profileStore , updateProfile } from '~/lib/stores/profile' ;
@@ -7,6 +7,32 @@ import { toast } from 'react-toastify';
7
7
export default function ProfileTab ( ) {
8
8
const profile = useStore ( profileStore ) ;
9
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 ] ) ;
10
36
11
37
const handleAvatarUpload = async ( e : React . ChangeEvent < HTMLInputElement > ) => {
12
38
const file = e . target . files ?. [ 0 ] ;
@@ -41,17 +67,6 @@ export default function ProfileTab() {
41
67
}
42
68
} ;
43
69
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
70
return (
56
71
< div className = "max-w-2xl mx-auto" >
57
72
< div className = "space-y-6" >
0 commit comments