import { type CreatePostInput, createPostInputSchema, type UpdatePostInput, updatePostInputSchema, } from "@cms/content" import { type CrudAuditHook, type CrudMutationContext, createCrudService } from "@cms/crud" import { z } from "zod" import type { Post } from "../prisma/generated/client/client" import { db } from "./client" const postRepository = { list: () => db.post.findMany({ orderBy: { updatedAt: "desc", }, }), findById: (id: string) => db.post.findUnique({ where: { id }, }), create: (input: CreatePostInput) => db.post.create({ data: input, }), update: (id: string, input: UpdatePostInput) => db.post.update({ where: { id }, data: input, }), delete: (id: string) => db.post.delete({ where: { id }, }), } const supportedLocaleSchema = z.enum(["de", "en", "es", "fr"]) const upsertPostTranslationInputSchema = z.object({ postId: z.string().uuid(), locale: supportedLocaleSchema, title: z.string().min(3).max(180), excerpt: z.string().max(320).nullable().optional(), body: z.string().min(1), }) const postAuditHooks: Array> = [] const postCrudService = createCrudService({ resource: "post", repository: postRepository, schemas: { create: createPostInputSchema, update: updatePostInputSchema, }, auditHooks: postAuditHooks, }) export function registerPostCrudAuditHook(hook: CrudAuditHook): () => void { postAuditHooks.push(hook) return () => { const index = postAuditHooks.indexOf(hook) if (index >= 0) { postAuditHooks.splice(index, 1) } } } export async function listPosts() { return postCrudService.list() } export async function getPostById(id: string) { return postCrudService.getById(id) } export async function getPostBySlug(slug: string) { return db.post.findUnique({ where: { slug }, }) } export async function getPostBySlugForLocale(slug: string, locale: string) { const normalizedLocale = supportedLocaleSchema.safeParse(locale).data const post = await db.post.findUnique({ where: { slug }, include: { translations: normalizedLocale ? { where: { locale: normalizedLocale, }, take: 1, } : false, }, }) if (!post) { return null } const translation = post.translations?.[0] return { ...post, title: translation?.title ?? post.title, excerpt: translation?.excerpt ?? post.excerpt, body: translation?.body ?? post.body, } } export async function listPostsForLocale(locale: string) { const normalizedLocale = supportedLocaleSchema.safeParse(locale).data const posts = await db.post.findMany({ where: { status: "published", }, orderBy: { updatedAt: "desc", }, include: { translations: normalizedLocale ? { where: { locale: normalizedLocale }, take: 1, } : false, }, }) return posts.map((post) => { const translation = post.translations?.[0] return { ...post, title: translation?.title ?? post.title, excerpt: translation?.excerpt ?? post.excerpt, body: translation?.body ?? post.body, } }) } export async function listPostsWithTranslations() { return db.post.findMany({ orderBy: { updatedAt: "desc", }, include: { translations: { orderBy: [{ locale: "asc" }], }, }, }) } export async function upsertPostTranslation(input: unknown) { const payload = upsertPostTranslationInputSchema.parse(input) const { postId, locale, ...data } = payload return db.postTranslation.upsert({ where: { postId_locale: { postId, locale, }, }, create: { postId, locale, ...data, }, update: data, }) } export async function createPost(input: unknown, context?: CrudMutationContext) { return postCrudService.create(input, context) } export async function updatePost(id: string, input: unknown, context?: CrudMutationContext) { return postCrudService.update(id, input, context) } export async function deletePost(id: string, context?: CrudMutationContext) { return postCrudService.delete(id, context) }