aboutsummaryrefslogtreecommitdiffstats
path: root/web/app
diff options
context:
space:
mode:
Diffstat (limited to 'web/app')
-rw-r--r--web/app/api/v1/links/[linkId]/route.ts32
-rw-r--r--web/app/bookmarks/components/LinkCard.tsx36
-rw-r--r--web/app/layout.tsx6
3 files changed, 66 insertions, 8 deletions
diff --git a/web/app/api/v1/links/[linkId]/route.ts b/web/app/api/v1/links/[linkId]/route.ts
new file mode 100644
index 00000000..39449d6d
--- /dev/null
+++ b/web/app/api/v1/links/[linkId]/route.ts
@@ -0,0 +1,32 @@
+import { authOptions } from "@/lib/auth";
+import { unbookmarkLink } from "@/lib/services/links";
+import { Prisma } from "@remember/db";
+
+import { getServerSession } from "next-auth";
+import { NextRequest } from "next/server";
+
+export async function DELETE(
+ _request: NextRequest,
+ { params }: { params: { linkId: string } },
+) {
+ // TODO: We probably should be using an API key here instead of the session;
+ const session = await getServerSession(authOptions);
+ if (!session) {
+ return new Response(null, { status: 401 });
+ }
+
+ try {
+ await unbookmarkLink(params.linkId, session.user.id);
+ } catch (e: unknown) {
+ if (
+ e instanceof Prisma.PrismaClientKnownRequestError &&
+ e.code === "P2025" // RecordNotFound
+ ) {
+ return new Response(null, { status: 404 });
+ } else {
+ throw e;
+ }
+ }
+
+ return new Response(null, { status: 201 });
+}
diff --git a/web/app/bookmarks/components/LinkCard.tsx b/web/app/bookmarks/components/LinkCard.tsx
index 75973f7e..907acd19 100644
--- a/web/app/bookmarks/components/LinkCard.tsx
+++ b/web/app/bookmarks/components/LinkCard.tsx
@@ -13,12 +13,34 @@ import {
ImageCardFooter,
ImageCardTitle,
} from "@/components/ui/imageCard";
+import { useToast } from "@/components/ui/use-toast";
+import APIClient from "@/lib/api";
import { ZBookmarkedLink } from "@/lib/types/api/links";
import { MoreHorizontal, Trash2 } from "lucide-react";
import Link from "next/link";
+import { useRouter } from "next/navigation";
-export function LinkOptions() {
- // TODO: Implement deletion
+export function LinkOptions({ linkId }: { linkId: string }) {
+ const { toast } = useToast();
+ const router = useRouter();
+
+ const unbookmarkLink = async () => {
+ let [_, error] = await APIClient.unbookmarkLink(linkId);
+
+ if (error) {
+ toast({
+ variant: "destructive",
+ title: "Something went wrong",
+ description: "There was a problem with your request.",
+ });
+ } else {
+ toast({
+ description: "The link has been deleted!",
+ });
+ }
+
+ router.refresh();
+ };
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
@@ -27,10 +49,10 @@ export function LinkOptions() {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-fit">
- <DropdownMenuItem className="text-destructive">
- <Trash2 className="mr-2 h-4 w-4" />
- <span>Delete</span>
- </DropdownMenuItem>
+ <DropdownMenuItem className="text-destructive" onClick={unbookmarkLink}>
+ <Trash2 className="mr-2 h-4 w-4" />
+ <span>Delete</span>
+ </DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
@@ -59,7 +81,7 @@ export default function LinkCard({ link }: { link: ZBookmarkedLink }) {
{parsedUrl.host}
</Link>
</div>
- <LinkOptions />
+ <LinkOptions linkId={link.id} />
</div>
</ImageCardFooter>
</ImageCard>
diff --git a/web/app/layout.tsx b/web/app/layout.tsx
index 30d918df..a6543b1c 100644
--- a/web/app/layout.tsx
+++ b/web/app/layout.tsx
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import React from "react";
+import { Toaster } from "@/components/ui/toaster";
const inter = Inter({ subsets: ["latin"] });
@@ -17,7 +18,10 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
- <body className={inter.className}>{children}</body>
+ <body className={inter.className}>
+ {children}
+ <Toaster />
+ </body>
</html>
);
}