import type { FastifyInstance } from 'fastify'; import { markSeenSchema } from '@family-wishlist/shared'; import { NotFoundError } from '../../utils/errors.js'; export default async function publicRoutes(app: FastifyInstance) { app.get('/:slug', async (request) => { const { slug } = request.params as { slug: string }; const user = await app.prisma.user.findUnique({ where: { slug }, select: { slug: true, displayName: true, bio: true, avatarUrl: true }, }); if (!user) throw new NotFoundError('Profile'); return user; }); app.get('/:slug/wishes', async (request) => { const { slug } = request.params as { slug: string }; const user = await app.prisma.user.findUnique({ where: { slug }, select: { id: true } }); if (!user) throw new NotFoundError('Profile'); const wishes = await app.prisma.wish.findMany({ where: { userId: user.id, status: { in: ['ACTIVE', 'COMPLETED'] } }, orderBy: [{ status: 'asc' }, { createdAt: 'desc' }], }); const wishIds = wishes.map((w) => w.id); const seen = wishIds.length ? await app.prisma.guestView.findMany({ where: { guestId: request.guestId, wishId: { in: wishIds } }, select: { wishId: true }, }) : []; const seenSet = new Set(seen.map((s) => s.wishId)); return wishes.map((w) => ({ ...w, isNewForGuest: w.status === 'ACTIVE' && !seenSet.has(w.id), })); }); app.post('/:slug/views', async (request) => { const { slug } = request.params as { slug: string }; const body = markSeenSchema.parse(request.body); const user = await app.prisma.user.findUnique({ where: { slug }, select: { id: true } }); if (!user) throw new NotFoundError('Profile'); // Filter wishIds to those that actually belong to this user (avoid cross-user pollution). const owned = await app.prisma.wish.findMany({ where: { userId: user.id, id: { in: body.wishIds } }, select: { id: true }, }); if (owned.length === 0) return { marked: 0 }; const data = owned.map((w) => ({ guestId: request.guestId, wishId: w.id })); const res = await app.prisma.guestView.createMany({ data, skipDuplicates: true }); return { marked: res.count }; }); }