diff --git a/backend/database/src/index.ts b/backend/database/src/index.ts index cd1da76..c5aca75 100644 --- a/backend/database/src/index.ts +++ b/backend/database/src/index.ts @@ -5,7 +5,13 @@ import { z } from "zod" import { and, eq, sql } from "drizzle-orm" import * as schema from "./schema" -import { Sandbox, sandbox, user, usersToSandboxes } from "./schema" +import { + Sandbox, + sandbox, + sandboxLikes, + user, + usersToSandboxes, +} from "./schema" export interface Env { DB: D1Database @@ -67,6 +73,7 @@ export default { const params = url.searchParams if (params.has("id")) { const id = params.get("id") as string + await db.delete(sandboxLikes).where(eq(sandboxLikes.sandboxId, id)) await db .delete(usersToSandboxes) .where(eq(usersToSandboxes.sandboxId, id)) @@ -239,6 +246,88 @@ export default { return success } else return methodNotAllowed + } else if (path === "/api/sandbox/like") { + if (method === "POST") { + const likeSchema = z.object({ + sandboxId: z.string(), + userId: z.string(), + }) + + try { + const body = await request.json() + const { sandboxId, userId } = likeSchema.parse(body) + + // Check if user has already liked + const existingLike = await db.query.sandboxLikes.findFirst({ + where: (likes, { and, eq }) => + and(eq(likes.sandboxId, sandboxId), eq(likes.userId, userId)), + }) + + if (existingLike) { + // Unlike + await db + .delete(sandboxLikes) + .where( + and( + eq(sandboxLikes.sandboxId, sandboxId), + eq(sandboxLikes.userId, userId) + ) + ) + + await db + .update(sandbox) + .set({ + likeCount: sql`${sandbox.likeCount} - 1`, + }) + .where(eq(sandbox.id, sandboxId)) + + return json({ + message: "Unlike successful", + liked: false, + }) + } else { + // Like + await db.insert(sandboxLikes).values({ + sandboxId, + userId, + createdAt: new Date(), + }) + + await db + .update(sandbox) + .set({ + likeCount: sql`${sandbox.likeCount} + 1`, + }) + .where(eq(sandbox.id, sandboxId)) + + return json({ + message: "Like successful", + liked: true, + }) + } + } catch (error) { + return new Response("Invalid request format", { status: 400 }) + } + } else if (method === "GET") { + const params = url.searchParams + const sandboxId = params.get("sandboxId") + const userId = params.get("userId") + + if (!sandboxId || !userId) { + return invalidRequest + } + + const like = await db.query.sandboxLikes.findFirst({ + where: (likes, { and, eq }) => + and(eq(likes.sandboxId, sandboxId), eq(likes.userId, userId)), + }) + + return json({ + liked: !!like, + }) + } else { + return methodNotAllowed + } } else if (path === "/api/user") { if (method === "GET") { const params = url.searchParams diff --git a/frontend/lib/actions.ts b/frontend/lib/actions.ts index 845d9f5..c01f0e5 100644 --- a/frontend/lib/actions.ts +++ b/frontend/lib/actions.ts @@ -97,7 +97,7 @@ export async function unshareSandbox(sandboxId: string, userId: string) { } export async function toggleLike(sandboxId: string, userId: string) { - await fetch( + const res = await fetch( `${process.env.NEXT_PUBLIC_DATABASE_WORKER_URL}/api/sandbox/like`, { method: "POST",