Skip to content

Commit

Permalink
feature(web): Allow adding to lists in bulk actions. #368
Browse files Browse the repository at this point in the history
  • Loading branch information
MohamedBassem committed Sep 1, 2024
1 parent dbdbd49 commit ddc7e5d
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 1 deletion.
16 changes: 15 additions & 1 deletion apps/web/components/dashboard/BulkBookmarksAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import {
import ActionConfirmingDialog from "@/components/ui/action-confirming-dialog";
import { useToast } from "@/components/ui/use-toast";
import useBulkActionsStore from "@/lib/bulkActions";
import { Pencil, Trash2, X } from "lucide-react";
import { List, Pencil, Trash2, X } from "lucide-react";

import {
useDeleteBookmark,
useUpdateBookmark,
} from "@hoarder/shared-react/hooks/bookmarks";

import BulkManageListsModal from "./bookmarks/BulkManageListsModal";
import { ArchivedActionIcon, FavouritedActionIcon } from "./bookmarks/icons";

export default function BulkBookmarksAction() {
Expand All @@ -24,6 +25,7 @@ export default function BulkBookmarksAction() {
);
const { toast } = useToast();
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const [manageListsModal, setManageListsModalOpen] = useState(false);

useEffect(() => {
setIsBulkEditEnabled(false); // turn off toggle + clear selected bookmarks on mount
Expand Down Expand Up @@ -95,6 +97,13 @@ export default function BulkBookmarksAction() {
selectedBookmarks.every((item) => item.archived === true);

const actionList = [
{
name: "Add to List",
icon: <List size={18} />,
action: () => setManageListsModalOpen(true),
isPending: false,
hidden: !isBulkEditEnabled,
},
{
name: alreadyFavourited ? "Unfavourite" : "Favourite",
icon: <FavouritedActionIcon favourited={!!alreadyFavourited} size={18} />,
Expand Down Expand Up @@ -149,6 +158,11 @@ export default function BulkBookmarksAction() {
</ActionButton>
)}
/>
<BulkManageListsModal
bookmarkIds={selectedBookmarks.map((b) => b.id)}
open={manageListsModal}
setOpen={setManageListsModalOpen}
/>
<div className="flex">
{actionList.map(
({ name, icon: Icon, action, isPending, hidden, alwaysEnable }) => (
Expand Down
138 changes: 138 additions & 0 deletions apps/web/components/dashboard/bookmarks/BulkManageListsModal.tsx
Original file line number Diff line number Diff line change
@@ -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>
);
}

0 comments on commit ddc7e5d

Please sign in to comment.