import { FastifyPluginAsync } from 'fastify'; import { z } from 'zod'; import { db } from '../config/database.js'; import { galleryImages } from '../db/schema.js'; import { eq } from 'drizzle-orm'; const galleryImageSchema = z.object({ imageUrl: z.string().url(), altText: z.string().min(1).max(200), displayOrder: z.number().int().min(0), isPublished: z.boolean().optional().default(true), }); const galleryRoute: FastifyPluginAsync = async (fastify) => { // List all gallery images fastify.get('/gallery', { preHandler: [fastify.authenticate], }, async (request, reply) => { const images = await db.select().from(galleryImages).orderBy(galleryImages.displayOrder); return { images }; }); // Get single gallery image fastify.get('/gallery/:id', { preHandler: [fastify.authenticate], }, async (request, reply) => { const { id } = request.params as { id: string }; const image = await db.select().from(galleryImages).where(eq(galleryImages.id, id)).limit(1); if (image.length === 0) { return reply.code(404).send({ error: 'Image not found' }); } return { image: image[0] }; }); // Create gallery image fastify.post('/gallery', { schema: { body: galleryImageSchema, }, preHandler: [fastify.authenticate], }, async (request, reply) => { const data = request.body as z.infer; const [newImage] = await db.insert(galleryImages).values(data).returning(); return reply.code(201).send({ image: newImage }); }); // Update gallery image fastify.put('/gallery/:id', { schema: { body: galleryImageSchema, }, preHandler: [fastify.authenticate], }, async (request, reply) => { const { id } = request.params as { id: string }; const data = request.body as z.infer; const [updated] = await db .update(galleryImages) .set(data) .where(eq(galleryImages.id, id)) .returning(); if (!updated) { return reply.code(404).send({ error: 'Image not found' }); } return { image: updated }; }); // Delete gallery image fastify.delete('/gallery/:id', { preHandler: [fastify.authenticate], }, async (request, reply) => { const { id } = request.params as { id: string }; const [deleted] = await db .delete(galleryImages) .where(eq(galleryImages.id, id)) .returning(); if (!deleted) { return reply.code(404).send({ error: 'Image not found' }); } return { message: 'Image deleted successfully' }; }); // Reorder gallery images fastify.put('/gallery/reorder', { schema: { body: z.object({ orders: z.array(z.object({ id: z.string().uuid(), displayOrder: z.number().int().min(0), })), }), }, preHandler: [fastify.authenticate], }, async (request, reply) => { const { orders } = request.body as { orders: Array<{ id: string; displayOrder: number }> }; // Update all in transaction await db.transaction(async (tx) => { for (const { id, displayOrder } of orders) { await tx .update(galleryImages) .set({ displayOrder }) .where(eq(galleryImages.id, id)); } }); return { message: 'Gallery images reordered successfully' }; }); }; export default galleryRoute;