'use server' import { revalidatePath } from 'next/cache' import { z } from 'zod' import { requireUser } from '@/lib/auth/current' import { AccessError } from '@/lib/errors' import { adoptAsEntry, editMessage, markRead, sendMessage, toggleReaction, withdrawMessage, } from '@/lib/chat/service' import { REACTIONS } from '@/lib/chat/terms' import { de } from '@/lib/i18n/de' export type ActionResult = { ok: true } | { ok: false; error: string } function toMessage(error: unknown): string { if (error instanceof AccessError) { return de.actionErrors[error.code] ?? de.actionErrors.default! } console.error('[chat] unerwartet', error) return de.actionErrors.default! } const scope = z.union([ z.object({ kind: z.literal('case'), caseNumber: z.string().min(1) }), z.object({ kind: z.literal('personnel'), fileId: z.string().min(1) }), ]) const sendSchema = z.object({ id: z.string().min(1).max(64), scope, body: z.string().min(1).max(4000), replyToId: z.string().max(64).nullish(), }) export async function sendMessageAction(input: unknown): Promise { const user = await requireUser() const parsed = sendSchema.safeParse(input) if (!parsed.success) return { ok: false, error: de.actionErrors['message-empty']! } try { await sendMessage(user.permissions, parsed.data) return { ok: true } } catch (error) { return { ok: false, error: toMessage(error) } } } const editSchema = z.object({ id: z.string().min(1), body: z.string().min(1).max(4000) }) export async function editMessageAction(input: unknown): Promise { const user = await requireUser() const parsed = editSchema.safeParse(input) if (!parsed.success) return { ok: false, error: de.actionErrors['message-empty']! } try { await editMessage(user.permissions, parsed.data) return { ok: true } } catch (error) { return { ok: false, error: toMessage(error) } } } const idSchema = z.object({ id: z.string().min(1) }) export async function withdrawMessageAction(input: unknown): Promise { const user = await requireUser() const parsed = idSchema.safeParse(input) if (!parsed.success) return { ok: false, error: de.actionErrors.default! } try { await withdrawMessage(user.permissions, parsed.data.id) return { ok: true } } catch (error) { return { ok: false, error: toMessage(error) } } } const reactionSchema = z.object({ id: z.string().min(1), key: z.enum(REACTIONS) }) export async function toggleReactionAction(input: unknown): Promise { const user = await requireUser() const parsed = reactionSchema.safeParse(input) if (!parsed.success) return { ok: false, error: de.actionErrors.default! } try { await toggleReaction(user.permissions, parsed.data) return { ok: true } } catch (error) { return { ok: false, error: toMessage(error) } } } /** * „Als Vermerk übernehmen". Danach wird die Akte neu geladen: der Vermerk * gehört in den Verlauf, und der steht auf derselben Seite. */ export async function adoptAsEntryAction(input: unknown): Promise { const user = await requireUser() const parsed = idSchema.safeParse(input) if (!parsed.success) return { ok: false, error: de.actionErrors.default! } try { await adoptAsEntry(user.permissions, parsed.data.id) revalidatePath('/faelle', 'layout') return { ok: true } } catch (error) { return { ok: false, error: toMessage(error) } } } const readSchema = z.object({ scopeType: z.enum(['case', 'personnel']), scopeId: z.string().min(1), }) export async function markReadAction(input: unknown): Promise { const user = await requireUser() const parsed = readSchema.safeParse(input) if (!parsed.success) return { ok: false, error: de.actionErrors.default! } await markRead(user.permissions, parsed.data.scopeType, parsed.data.scopeId) return { ok: true } }