@@ -20,7 +20,6 @@ import MenuList from "@mui/material/MenuList"
20
20
import { useSearchParams } from "react-router-dom"
21
21
import { useQuery } from "@tanstack/react-query"
22
22
import { getUsers , getTemplates } from "api/api"
23
- import { useOrganizationId } from "hooks/useOrganizationId"
24
23
25
24
/** Filter */
26
25
@@ -94,6 +93,18 @@ type BaseOption = {
94
93
value : string
95
94
}
96
95
96
+ type OwnerOption = BaseOption & {
97
+ avatarUrl ?: string
98
+ }
99
+
100
+ type StatusOption = BaseOption & {
101
+ color : string
102
+ }
103
+
104
+ type TemplateOption = BaseOption & {
105
+ icon ?: string
106
+ }
107
+
97
108
type UseAutocompleteOptions < TOption extends BaseOption > = {
98
109
id : string
99
110
initialQuery ?: string
@@ -146,21 +157,118 @@ const useAutocomplete = <TOption extends BaseOption = BaseOption>({
146
157
}
147
158
}
148
159
149
- /** Components */
160
+ export const useUsersAutocomplete = (
161
+ initialOptionValue : string | undefined ,
162
+ onChange : ( option : OwnerOption | undefined ) => void ,
163
+ ) =>
164
+ useAutocomplete ( {
165
+ id : "owner" ,
166
+ getInitialOption : async ( ) => {
167
+ const usersRes = await getUsers ( { q : initialOptionValue , limit : 1 } )
168
+ const firstUser = usersRes . users . at ( 0 )
169
+ if ( firstUser && firstUser . username === initialOptionValue ) {
170
+ return {
171
+ label : firstUser . username ,
172
+ value : firstUser . username ,
173
+ avatarUrl : firstUser . avatar_url ,
174
+ }
175
+ }
176
+ return null
177
+ } ,
178
+ getOptions : async ( query ) => {
179
+ const usersRes = await getUsers ( { q : query , limit : 25 } )
180
+ return usersRes . users . map ( ( user ) => ( {
181
+ label : user . username ,
182
+ value : user . username ,
183
+ avatarUrl : user . avatar_url ,
184
+ } ) )
185
+ } ,
186
+ onChange,
187
+ } )
150
188
151
- type OwnerOption = BaseOption & {
152
- avatarUrl ?: string
153
- }
189
+ type UsersAutocomplete = ReturnType < typeof useUsersAutocomplete >
154
190
155
- type StatusOption = BaseOption & {
156
- color : string
191
+ export const useTemplatesAutocomplete = (
192
+ orgId : string ,
193
+ initialOptionValue : string | undefined ,
194
+ onChange : ( option : TemplateOption | undefined ) => void ,
195
+ ) => {
196
+ return useAutocomplete ( {
197
+ id : "template" ,
198
+ getInitialOption : async ( ) => {
199
+ const templates = await getTemplates ( orgId )
200
+ const template = templates . find (
201
+ ( template ) => template . name === initialOptionValue ,
202
+ )
203
+ if ( template ) {
204
+ return {
205
+ label :
206
+ template . display_name !== ""
207
+ ? template . display_name
208
+ : template . name ,
209
+ value : template . name ,
210
+ icon : template . icon ,
211
+ }
212
+ }
213
+ return null
214
+ } ,
215
+ getOptions : async ( query ) => {
216
+ const templates = await getTemplates ( orgId )
217
+ const filteredTemplates = templates . filter (
218
+ ( template ) =>
219
+ template . name . toLowerCase ( ) . includes ( query . toLowerCase ( ) ) ||
220
+ template . display_name . toLowerCase ( ) . includes ( query . toLowerCase ( ) ) ,
221
+ )
222
+ return filteredTemplates . map ( ( template ) => ( {
223
+ label :
224
+ template . display_name !== "" ? template . display_name : template . name ,
225
+ value : template . name ,
226
+ icon : template . icon ,
227
+ } ) )
228
+ } ,
229
+ onChange,
230
+ } )
157
231
}
158
232
159
- type TemplateOption = BaseOption & {
160
- icon ?: string
233
+ type TemplatesAutocomplete = ReturnType < typeof useTemplatesAutocomplete >
234
+
235
+ export const useStatusAutocomplete = (
236
+ initialOptionValue : string | undefined ,
237
+ onChange : ( option : StatusOption | undefined ) => void ,
238
+ ) => {
239
+ const statusOptions = WorkspaceStatuses . map ( ( status ) => {
240
+ const display = getDisplayWorkspaceStatus ( status )
241
+ return {
242
+ label : display . text ,
243
+ value : status ,
244
+ color : display . type ?? "warning" ,
245
+ } as StatusOption
246
+ } )
247
+ return useAutocomplete ( {
248
+ id : "status" ,
249
+ getInitialOption : async ( ) =>
250
+ statusOptions . find ( ( option ) => option . value === initialOptionValue ) ??
251
+ null ,
252
+ getOptions : async ( ) => statusOptions ,
253
+ onChange,
254
+ } )
161
255
}
162
256
163
- export const Filter = ( { filter } : { filter : UseFilterResult } ) => {
257
+ type StatusAutocomplete = ReturnType < typeof useStatusAutocomplete >
258
+
259
+ /** Components */
260
+
261
+ export const Filter = ( {
262
+ filter,
263
+ autocomplete,
264
+ } : {
265
+ filter : UseFilterResult
266
+ autocomplete : {
267
+ users : UsersAutocomplete
268
+ templates : TemplatesAutocomplete
269
+ status : StatusAutocomplete
270
+ }
271
+ } ) => {
164
272
const hasFilterQuery = filter . query !== ""
165
273
166
274
return (
@@ -200,56 +308,14 @@ export const Filter = ({ filter }: { filter: UseFilterResult }) => {
200
308
) ,
201
309
} }
202
310
/>
203
- < OwnerFilter
204
- initialOptionValue = { filter . values . owner }
205
- onChange = { ( option ) =>
206
- filter . update ( { ...filter . values , owner : option ?. value } )
207
- }
208
- />
209
- < TemplateFilter
210
- initialOptionValue = { filter . values . template }
211
- onChange = { ( option ) =>
212
- filter . update ( { ...filter . values , template : option ?. value } )
213
- }
214
- />
215
- < StatusFilter
216
- initialOptionValue = { filter . values . status }
217
- onChange = { ( option ) =>
218
- filter . update ( { ...filter . values , status : option ?. value } )
219
- }
220
- />
311
+ < OwnerFilter autocomplete = { autocomplete . users } />
312
+ < TemplatesFilter autocomplete = { autocomplete . templates } />
313
+ < StatusFilter autocomplete = { autocomplete . status } />
221
314
</ Box >
222
315
)
223
316
}
224
317
225
- const OwnerFilter : FC < {
226
- initialOptionValue ?: string
227
- onChange : ( option : OwnerOption | undefined ) => void
228
- } > = ( { initialOptionValue, onChange } ) => {
229
- const usersAutocomplete = useAutocomplete ( {
230
- id : "owner" ,
231
- getInitialOption : async ( ) => {
232
- const usersRes = await getUsers ( { q : initialOptionValue , limit : 1 } )
233
- const firstUser = usersRes . users . at ( 0 )
234
- if ( firstUser && firstUser . username === initialOptionValue ) {
235
- return {
236
- label : firstUser . username ,
237
- value : firstUser . username ,
238
- avatarUrl : firstUser . avatar_url ,
239
- }
240
- }
241
- return null
242
- } ,
243
- getOptions : async ( query ) => {
244
- const usersRes = await getUsers ( { q : query , limit : 25 } )
245
- return usersRes . users . map ( ( user ) => ( {
246
- label : user . username ,
247
- value : user . username ,
248
- avatarUrl : user . avatar_url ,
249
- } ) )
250
- } ,
251
- onChange,
252
- } )
318
+ const OwnerFilter = ( { autocomplete } : { autocomplete : UsersAutocomplete } ) => {
253
319
const buttonRef = useRef < HTMLButtonElement > ( null )
254
320
const [ isMenuOpen , setIsMenuOpen ] = useState ( false )
255
321
@@ -267,13 +333,13 @@ const OwnerFilter: FC<{
267
333
anchorEl = { buttonRef . current }
268
334
open = { isMenuOpen }
269
335
onClose = { handleClose }
270
- options = { usersAutocomplete . searchOptions }
336
+ options = { autocomplete . searchOptions }
271
337
renderOption = { ( option ) => (
272
338
< MenuItem
273
339
key = { option . label }
274
- selected = { option . value === usersAutocomplete . selectedOption ?. value }
340
+ selected = { option . value === autocomplete . selectedOption ?. value }
275
341
onClick = { ( ) => {
276
- usersAutocomplete . selectOption ( option )
342
+ autocomplete . selectOption ( option )
277
343
handleClose ( )
278
344
} }
279
345
>
@@ -292,46 +358,11 @@ const OwnerFilter: FC<{
292
358
)
293
359
}
294
360
295
- const TemplateFilter : FC < {
296
- initialOptionValue ?: string
297
- onChange : ( value : TemplateOption | undefined ) => void
298
- } > = ( { initialOptionValue, onChange } ) => {
299
- const orgId = useOrganizationId ( )
300
- const templatesAutocomplete = useAutocomplete ( {
301
- id : "template" ,
302
- getInitialOption : async ( ) => {
303
- const templates = await getTemplates ( orgId )
304
- const template = templates . find (
305
- ( template ) => template . name === initialOptionValue ,
306
- )
307
- if ( template ) {
308
- return {
309
- label :
310
- template . display_name !== ""
311
- ? template . display_name
312
- : template . name ,
313
- value : template . name ,
314
- icon : template . icon ,
315
- }
316
- }
317
- return null
318
- } ,
319
- getOptions : async ( query ) => {
320
- const templates = await getTemplates ( orgId )
321
- const filteredTemplates = templates . filter (
322
- ( template ) =>
323
- template . name . toLowerCase ( ) . includes ( query . toLowerCase ( ) ) ||
324
- template . display_name . toLowerCase ( ) . includes ( query . toLowerCase ( ) ) ,
325
- )
326
- return filteredTemplates . map ( ( template ) => ( {
327
- label :
328
- template . display_name !== "" ? template . display_name : template . name ,
329
- value : template . name ,
330
- icon : template . icon ,
331
- } ) )
332
- } ,
333
- onChange,
334
- } )
361
+ const TemplatesFilter = ( {
362
+ autocomplete,
363
+ } : {
364
+ autocomplete : TemplatesAutocomplete
365
+ } ) => {
335
366
const buttonRef = useRef < HTMLButtonElement > ( null )
336
367
const [ isMenuOpen , setIsMenuOpen ] = useState ( false )
337
368
@@ -349,15 +380,13 @@ const TemplateFilter: FC<{
349
380
anchorEl = { buttonRef . current }
350
381
open = { isMenuOpen }
351
382
onClose = { handleClose }
352
- options = { templatesAutocomplete . searchOptions }
383
+ options = { autocomplete . searchOptions }
353
384
renderOption = { ( option ) => (
354
385
< MenuItem
355
386
key = { option . label }
356
- selected = {
357
- option . value === templatesAutocomplete . selectedOption ?. value
358
- }
387
+ selected = { option . value === autocomplete . selectedOption ?. value }
359
388
onClick = { ( ) => {
360
- templatesAutocomplete . selectOption ( option )
389
+ autocomplete . selectOption ( option )
361
390
handleClose ( )
362
391
} }
363
392
>
@@ -386,26 +415,11 @@ const TemplateAvatar: FC<
386
415
)
387
416
}
388
417
389
- const StatusFilter : FC < {
390
- initialOptionValue ?: string
391
- onChange : ( value : StatusOption | undefined ) => void
392
- } > = ( { initialOptionValue, onChange } ) => {
393
- const statusOptions = WorkspaceStatuses . map ( ( status ) => {
394
- const display = getDisplayWorkspaceStatus ( status )
395
- return {
396
- label : display . text ,
397
- value : status ,
398
- color : display . type ?? "warning" ,
399
- } as StatusOption
400
- } )
401
- const statusAutocomplete = useAutocomplete ( {
402
- id : "status" ,
403
- getInitialOption : async ( ) =>
404
- statusOptions . find ( ( option ) => option . value === initialOptionValue ) ??
405
- null ,
406
- getOptions : async ( ) => statusOptions ,
407
- onChange,
408
- } )
418
+ const StatusFilter = ( {
419
+ autocomplete,
420
+ } : {
421
+ autocomplete : StatusAutocomplete
422
+ } ) => {
409
423
const buttonRef = useRef < HTMLButtonElement > ( null )
410
424
const [ isMenuOpen , setIsMenuOpen ] = useState ( false )
411
425
@@ -424,12 +438,12 @@ const StatusFilter: FC<{
424
438
open = { isMenuOpen }
425
439
onClose = { handleClose }
426
440
>
427
- { statusAutocomplete . searchOptions ?. map ( ( option ) => (
441
+ { autocomplete . searchOptions ?. map ( ( option ) => (
428
442
< MenuItem
429
443
key = { option . label }
430
- selected = { option . value === statusAutocomplete . selectedOption ?. value }
444
+ selected = { option . value === autocomplete . selectedOption ?. value }
431
445
onClick = { ( ) => {
432
- statusAutocomplete . selectOption ( option )
446
+ autocomplete . selectOption ( option )
433
447
handleClose ( )
434
448
} }
435
449
>
0 commit comments