import { Elysia, t } from "elysia"; import prisma from "../lib/prisma"; import { adminOnly } from "../middleware/auth"; export const menusRoute = new Elysia({ prefix: "/menus" }) .get("/", async () => { return await prisma.menu.findMany({ include: { items: { orderBy: { order: "asc" }, include: { translations: true } } } }); }) .get("/:name", async ({ params: { name }, set }) => { const menu = await prisma.menu.findUnique({ where: { name }, include: { items: { orderBy: { order: "asc" }, include: { translations: true } } } }); if (!menu) { return { name, items: [], payload: null, isActive: false }; } return menu; }) .use(adminOnly) .post("/", async ({ body, set }) => { try { const { name, items } = body; const menu = await prisma.menu.create({ data: { name, items: items ? { create: items } : undefined }, include: { items: true } }); return menu; } catch (err) { console.error(err); set.status = 500; return { error: "Failed to create menu" }; } }, { body: t.Object({ name: t.String(), items: t.Optional(t.Array(t.Object({ label: t.String(), url: t.String(), order: t.Number() }))) }) }) .put("/:name", async ({ params: { name }, body, set }) => { try { const { items, payload, isActive } = body; let menu = await prisma.menu.findUnique({ where: { name } }); const updateData = {}; if (payload !== undefined) updateData.payload = payload; if (isActive !== undefined) updateData.isActive = isActive; if (!menu) { menu = await prisma.menu.create({ data: { name, ...updateData } }); } else if (Object.keys(updateData).length > 0) { menu = await prisma.menu.update({ where: { name }, data: updateData }); } await prisma.$transaction(async (tx) => { const existingItems = await tx.menuItem.findMany({ where: { menuId: menu.id } }); const existingItemIds = existingItems.map((i) => i.id); const payloadItemIds = items.map(i => i.id).filter(id => id != null); const itemsToDelete = existingItemIds.filter((id) => !payloadItemIds.includes(id)); if (itemsToDelete.length > 0) { await tx.menuItem.deleteMany({ where: { id: { in: itemsToDelete } } }); } for (const item of items) { if (item.id && existingItemIds.includes(item.id)) { await tx.menuItem.update({ where: { id: item.id }, data: { label: item.label, url: item.url, order: item.order } }); if (item.translations?.length) { for (const t of item.translations) { await tx.menuItemTranslation.upsert({ where: { menuItemId_langCode: { menuItemId: item.id, langCode: t.langCode } }, update: { label: t.label }, create: { menuItemId: item.id, langCode: t.langCode, label: t.label } }); } } } else { await tx.menuItem.create({ data: { menuId: menu.id, label: item.label, url: item.url, order: item.order, translations: item.translations?.length ? { create: item.translations.map(t => ({ langCode: t.langCode, label: t.label })) } : undefined } }); } } }); return await prisma.menu.findUnique({ where: { name }, include: { items: { orderBy: { order: "asc" }, include: { translations: true } } } }); } catch (err) { console.error(err); set.status = 500; return { error: "Failed to update menu" }; } }, { body: t.Object({ payload: t.Optional(t.Any()), isActive: t.Optional(t.Boolean()), items: t.Array(t.Object({ id: t.Optional(t.Number()), label: t.String(), url: t.String(), order: t.Number(), translations: t.Optional(t.Array(t.Object({ langCode: t.String(), label: t.String() }))) })) }) }) .patch("/items/:id/translations", async ({ params, body, set }) => { const id = Number(params.id); if (isNaN(id)) { set.status = 400; return { error: "Invalid menu item ID" }; } const menuItem = await prisma.menuItem.findUnique({ where: { id } }); if (!menuItem) { set.status = 404; return { error: "Menu item not found. Please ensure database is seeded or the item exists." }; } const payload = body; const results = []; const LANGS = ['th', 'en', 'ja', 'zh', 'vi', 'ko']; for (const lang of LANGS) { const label = typeof payload.label === 'string' ? (lang === 'th' ? payload.label : null) : payload.label?.[lang]; if (!label) continue; const existing = await prisma.menuItemTranslation.findUnique({ where: { menuItemId_langCode: { menuItemId: id, langCode: lang } } }); if (existing) { const updated = await prisma.menuItemTranslation.update({ where: { id: existing.id }, data: { label } }); results.push(updated); } else { const created = await prisma.menuItemTranslation.create({ data: { menuItemId: id, langCode: lang, label } }); results.push(created); } } const updated = await prisma.menuItem.findUnique({ where: { id }, include: { translations: true } }); return { success: true, translations: results, menuItem: updated }; }); //# sourceMappingURL=menus.js.map