1
1
import { useQuery , useMutation , useQueryClient } from '@tanstack/react-query' ;
2
- import { useRef , useEffect } from 'react' ;
2
+ import { useRef , useEffect , useState } from 'react' ;
3
3
import federalist from '@util/federalistApi' ;
4
4
import { REFETCH_INTERVAL } from './utils' ;
5
5
@@ -10,55 +10,139 @@ const INITIAL_DATA = {
10
10
totalItems : 0 ,
11
11
} ;
12
12
13
+ const TIMEOUT_DURATION = 5000 ;
14
+
13
15
export default function useFileStorage (
14
16
fileStorageId ,
15
- path = '' ,
16
- sortKey = null ,
17
- sortOrder = null ,
17
+ path = '/ ' ,
18
+ sortKey = 'updatedAt' ,
19
+ sortOrder = 'desc' ,
18
20
page = 1 ,
19
21
) {
20
22
const previousData = useRef ( ) ;
21
23
const queryClient = useQueryClient ( ) ;
22
24
23
- const { data, isLoading, isFetching, isPending, isPlaceholderData, error } = useQuery ( {
24
- queryKey : [ 'fileStorage' , fileStorageId , path , sortKey , sortOrder , page ] ,
25
- queryFn : ( ) =>
26
- federalist . fetchPublicFiles ( fileStorageId , path , sortKey , sortOrder , page ) ,
27
- refetchInterval : REFETCH_INTERVAL ,
28
- refetchIntervalInBackground : false ,
29
- enabled : ! ! fileStorageId ,
30
- keepPreviousData : true ,
31
- staleTime : 2000 ,
32
- placeholderData : previousData . current || INITIAL_DATA ,
33
- onError : ( err ) => {
34
- // using an empty string so that we don't end up with "undefined" at the end
35
- throw new Error ( 'Failed to fetch public files ' + ( err ?. message || '' ) ) ;
36
- } ,
37
- } ) ;
25
+ const [ uploadError , setUploadError ] = useState ( null ) ;
26
+ const [ uploadSuccess , setUploadSuccess ] = useState ( null ) ;
27
+ const [ deleteError , setDeleteError ] = useState ( null ) ;
28
+ const [ deleteSuccess , setDeleteSuccess ] = useState ( null ) ;
29
+ const [ createFolderError , setCreateFolderError ] = useState ( null ) ;
30
+ const [ createFolderSuccess , setCreateFolderSuccess ] = useState ( null ) ;
31
+ const uploadTimeout = useRef ( null ) ;
32
+ const deleteTimeout = useRef ( null ) ;
33
+ const createFolderTimeout = useRef ( null ) ;
34
+
35
+ const handleSuccess = ( setSuccess , setError , timeoutRef , message ) => {
36
+ setError ( null ) ;
37
+ setSuccess ( ( ) => {
38
+ if ( timeoutRef . current ) clearTimeout ( timeoutRef . current ) ;
39
+ timeoutRef . current = setTimeout ( ( ) => setSuccess ( null ) , TIMEOUT_DURATION ) ;
40
+ return message ;
41
+ } ) ;
42
+ queryClient . invalidateQueries ( {
43
+ queryKey : [ 'fileStorage' , fileStorageId , path , sortKey , sortOrder , page ] ,
44
+ } ) ;
45
+ } ;
46
+
47
+ const handleError = ( setError , setSuccess , timeoutRef , errorMessage ) => {
48
+ setSuccess ( null ) ;
49
+ setError ( ( ) => {
50
+ if ( timeoutRef . current ) clearTimeout ( timeoutRef . current ) ;
51
+ timeoutRef . current = setTimeout ( ( ) => setError ( null ) , TIMEOUT_DURATION ) ;
52
+ return errorMessage ;
53
+ } ) ;
54
+ } ;
38
55
56
+ const { data, isLoading, isFetching, isPending, isPlaceholderData, isError, error } =
57
+ useQuery ( {
58
+ queryKey : [ 'fileStorage' , fileStorageId , path , sortKey , sortOrder , page ] ,
59
+ queryFn : ( ) =>
60
+ federalist . fetchPublicFiles ( fileStorageId , path , sortKey , sortOrder , page ) ,
61
+ refetchInterval : REFETCH_INTERVAL ,
62
+ refetchIntervalInBackground : false ,
63
+ enabled : ! ! fileStorageId ,
64
+ keepPreviousData : true ,
65
+ staleTime : 2000 ,
66
+ placeholderData : previousData . current || INITIAL_DATA ,
67
+ onError : ( err ) => {
68
+ // using an empty string so that we don't end up with "undefined" at the end
69
+ throw new Error ( 'Failed to fetch public files ' + ( err ?. message || '' ) ) ;
70
+ } ,
71
+ } ) ;
39
72
useEffect ( ( ) => {
40
73
if ( data !== undefined ) {
41
74
previousData . current = data ;
42
75
}
43
76
} , [ data ] ) ;
44
77
78
+ useEffect ( ( ) => {
79
+ return ( ) => {
80
+ if ( uploadTimeout . current ) clearTimeout ( uploadTimeout . current ) ;
81
+ if ( deleteTimeout . current ) clearTimeout ( deleteTimeout . current ) ;
82
+ if ( createFolderTimeout . current ) clearTimeout ( createFolderTimeout . current ) ;
83
+ } ;
84
+ } , [ ] ) ;
85
+
45
86
const deleteMutation = useMutation ( {
46
- mutationFn : ( item ) => federalist . deletePublicItem ( fileStorageId , item . id ) ,
47
- onSuccess : ( ) => {
48
- // Invalidate the query to refetch the file list after deletion.
49
- return queryClient . invalidateQueries ( {
50
- queryKey : [ 'fileStorage' , fileStorageId , path , sortKey , sortOrder , page ] ,
51
- } ) ;
52
- } ,
53
- onError : ( err ) => {
54
- // using an empty string so that we don't end up with "undefined" at the end
55
- throw new Error ( 'Failed to delete file ' + ( err ?. message || '' ) ) ;
87
+ mutationFn : ( { item } ) => federalist . deletePublicItem ( fileStorageId , item . id ) ,
88
+ onSuccess : ( ) =>
89
+ handleSuccess (
90
+ setDeleteSuccess ,
91
+ setDeleteError ,
92
+ deleteTimeout ,
93
+ 'File deleted successfully.' ,
94
+ ) ,
95
+ onError : ( err ) =>
96
+ handleError (
97
+ setDeleteError ,
98
+ setDeleteSuccess ,
99
+ deleteTimeout ,
100
+ err ?. message || 'Failed to delete file.' ,
101
+ ) ,
102
+ } ) ;
103
+
104
+ const uploadMutation = useMutation ( {
105
+ mutationFn : ( { parent = '/' , file } ) =>
106
+ federalist . uploadPublicFile ( fileStorageId , parent , file ) ,
107
+ onSuccess : ( ) =>
108
+ handleSuccess (
109
+ setUploadSuccess ,
110
+ setUploadError ,
111
+ uploadTimeout ,
112
+ 'File uploaded successfully.' ,
113
+ ) ,
114
+ onError : ( err , { file } ) => {
115
+ const errorMessage = err ?. message || 'Upload failed.' ;
116
+ const formattedMessage = errorMessage . includes ( 'already exists' )
117
+ ? `A file named "${ file . name } " already exists in this folder.`
118
+ : errorMessage ;
119
+ handleError ( setUploadError , setUploadSuccess , uploadTimeout , formattedMessage ) ;
56
120
} ,
57
121
} ) ;
58
122
59
- async function deleteItem ( item ) {
60
- return deleteMutation . mutate ( item ) ;
61
- }
123
+ const createFolderMutation = useMutation ( {
124
+ mutationFn : ( { parent = '/' , name } ) =>
125
+ federalist . createPublicDirectory ( fileStorageId , parent , name ) ,
126
+ onSuccess : ( ) =>
127
+ handleSuccess (
128
+ setCreateFolderSuccess ,
129
+ setCreateFolderError ,
130
+ createFolderTimeout ,
131
+ 'Folder created successfully.' ,
132
+ ) ,
133
+ onError : ( err , { name } ) => {
134
+ const errorMessage = err ?. message || 'Could not create folder.' ;
135
+ const formattedMessage = errorMessage . includes ( 'already exists' )
136
+ ? `A folder named "${ name } " already exists in this folder.`
137
+ : errorMessage ;
138
+ handleError (
139
+ setCreateFolderError ,
140
+ setCreateFolderSuccess ,
141
+ createFolderTimeout ,
142
+ formattedMessage ,
143
+ ) ;
144
+ } ,
145
+ } ) ;
62
146
63
147
return {
64
148
...data ,
@@ -67,9 +151,16 @@ export default function useFileStorage(
67
151
isFetching,
68
152
isPending,
69
153
isPlaceholderData,
70
- error,
71
- deleteItem,
72
- deleteError : deleteMutation . error ,
73
- deleteSuccess : deleteMutation . isSuccess ,
154
+ isError,
155
+ defaultError : error ,
156
+ deleteItem : ( item ) => deleteMutation . mutateAsync ( { item } ) ,
157
+ deleteError,
158
+ deleteSuccess,
159
+ uploadFile : ( parent , file ) => uploadMutation . mutateAsync ( { parent, file } ) ,
160
+ uploadError,
161
+ uploadSuccess,
162
+ createFolder : ( parent , name ) => createFolderMutation . mutateAsync ( { parent, name } ) ,
163
+ createFolderError,
164
+ createFolderSuccess,
74
165
} ;
75
166
}
0 commit comments