139 lines
3.5 KiB
TypeScript
139 lines
3.5 KiB
TypeScript
import { ActionButton } from "@/components/ui/action-button";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Dialog,
|
|
DialogClose,
|
|
DialogContent,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog";
|
|
import {
|
|
Form,
|
|
FormControl,
|
|
FormField,
|
|
FormItem,
|
|
FormMessage,
|
|
} from "@/components/ui/form";
|
|
import { toast } from "@/components/ui/use-toast";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { useForm } from "react-hook-form";
|
|
import { z } from "zod";
|
|
|
|
import { useAddBookmarkToList } from "@hoarder/shared-react/hooks/lists";
|
|
|
|
import { BookmarkListSelector } from "../lists/BookmarkListSelector";
|
|
|
|
export default function BulkManageListsModal({
|
|
bookmarkIds,
|
|
open,
|
|
setOpen,
|
|
}: {
|
|
bookmarkIds: string[];
|
|
open: boolean;
|
|
setOpen: (open: boolean) => void;
|
|
}) {
|
|
const formSchema = z.object({
|
|
listId: z.string({
|
|
required_error: "Please select a list",
|
|
}),
|
|
});
|
|
const form = useForm<z.infer<typeof formSchema>>({
|
|
resolver: zodResolver(formSchema),
|
|
defaultValues: {
|
|
listId: undefined,
|
|
},
|
|
});
|
|
|
|
const { mutateAsync: addToList, isPending: isAddingToListPending } =
|
|
useAddBookmarkToList({
|
|
onSettled: () => {
|
|
form.resetField("listId");
|
|
},
|
|
onError: (e) => {
|
|
if (e.data?.code == "BAD_REQUEST") {
|
|
toast({
|
|
variant: "destructive",
|
|
description: e.message,
|
|
});
|
|
} else {
|
|
toast({
|
|
variant: "destructive",
|
|
title: "Something went wrong",
|
|
});
|
|
}
|
|
},
|
|
});
|
|
|
|
const onSubmit = async (value: z.infer<typeof formSchema>) => {
|
|
const results = await Promise.allSettled(
|
|
bookmarkIds.map((bookmarkId) =>
|
|
addToList({
|
|
bookmarkId,
|
|
listId: value.listId,
|
|
}),
|
|
),
|
|
);
|
|
|
|
const successes = results.filter((r) => r.status == "fulfilled").length;
|
|
if (successes > 0) {
|
|
toast({
|
|
description: `${successes} bookmarks have been added to the list!`,
|
|
});
|
|
}
|
|
|
|
setOpen(false);
|
|
};
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
<DialogContent>
|
|
<Form {...form}>
|
|
<form
|
|
className="flex w-full flex-col gap-4"
|
|
onSubmit={form.handleSubmit(onSubmit)}
|
|
>
|
|
<DialogHeader>
|
|
<DialogTitle>
|
|
Add {bookmarkIds.length} bookmarks to List
|
|
</DialogTitle>
|
|
</DialogHeader>
|
|
|
|
<FormField
|
|
control={form.control}
|
|
name="listId"
|
|
render={({ field }) => {
|
|
return (
|
|
<FormItem>
|
|
<FormControl>
|
|
<BookmarkListSelector
|
|
value={field.value}
|
|
onChange={field.onChange}
|
|
/>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
);
|
|
}}
|
|
/>
|
|
<DialogFooter className="sm:justify-end">
|
|
<DialogClose asChild>
|
|
<Button type="button" variant="secondary">
|
|
Close
|
|
</Button>
|
|
</DialogClose>
|
|
<ActionButton
|
|
type="submit"
|
|
loading={isAddingToListPending}
|
|
disabled={isAddingToListPending}
|
|
>
|
|
Add
|
|
</ActionButton>
|
|
</DialogFooter>
|
|
</form>
|
|
</Form>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|