import { useEffect, useMemo, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { ActionButton } from "@/components/ui/action-button"; import { Button } from "@/components/ui/button"; import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { toast } from "@/components/ui/use-toast"; import { useTranslation } from "@/lib/i18n/client"; import data from "@emoji-mart/data"; import Picker from "@emoji-mart/react"; import { zodResolver } from "@hookform/resolvers/zod"; import { X } from "lucide-react"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { useCreateBookmarkList, useEditBookmarkList, } from "@karakeep/shared-react/hooks/lists"; import { parseSearchQuery } from "@karakeep/shared/searchQueryParser"; import { ZBookmarkList, zNewBookmarkListSchema, } from "@karakeep/shared/types/lists"; import QueryExplainerTooltip from "../search/QueryExplainerTooltip"; import { BookmarkListSelector } from "./BookmarkListSelector"; export function EditListModal({ open: userOpen, setOpen: userSetOpen, list, prefill, children, }: { open?: boolean; setOpen?: (v: boolean) => void; list?: ZBookmarkList; prefill?: Partial>; children?: React.ReactNode; }) { const { t } = useTranslation(); const router = useRouter(); if ( (userOpen !== undefined && !userSetOpen) || (userOpen === undefined && userSetOpen) ) { throw new Error("You must provide both open and setOpen or neither"); } const [customOpen, customSetOpen] = useState(false); const form = useForm>({ resolver: zodResolver(zNewBookmarkListSchema), defaultValues: { name: list?.name ?? prefill?.name ?? "", icon: list?.icon ?? prefill?.icon ?? "🚀", parentId: list?.parentId ?? prefill?.parentId, type: list?.type ?? prefill?.type ?? "manual", query: list?.query ?? prefill?.query ?? undefined, }, }); const [open, setOpen] = [ userOpen ?? customOpen, userSetOpen ?? customSetOpen, ]; useEffect(() => { form.reset({ name: list?.name ?? prefill?.name ?? "", icon: list?.icon ?? prefill?.icon ?? "🚀", parentId: list?.parentId ?? prefill?.parentId, type: list?.type ?? prefill?.type ?? "manual", query: list?.query ?? prefill?.query ?? undefined, }); }, [open]); const parsedSearchQuery = useMemo(() => { const query = form.getValues().query; if (!query) { return undefined; } return parseSearchQuery(query); }, [form.watch("query")]); const { mutate: createList, isPending: isCreating } = useCreateBookmarkList({ onSuccess: (resp) => { toast({ description: t("toasts.lists.created"), }); setOpen(false); router.push(`/dashboard/lists/${resp.id}`); form.reset(); }, onError: (e) => { if (e.data?.code == "BAD_REQUEST") { if (e.data.zodError) { toast({ variant: "destructive", description: Object.values(e.data.zodError.fieldErrors) .flat() .join("\n"), }); } else { toast({ variant: "destructive", description: e.message, }); } } else { toast({ variant: "destructive", title: t("common.something_went_wrong"), }); } }, }); const { mutate: editList, isPending: isEditing } = useEditBookmarkList({ onSuccess: () => { toast({ description: t("toasts.lists.updated"), }); setOpen(false); form.reset(); }, onError: (e) => { if (e.data?.code == "BAD_REQUEST") { if (e.data.zodError) { toast({ variant: "destructive", description: Object.values(e.data.zodError.fieldErrors) .flat() .join("\n"), }); } else { toast({ variant: "destructive", description: e.message, }); } } else { toast({ variant: "destructive", title: t("common.something_went_wrong"), }); } }, }); const listType = form.watch("type"); useEffect(() => { if (listType !== "smart") { form.resetField("query"); } }, [listType]); const isEdit = !!list; const isPending = isCreating || isEditing; const onSubmit = form.handleSubmit( (value: z.infer) => { value.parentId = value.parentId === "" ? null : value.parentId; value.query = value.type === "smart" ? value.query : undefined; isEdit ? editList({ ...value, listId: list.id }) : createList(value); }, ); return ( { form.reset(); setOpen(s); }} > {children && {children}}
{isEdit ? t("lists.edit_list") : t("lists.new_list")}
{ return ( {field.value} field.onChange(e.native) } /> ); }} /> { return ( ); }} />
{ return ( {t("lists.parent_list")}
); }} /> { return ( {t("lists.list_type")} ); }} /> {listType === "smart" && ( { return ( {t("lists.search_query")}
{parsedSearchQuery && ( )}
{t("lists.search_query_help")}
); }} /> )} {list ? t("actions.save") : t("actions.create")}
); }