aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/components/dashboard/bookmarks/BulkManageListsModal.tsx
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-09-01 17:44:09 +0000
committerMohamedBassem <me@mbassem.com>2024-09-01 17:44:27 +0000
commitddc7e5dbfc31b3e5b189c61883e1cc737fefd2ee (patch)
treebba661440260b9615ebdf7b00eb2da8a537ce317 /apps/web/components/dashboard/bookmarks/BulkManageListsModal.tsx
parentdbdbd4902796a1cb6a3a382ccbbf8338954e7431 (diff)
downloadkarakeep-ddc7e5dbfc31b3e5b189c61883e1cc737fefd2ee.tar.zst
feature(web): Allow adding to lists in bulk actions. #368
Diffstat (limited to 'apps/web/components/dashboard/bookmarks/BulkManageListsModal.tsx')
-rw-r--r--apps/web/components/dashboard/bookmarks/BulkManageListsModal.tsx138
1 files changed, 138 insertions, 0 deletions
diff --git a/apps/web/components/dashboard/bookmarks/BulkManageListsModal.tsx b/apps/web/components/dashboard/bookmarks/BulkManageListsModal.tsx
new file mode 100644
index 00000000..9c1f05d2
--- /dev/null
+++ b/apps/web/components/dashboard/bookmarks/BulkManageListsModal.tsx
@@ -0,0 +1,138 @@
+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>
+ );
+}