@@ -25,6 +25,13 @@ import {
25
25
PopoverContent ,
26
26
PopoverTrigger ,
27
27
} from "@/components/ui/popover" ;
28
+ import {
29
+ Select ,
30
+ SelectContent ,
31
+ SelectItem ,
32
+ SelectTrigger ,
33
+ SelectValue ,
34
+ } from "@/components/ui/select" ;
28
35
import { toast } from "@/components/ui/use-toast" ;
29
36
import { useTranslation } from "@/lib/i18n/client" ;
30
37
import data from "@emoji-mart/data" ;
@@ -38,21 +45,24 @@ import {
38
45
useCreateBookmarkList ,
39
46
useEditBookmarkList ,
40
47
} from "@hoarder/shared-react/hooks/lists" ;
41
- import { ZBookmarkList } from "@hoarder/shared/types/lists" ;
48
+ import {
49
+ ZBookmarkList ,
50
+ zNewBookmarkListSchema ,
51
+ } from "@hoarder/shared/types/lists" ;
42
52
43
53
import { BookmarkListSelector } from "./BookmarkListSelector" ;
44
54
45
55
export function EditListModal ( {
46
56
open : userOpen ,
47
57
setOpen : userSetOpen ,
48
58
list,
49
- parent ,
59
+ prefill ,
50
60
children,
51
61
} : {
52
62
open ?: boolean ;
53
63
setOpen ?: ( v : boolean ) => void ;
54
64
list ?: ZBookmarkList ;
55
- parent ?: ZBookmarkList ;
65
+ prefill ?: Partial < Omit < ZBookmarkList , "id" > > ;
56
66
children ?: React . ReactNode ;
57
67
} ) {
58
68
const { t } = useTranslation ( ) ;
@@ -64,17 +74,14 @@ export function EditListModal({
64
74
throw new Error ( "You must provide both open and setOpen or neither" ) ;
65
75
}
66
76
const [ customOpen , customSetOpen ] = useState ( false ) ;
67
- const formSchema = z . object ( {
68
- name : z . string ( ) ,
69
- icon : z . string ( ) ,
70
- parentId : z . string ( ) . nullish ( ) ,
71
- } ) ;
72
- const form = useForm < z . infer < typeof formSchema > > ( {
73
- resolver : zodResolver ( formSchema ) ,
77
+ const form = useForm < z . infer < typeof zNewBookmarkListSchema > > ( {
78
+ resolver : zodResolver ( zNewBookmarkListSchema ) ,
74
79
defaultValues : {
75
- name : list ?. name ?? "" ,
76
- icon : list ?. icon ?? "🚀" ,
77
- parentId : list ?. parentId ?? parent ?. id ,
80
+ name : list ?. name ?? prefill ?. name ?? "" ,
81
+ icon : list ?. icon ?? prefill ?. icon ?? "🚀" ,
82
+ parentId : list ?. parentId ?? prefill ?. parentId ,
83
+ type : list ?. type ?? prefill ?. type ?? "manual" ,
84
+ query : list ?. query ?? prefill ?. query ?? undefined ,
78
85
} ,
79
86
} ) ;
80
87
const [ open , setOpen ] = [
@@ -84,9 +91,11 @@ export function EditListModal({
84
91
85
92
useEffect ( ( ) => {
86
93
form . reset ( {
87
- name : list ?. name ?? "" ,
88
- icon : list ?. icon ?? "🚀" ,
89
- parentId : list ?. parentId ?? parent ?. id ,
94
+ name : list ?. name ?? prefill ?. name ?? "" ,
95
+ icon : list ?. icon ?? prefill ?. icon ?? "🚀" ,
96
+ parentId : list ?. parentId ?? prefill ?. parentId ,
97
+ type : list ?. type ?? prefill ?. type ?? "manual" ,
98
+ query : list ?. query ?? prefill ?. query ?? undefined ,
90
99
} ) ;
91
100
} , [ open ] ) ;
92
101
@@ -154,14 +163,24 @@ export function EditListModal({
154
163
}
155
164
} ,
156
165
} ) ;
166
+ const listType = form . watch ( "type" ) ;
167
+
168
+ useEffect ( ( ) => {
169
+ if ( listType !== "smart" ) {
170
+ form . resetField ( "query" ) ;
171
+ }
172
+ } , [ listType ] ) ;
157
173
158
174
const isEdit = ! ! list ;
159
175
const isPending = isCreating || isEditing ;
160
176
161
- const onSubmit = form . handleSubmit ( ( value : z . infer < typeof formSchema > ) => {
162
- value . parentId = value . parentId === "" ? null : value . parentId ;
163
- isEdit ? editList ( { ...value , listId : list . id } ) : createList ( value ) ;
164
- } ) ;
177
+ const onSubmit = form . handleSubmit (
178
+ ( value : z . infer < typeof zNewBookmarkListSchema > ) => {
179
+ value . parentId = value . parentId === "" ? null : value . parentId ;
180
+ value . query = value . type === "smart" ? value . query : undefined ;
181
+ isEdit ? editList ( { ...value , listId : list . id } ) : createList ( value ) ;
182
+ } ,
183
+ ) ;
165
184
166
185
return (
167
186
< Dialog
@@ -176,7 +195,9 @@ export function EditListModal({
176
195
< Form { ...form } >
177
196
< form onSubmit = { onSubmit } >
178
197
< DialogHeader >
179
- < DialogTitle > { isEdit ? "Edit" : "New" } List</ DialogTitle >
198
+ < DialogTitle >
199
+ { isEdit ? t ( "lists.edit_list" ) : t ( "lists.new_list" ) }
200
+ </ DialogTitle >
180
201
</ DialogHeader >
181
202
< div className = "flex w-full gap-2 py-4" >
182
203
< FormField
@@ -232,15 +253,15 @@ export function EditListModal({
232
253
render = { ( { field } ) => {
233
254
return (
234
255
< FormItem className = "grow pb-4" >
235
- < FormLabel > Parent </ FormLabel >
256
+ < FormLabel > { t ( "lists.parent_list" ) } </ FormLabel >
236
257
< div className = "flex items-center gap-1" >
237
258
< FormControl >
238
259
< BookmarkListSelector
239
260
// Hide the current list from the list of parents
240
261
hideSubtreeOf = { list ? list . id : undefined }
241
262
value = { field . value }
242
263
onChange = { field . onChange }
243
- placeholder = { "No Parent" }
264
+ placeholder = { t ( "lists.no_parent" ) }
244
265
/>
245
266
</ FormControl >
246
267
< Button
@@ -258,6 +279,58 @@ export function EditListModal({
258
279
) ;
259
280
} }
260
281
/>
282
+ < FormField
283
+ control = { form . control }
284
+ name = "type"
285
+ render = { ( { field } ) => {
286
+ return (
287
+ < FormItem className = "grow pb-4" >
288
+ < FormLabel > { t ( "lists.list_type" ) } </ FormLabel >
289
+ < FormControl >
290
+ < Select
291
+ disabled = { isEdit }
292
+ onValueChange = { field . onChange }
293
+ value = { field . value }
294
+ >
295
+ < SelectTrigger className = "w-full" >
296
+ < SelectValue />
297
+ </ SelectTrigger >
298
+ < SelectContent >
299
+ < SelectItem value = "manual" >
300
+ { t ( "lists.manual_list" ) }
301
+ </ SelectItem >
302
+ < SelectItem value = "smart" >
303
+ { t ( "lists.smart_list" ) }
304
+ </ SelectItem >
305
+ </ SelectContent >
306
+ </ Select >
307
+ </ FormControl >
308
+ < FormMessage />
309
+ </ FormItem >
310
+ ) ;
311
+ } }
312
+ />
313
+ { listType === "smart" && (
314
+ < FormField
315
+ control = { form . control }
316
+ name = "query"
317
+ render = { ( { field } ) => {
318
+ return (
319
+ < FormItem className = "grow pb-4" >
320
+ < FormLabel > { t ( "lists.search_query" ) } </ FormLabel >
321
+ < FormControl >
322
+ < Input
323
+ value = { field . value }
324
+ onChange = { field . onChange }
325
+ placeholder = { t ( "lists.search_query" ) }
326
+ />
327
+ </ FormControl >
328
+ < FormMessage />
329
+ </ FormItem >
330
+ ) ;
331
+ } }
332
+ />
333
+ ) }
261
334
< DialogFooter className = "sm:justify-end" >
262
335
< DialogClose asChild >
263
336
< Button type = "button" variant = "secondary" >
0 commit comments