feat: add product review and rating system with schema update

This commit is contained in:
Your Name committed 2026-06-06 19:45:28 +07:00
1 parent 091eeef7d8
commit e4f7951b34
5 files changed
+230 -1

No files matched your search

+20
View File
@@ -38,6 +38,7 @@ model Product {
scent Scent @relation(fields: [scentId], references: [id])
variants ProductVariant[]
images ProductImage[]
reviews Review[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@ -82,6 +83,7 @@ model Customer {
email String?
phone String?
orders Order[]
reviews Review[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
@@ -372,3 +374,21 @@ model LazadaOrderItem {
shippingFee Float @default(0)
status String?
}
// ── Reviews ────────────────────────────────────────────────────────────────
model Review {
id Int @id @default(autoincrement())
rating Int @default(5)
comment String?
productId Int
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
customerId Int?
customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
customerName String?
isPublished Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([productId])
@@index([customerId])
}
+2 -1
View File
@@ -18,6 +18,7 @@ import { tiktokOrderRoute } from "./routes/tiktokOrder";
import { lazadaOrderRoute } from "./routes/lazadaOrder";
import { customersRoute } from "./routes/customers";
import { couponsRoute } from "./routes/coupons";
import { reviewsRoute } from "./routes/reviews";
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3000;
const CORS_ORIGIN = process.env.CORS_ORIGIN || "http://localhost:5173";
const JWT_SECRET = process.env.JWT_SECRET || "homaroma_secret_2026_scent";
@@ -81,7 +82,7 @@ const app = new Elysia()
return file;
})
.group("/api", (app) =>
app.use(authRoute).use(categoriesRoute).use(productsRoute).use(uploadRoute).use(heroRoute).use(ordersRoute).use(settingsRoute).use(articlesRoute).use(tiktokRoute).use(rawMaterialsRoute).use(shopeeRoute).use(tiktokOrderRoute).use(lazadaOrderRoute).use(customersRoute).use(couponsRoute)
app.use(authRoute).use(categoriesRoute).use(productsRoute).use(uploadRoute).use(heroRoute).use(ordersRoute).use(settingsRoute).use(articlesRoute).use(tiktokRoute).use(rawMaterialsRoute).use(shopeeRoute).use(tiktokOrderRoute).use(lazadaOrderRoute).use(customersRoute).use(couponsRoute).use(reviewsRoute)
)
.listen(PORT);
+49
View File
@@ -0,0 +1,49 @@
import { Elysia, t } from "elysia";
import prisma from "../lib/prisma";
export const reviewsRoute = new Elysia({ prefix: "/reviews" })
.get("/product/:productId", async ({ params: { productId } }) => {
return await prisma.review.findMany({
where: {
productId: Number(productId),
isPublished: true
},
orderBy: { createdAt: 'desc' },
include: {
customer: {
select: {
displayName: true,
pictureUrl: true
}
}
}
});
})
.post("/", async ({ body, set }) => {
try {
const data = body as any;
const review = await prisma.review.create({
data: {
rating: data.rating,
comment: data.comment,
productId: data.productId,
customerId: data.customerId || null,
customerName: data.customerName || "Anonymous",
isPublished: true
}
});
return review;
} catch (err) {
console.error("[Reviews] Error:", err);
set.status = 500;
return { error: "Failed to create review" };
}
}, {
body: t.Object({
rating: t.Number(),
comment: t.Optional(t.String()),
productId: t.Number(),
customerId: t.Optional(t.Nullable(t.Number())),
customerName: t.Optional(t.String())
})
});