feat: lunch manifest query + CSV export
Adds buildManifest service shared between getManifest and the recap. CSV escaper handles commas/quotes/newlines for safe spreadsheet import. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import { z } from 'zod'
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import { router, adminProcedure, protectedProcedure } from '../trpc'
|
||||
import { logAudit } from '../utils/audit'
|
||||
import { buildManifest } from '../services/lunch-recap'
|
||||
|
||||
// ─── Shared zod schemas ──────────────────────────────────────────────────────
|
||||
|
||||
@@ -225,6 +226,48 @@ export const lunchRouter = router({
|
||||
return { ok: true as const }
|
||||
}),
|
||||
|
||||
// ─── Manifest + CSV export ───────────────────────────────────────────────
|
||||
|
||||
getManifest: adminProcedure
|
||||
.input(z.object({ programId: z.string() }))
|
||||
.query(({ ctx, input }) => buildManifest(ctx.prisma, input.programId)),
|
||||
|
||||
exportManifestCsv: adminProcedure
|
||||
.input(z.object({ programId: z.string() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const m = await buildManifest(ctx.prisma, input.programId)
|
||||
const escape = (s: string | null | undefined) => {
|
||||
const v = s ?? ''
|
||||
return /[",\n]/.test(v) ? `"${v.replace(/"/g, '""')}"` : v
|
||||
}
|
||||
const lines = [
|
||||
'Type,Team,Name,Email,Dish,Allergens,Allergen notes',
|
||||
...m.members.map((row) =>
|
||||
[
|
||||
'Member',
|
||||
escape(row.project?.name),
|
||||
escape(row.name),
|
||||
escape(row.email),
|
||||
escape(row.dish?.name),
|
||||
escape(row.allergens.join(';')),
|
||||
escape(row.allergenOther),
|
||||
].join(','),
|
||||
),
|
||||
...m.externals.map((row) =>
|
||||
[
|
||||
'External',
|
||||
escape(row.project?.name),
|
||||
escape(row.name),
|
||||
escape(row.email),
|
||||
escape(row.dish?.name),
|
||||
escape(row.allergens.join(';')),
|
||||
escape(row.allergenOther),
|
||||
].join(','),
|
||||
),
|
||||
]
|
||||
return lines.join('\n')
|
||||
}),
|
||||
|
||||
// ─── Member reads ────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user