This commit is contained in:
Your Name committed 2026-07-23 04:41:35 -04:00
1 parent ae3799d8ce
commit 0341b30b6d
9 files changed
+947 -51

No files matched your search

+12 -7
View File
@@ -20,6 +20,7 @@ export const categoriesRoute = new Elysia({ prefix: "/categories" })
.get("/", async ({ query }) => {
const lang = (query as any).lang || 'th';
const categories = await prisma.category.findMany({
where: { deletedAt: null },
orderBy: { name: "asc" },
include: {
translations: true,
@@ -45,7 +46,7 @@ export const categoriesRoute = new Elysia({ prefix: "/categories" })
const [category, total] = await Promise.all([
prisma.category.findUnique({
where: { id },
where: { id, deletedAt: null },
include: {
translations: true,
products: {
@@ -118,7 +119,7 @@ export const categoriesRoute = new Elysia({ prefix: "/categories" })
if (isNaN(id)) return status(400, { message: "Invalid category ID" });
try {
const categoryExists = await prisma.category.findUnique({ where: { id } });
const categoryExists = await prisma.category.findFirst({ where: { id, deletedAt: null } });
if (!categoryExists) return status(404, { message: "Category not found" });
const payload = body as any;
@@ -170,7 +171,7 @@ export const categoriesRoute = new Elysia({ prefix: "/categories" })
try {
const category = await prisma.category.update({
where: { id },
where: { id, deletedAt: null },
data: {
imageUrl: body.imageUrl,
},
@@ -217,7 +218,7 @@ export const categoriesRoute = new Elysia({ prefix: "/categories" })
try {
const category = await prisma.category.update({
where: { id },
where: { id, deletedAt: null },
data: {
name: body.name,
imageUrl: body.imageUrl,
@@ -246,7 +247,7 @@ export const categoriesRoute = new Elysia({ prefix: "/categories" })
try {
const category = await prisma.category.findUnique({
where: { id },
where: { id, deletedAt: null },
include: { _count: { select: { products: true } } }
});
@@ -255,8 +256,12 @@ export const categoriesRoute = new Elysia({ prefix: "/categories" })
return status(400, { message: "Cannot delete category with existing products" });
}
await prisma.category.delete({ where: { id } });
return { success: true };
const deletedAt = new Date();
await prisma.category.update({
where: { id },
data: { deletedAt },
});
return { success: true, softDeleted: true, id, deletedAt };
} catch (err: any) {
return status(500, { message: "Failed to delete category" });
}
+2 -1
View File
@@ -734,7 +734,7 @@ export async function hydrateSectionPayload(section: any, lang: string) {
if (Array.isArray(payload.categoryIds) && payload.categoryIds.length > 0) {
const ids = payload.categoryIds.map(Number);
categories = await prisma.category.findMany({
where: { id: { in: ids } },
where: { id: { in: ids }, deletedAt: null },
include: {
translations: true,
_count: {
@@ -745,6 +745,7 @@ export async function hydrateSectionPayload(section: any, lang: string) {
categories.sort((a, b) => ids.indexOf(a.id) - ids.indexOf(b.id));
} else {
categories = await prisma.category.findMany({
where: { deletedAt: null },
include: {
translations: true,
_count: {
+33 -3
View File
@@ -21,6 +21,18 @@ function defaultProductDetailSections(productId: number) {
];
}
async function assertActiveCategory(categoryId: number, client: any = prisma) {
const category = await client.category.findFirst({
where: { id: categoryId, deletedAt: null },
select: { id: true },
});
if (!category) {
const error = new Error("Category not found");
(error as any).code = "CATEGORY_NOT_FOUND";
throw error;
}
}
export const productsRoute = new Elysia({ prefix: "/products" })
.decorate("validateVariants", (options: any[] = [], variants: any[] = []) => {
if (options.length > 3) throw new Error("Options array length cannot exceed 3.");
@@ -522,7 +534,10 @@ export const productsRoute = new Elysia({ prefix: "/products" })
const updatedProduct = await prisma.$transaction(async (tx) => {
// 1. Update basic product info
const updateData: any = {};
if (categoryId !== undefined) updateData.categoryId = categoryId;
if (categoryId !== undefined) {
await assertActiveCategory(categoryId, tx);
updateData.categoryId = categoryId;
}
if (body.options !== undefined) updateData.options = body.options;
const prod = await tx.product.update({
@@ -632,6 +647,9 @@ export const productsRoute = new Elysia({ prefix: "/products" })
return { success: true, product: updatedProduct };
} catch (err: any) {
if (err?.code === "CATEGORY_NOT_FOUND") {
return status(400, { success: false, message: "Category not found" });
}
console.error("Update product error:", err);
return status(500, { success: false, message: err?.message || "Failed to update product" });
}
@@ -690,12 +708,15 @@ export const productsRoute = new Elysia({ prefix: "/products" })
const product = await prisma.$transaction(async (tx) => {
let categoryId = payload.categoryId;
if (!categoryId && payload.categoryName) {
let cat = await tx.category.findUnique({ where: { name: payload.categoryName } });
let cat = await tx.category.findFirst({
where: { name: payload.categoryName, deletedAt: null },
});
if (!cat) {
cat = await tx.category.create({ data: { name: payload.categoryName } });
}
categoryId = cat.id;
}
if (categoryId) await assertActiveCategory(categoryId, tx);
let brandId = payload.brandId;
if (!brandId && payload.brandName) {
@@ -775,6 +796,9 @@ export const productsRoute = new Elysia({ prefix: "/products" })
return { success: true, product };
} catch (err: any) {
if (err?.code === "CATEGORY_NOT_FOUND") {
return status(400, { success: false, message: "Category not found" });
}
console.error("Create product error:", err);
return status(500, { success: false, message: err?.message || "Failed to create product" });
}
@@ -806,12 +830,15 @@ export const productsRoute = new Elysia({ prefix: "/products" })
let categoryId = payload.categoryId;
if (!categoryId && payload.categoryName) {
let cat = await tx.category.findUnique({ where: { name: payload.categoryName } });
let cat = await tx.category.findFirst({
where: { name: payload.categoryName, deletedAt: null },
});
if (!cat) {
cat = await tx.category.create({ data: { name: payload.categoryName } });
}
categoryId = cat.id;
}
if (categoryId) await assertActiveCategory(categoryId, tx);
let brandId = payload.brandId;
if (!brandId && payload.brandName) {
@@ -892,6 +919,9 @@ export const productsRoute = new Elysia({ prefix: "/products" })
return { success: true, products: createdProducts };
} catch (err: any) {
if (err?.code === "CATEGORY_NOT_FOUND") {
return status(400, { success: false, message: "Category not found" });
}
console.error("Bulk create products error:", err);
return status(500, { success: false, message: err?.message || "Failed to bulk create products" });
}