feat: complete profile page with profile edit, project likes and UI updates

This commit is contained in:
Hamzat Victor
2024-11-25 21:53:46 +01:00
parent 105eab9bad
commit 06a5d46e1f
10 changed files with 888 additions and 293 deletions

View File

@ -5,7 +5,13 @@ import { z } from "zod"
import { and, eq, sql } from "drizzle-orm"
import * as schema from "./schema"
import { sandbox, user, usersToSandboxes } from "./schema"
import {
Sandbox,
sandbox,
sandboxLikes,
user,
usersToSandboxes,
} from "./schema"
export interface Env {
DB: D1Database
@ -18,6 +24,13 @@ export interface Env {
// npm run generate
// npx wrangler d1 execute d1-sandbox --local --file=./drizzle/<FILE>
interface SandboxWithLiked extends Sandbox {
liked: boolean
}
interface UserResponse extends Omit<schema.User, "sandbox"> {
sandbox: SandboxWithLiked[]
}
export default {
async fetch(
@ -258,33 +271,147 @@ export default {
.get()
return success
} 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
if (params.has("id")) {
const id = params.get("id") as string
const res = await db.query.user.findFirst({
where: (user, { eq }) => eq(user.id, id),
with: {
sandbox: {
orderBy: (sandbox, { desc }) => [desc(sandbox.createdAt)],
with: {
likes: true,
},
},
usersToSandboxes: true,
},
})
if (res) {
const transformedUser: UserResponse = {
...res,
sandbox: res.sandbox.map(
(sb): SandboxWithLiked => ({
...sb,
liked: sb.likes.some((like) => like.userId === id),
})
),
}
return json(transformedUser)
}
return json(res ?? {})
} else if (params.has("username")) {
const username = params.get("username") as string
const userId = params.get("currentUserId")
const res = await db.query.user.findFirst({
where: (user, { eq }) => eq(user.username, username),
with: {
sandbox: {
orderBy: (sandbox, { desc }) => [desc(sandbox.createdAt)],
with: {
likes: true,
},
},
usersToSandboxes: true,
},
})
if (res) {
const transformedUser: UserResponse = {
...res,
sandbox: res.sandbox.map(
(sb): SandboxWithLiked => ({
...sb,
liked: sb.likes.some((like) => like.userId === userId),
})
),
}
return json(transformedUser)
}
return json(res ?? {})
} else {
const res = await db.select().from(user).all()
@ -326,6 +453,57 @@ export default {
await db.delete(user).where(eq(user.id, id))
return success
} else return invalidRequest
} else if (method === "PUT") {
const updateUserSchema = z.object({
id: z.string(),
name: z.string().optional(),
email: z.string().email().optional(),
username: z.string().optional(),
avatarUrl: z.string().optional(),
generations: z.number().optional(),
})
try {
const body = await request.json()
const validatedData = updateUserSchema.parse(body)
const { id, username, ...updateData } = validatedData
// If username is being updated, check for existing username
if (username) {
const existingUser = await db
.select()
.from(user)
.where(eq(user.username, username))
.get()
if (existingUser && existingUser.id !== id) {
return json({ error: "Username already exists" }, { status: 409 })
}
}
const cleanUpdateData = {
...updateData,
...(username ? { username } : {}),
}
const res = await db
.update(user)
.set(cleanUpdateData)
.where(eq(user.id, id))
.returning()
.get()
if (!res) {
return json({ error: "User not found" }, { status: 404 })
}
return json({ res })
} catch (error) {
if (error instanceof z.ZodError) {
return json({ error: error.errors }, { status: 400 })
}
return json({ error: "Internal server error" }, { status: 500 })
}
} else {
return methodNotAllowed
}