import { z } from 'zod' import { router, adminProcedure, publicProcedure } from '../trpc' export const organizationsRouter = router({ /** * Get own organization details */ me: adminProcedure.query(async ({ ctx }) => { const org = await ctx.prisma.organization.findUniqueOrThrow({ where: { id: ctx.orgId }, }) return org }), /** * Update org settings (admin only) */ update: adminProcedure .input( z.object({ name: z.string().min(3).optional(), contactEmail: z.string().email().optional(), primaryColor: z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional(), }) ) .mutation(async ({ ctx, input }) => { const org = await ctx.prisma.organization.update({ where: { id: ctx.orgId }, data: input, }) return org }), /** * Accept AVV (Auftragsverarbeitungsvertrag) */ acceptAvv: adminProcedure.mutation(async ({ ctx }) => { const org = await ctx.prisma.organization.update({ where: { id: ctx.orgId }, data: { avvAccepted: true, avvAcceptedAt: new Date(), }, }) return org }), /** * Dashboard stats */ stats: adminProcedure.query(async ({ ctx }) => { const now = new Date() const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000) const [activeMembers, newsThisWeek, upcomingTermine, activeStellen] = await Promise.all([ ctx.prisma.member.count({ where: { orgId: ctx.orgId, status: 'aktiv' }, }), ctx.prisma.news.count({ where: { orgId: ctx.orgId, publishedAt: { gte: weekAgo, not: null }, }, }), ctx.prisma.termin.count({ where: { orgId: ctx.orgId, datum: { gte: now } }, }), ctx.prisma.stelle.count({ where: { orgId: ctx.orgId, aktiv: true }, }), ]) return { activeMembers, newsThisWeek, upcomingTermine, activeStellen } }), /** * Public org info by slug (for mobile onboarding) */ bySlug: publicProcedure .input(z.object({ slug: z.string() })) .query(async ({ ctx, input }) => { const org = await ctx.prisma.organization.findUnique({ where: { slug: input.slug }, select: { id: true, name: true, slug: true, primaryColor: true, logoUrl: true }, }) return org }), })