diff options
| author | MohamedBassem <me@mbassem.com> | 2024-03-01 18:00:58 +0000 |
|---|---|---|
| committer | MohamedBassem <me@mbassem.com> | 2024-03-01 18:00:58 +0000 |
| commit | 75d315dda4232ee3b89abf054f0b6ee10105ffe3 (patch) | |
| tree | f0796a136578f3b5aa82b4b3313e54fa3061ff5f /packages/web/app/dashboard/lists | |
| parent | 588471d65039e6920751ac2add8874ee932bc2f1 (diff) | |
| download | karakeep-75d315dda4232ee3b89abf054f0b6ee10105ffe3.tar.zst | |
feature: Add support for creating and updating lists
Diffstat (limited to 'packages/web/app/dashboard/lists')
3 files changed, 143 insertions, 0 deletions
diff --git a/packages/web/app/dashboard/lists/[listId]/components/DeleteListButton.tsx b/packages/web/app/dashboard/lists/[listId]/components/DeleteListButton.tsx new file mode 100644 index 00000000..8961b2d0 --- /dev/null +++ b/packages/web/app/dashboard/lists/[listId]/components/DeleteListButton.tsx @@ -0,0 +1,76 @@ +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { Trash } from "lucide-react"; +import { useRouter } from "next/navigation"; +import { toast } from "@/components/ui/use-toast"; +import { api } from "@/lib/trpc"; +import { ActionButton } from "@/components/ui/action-button"; +import { useState } from "react"; +import { ZBookmarkList } from "@/lib/types/api/lists"; + +export default function DeleteListButton({ list }: { list: ZBookmarkList }) { + const [isDialogOpen, setDialogOpen] = useState(false); + + const router = useRouter(); + + const listsInvalidationFunction = api.useUtils().lists.list.invalidate; + const { mutate: deleteList, isPending } = api.lists.delete.useMutation({ + onSuccess: () => { + listsInvalidationFunction(); + toast({ + description: `List "${list.icon} ${list.name}" is deleted!`, + }); + router.push("/"); + }, + onError: () => { + toast({ + variant: "destructive", + description: `Something went wrong`, + }); + }, + }); + return ( + <Dialog open={isDialogOpen} onOpenChange={setDialogOpen}> + <DialogTrigger asChild> + <Button className="mt-auto flex gap-2" variant="destructive"> + <Trash className="size-5" /> + <span className="hidden md:block">Delete List</span> + </Button> + </DialogTrigger> + <DialogContent> + <DialogHeader> + <DialogTitle> + Delete {list.icon} {list.name}? + </DialogTitle> + </DialogHeader> + <span> + Are you sure you want to delete {list.icon} {list.name}? + </span> + <DialogFooter className="sm:justify-end"> + <DialogClose asChild> + <Button type="button" variant="secondary"> + Close + </Button> + </DialogClose> + <ActionButton + type="button" + variant="destructive" + loading={isPending} + onClick={() => deleteList({ listId: list.id })} + > + Delete + </ActionButton> + </DialogFooter> + </DialogContent> + </Dialog> + ); +} diff --git a/packages/web/app/dashboard/lists/[listId]/components/ListView.tsx b/packages/web/app/dashboard/lists/[listId]/components/ListView.tsx new file mode 100644 index 00000000..c3d49b6a --- /dev/null +++ b/packages/web/app/dashboard/lists/[listId]/components/ListView.tsx @@ -0,0 +1,35 @@ +"use client"; + +import BookmarksGrid from "@/app/dashboard/bookmarks/components/BookmarksGrid"; +import { ZBookmark } from "@/lib/types/api/bookmarks"; +import { ZBookmarkListWithBookmarks } from "@/lib/types/api/lists"; +import { api } from "@/lib/trpc"; +import DeleteListButton from "./DeleteListButton"; + +export default function ListView({ + bookmarks, + list: initialData, +}: { + list: ZBookmarkListWithBookmarks; + bookmarks: ZBookmark[]; +}) { + const { data } = api.lists.get.useQuery( + { listId: initialData.id }, + { + initialData, + }, + ); + + return ( + <div className="container flex flex-col gap-3"> + <div className="flex justify-between"> + <span className="pt-4 text-2xl"> + {data.icon} {data.name} + </span> + <DeleteListButton list={data} /> + </div> + <hr /> + <BookmarksGrid query={{ ids: data.bookmarks }} bookmarks={bookmarks} /> + </div> + ); +} diff --git a/packages/web/app/dashboard/lists/[listId]/page.tsx b/packages/web/app/dashboard/lists/[listId]/page.tsx new file mode 100644 index 00000000..b8ca79c3 --- /dev/null +++ b/packages/web/app/dashboard/lists/[listId]/page.tsx @@ -0,0 +1,32 @@ +import { api } from "@/server/api/client"; +import { getServerAuthSession } from "@/server/auth"; +import { TRPCError } from "@trpc/server"; +import { notFound, redirect } from "next/navigation"; +import ListView from "./components/ListView"; + +export default async function ListPage({ + params, +}: { + params: { listId: string }; +}) { + const session = await getServerAuthSession(); + if (!session) { + redirect("/"); + } + + let list; + try { + list = await api.lists.get({ listId: params.listId }); + } catch (e) { + if (e instanceof TRPCError) { + if (e.code == "NOT_FOUND") { + notFound(); + } + } + throw e; + } + + const bookmarks = await api.bookmarks.getBookmarks({ ids: list.bookmarks }); + + return <ListView list={list} bookmarks={bookmarks.bookmarks} />; +} |
