'use server'; import { revalidatePath } from 'next/cache'; import { z } from 'zod'; import { authActionClient } from '@kit/next/safe-action'; import { todayISO } from '@kit/shared/dates'; import { getLogger } from '@kit/shared/logger'; import { getSupabaseServerClient } from '@kit/supabase/server-client'; import { CreateMemberClubSchema, UpdateMemberClubSchema, CreateClubContactSchema, UpdateClubContactSchema, CreateClubRoleSchema, CreateAssociationTypeSchema, CreateClubFeeTypeSchema, CreateClubFeeBillingSchema, CreateClubNoteSchema, CreateAssociationHistorySchema, } from '../../schema/verband.schema'; import { createVerbandApi } from '../api'; const REVALIDATE_PATH = '/home/[account]/verband'; // ===================================================== // Clubs (Vereine) // ===================================================== export const createClub = authActionClient .inputSchema(CreateMemberClubSchema) .action(async ({ parsedInput: input, ctx }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); const userId = ctx.user.id; logger.info({ name: 'verband.club.create' }, 'Creating club...'); const result = await api.createClub(input, userId); logger.info({ name: 'verband.club.create' }, 'Club created'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const updateClub = authActionClient .inputSchema(UpdateMemberClubSchema) .action(async ({ parsedInput: input, ctx }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); const userId = ctx.user.id; logger.info({ name: 'verband.club.update' }, 'Updating club...'); const result = await api.updateClub(input, userId); logger.info({ name: 'verband.club.update' }, 'Club updated'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const archiveClub = authActionClient .inputSchema( z.object({ clubId: z.string().uuid(), accountId: z.string().uuid(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.club.archive' }, 'Archiving club...'); await api.archiveClub(input.clubId); logger.info({ name: 'verband.club.archive' }, 'Club archived'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true }; }); // ===================================================== // Contacts (Ansprechpartner) // ===================================================== export const createContact = authActionClient .inputSchema(CreateClubContactSchema) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.contact.create' }, 'Creating contact...'); const result = await api.createContact(input); logger.info({ name: 'verband.contact.create' }, 'Contact created'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const updateContact = authActionClient .inputSchema(UpdateClubContactSchema) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.contact.update' }, 'Updating contact...'); const result = await api.updateContact(input); logger.info({ name: 'verband.contact.update' }, 'Contact updated'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const deleteContact = authActionClient .inputSchema( z.object({ contactId: z.string().uuid(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.contact.delete' }, 'Deleting contact...'); await api.deleteContact(input.contactId); logger.info({ name: 'verband.contact.delete' }, 'Contact deleted'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true }; }); // ===================================================== // Roles (Funktionen) // ===================================================== export const createRole = authActionClient .inputSchema(CreateClubRoleSchema) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.role.create' }, 'Creating role...'); const result = await api.createRole(input); logger.info({ name: 'verband.role.create' }, 'Role created'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const updateRole = authActionClient .inputSchema( z.object({ roleId: z.string().uuid(), name: z.string().min(1).max(128).optional(), description: z.string().max(512).optional(), sortOrder: z.number().int().optional(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); const { roleId, ...updates } = input; logger.info({ name: 'verband.role.update' }, 'Updating role...'); const result = await api.updateRole(roleId, updates); logger.info({ name: 'verband.role.update' }, 'Role updated'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const deleteRole = authActionClient .inputSchema( z.object({ roleId: z.string().uuid(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.role.delete' }, 'Deleting role...'); await api.deleteRole(input.roleId); logger.info({ name: 'verband.role.delete' }, 'Role deleted'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true }; }); // ===================================================== // Association Types (Vereinstypen) // ===================================================== export const createAssociationType = authActionClient .inputSchema(CreateAssociationTypeSchema) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info( { name: 'verband.type.create' }, 'Creating association type...', ); const result = await api.createType(input); logger.info({ name: 'verband.type.create' }, 'Association type created'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const updateAssociationType = authActionClient .inputSchema( z.object({ typeId: z.string().uuid(), name: z.string().min(1).max(128).optional(), description: z.string().max(512).optional(), sortOrder: z.number().int().optional(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); const { typeId, ...updates } = input; logger.info( { name: 'verband.type.update' }, 'Updating association type...', ); const result = await api.updateType(typeId, updates); logger.info({ name: 'verband.type.update' }, 'Association type updated'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const deleteAssociationType = authActionClient .inputSchema( z.object({ typeId: z.string().uuid(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info( { name: 'verband.type.delete' }, 'Deleting association type...', ); await api.deleteType(input.typeId); logger.info({ name: 'verband.type.delete' }, 'Association type deleted'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true }; }); // ===================================================== // Fee Types (Beitragsarten) // ===================================================== export const createFeeType = authActionClient .inputSchema(CreateClubFeeTypeSchema) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.feeType.create' }, 'Creating fee type...'); const result = await api.createFeeType(input); logger.info({ name: 'verband.feeType.create' }, 'Fee type created'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const updateFeeType = authActionClient .inputSchema( z.object({ feeTypeId: z.string().uuid(), name: z.string().min(1).max(128).optional(), description: z.string().max(512).optional(), defaultAmount: z.number().min(0).optional(), isActive: z.boolean().optional(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); const { feeTypeId, ...updates } = input; logger.info({ name: 'verband.feeType.update' }, 'Updating fee type...'); const result = await api.updateFeeType(feeTypeId, updates); logger.info({ name: 'verband.feeType.update' }, 'Fee type updated'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const deleteFeeType = authActionClient .inputSchema( z.object({ feeTypeId: z.string().uuid(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.feeType.delete' }, 'Deleting fee type...'); await api.deleteFeeType(input.feeTypeId); logger.info({ name: 'verband.feeType.delete' }, 'Fee type deleted'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true }; }); // ===================================================== // Fee Billings (Beitragsabrechnungen) // ===================================================== export const createFeeBilling = authActionClient .inputSchema(CreateClubFeeBillingSchema) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.billing.create' }, 'Creating fee billing...'); const result = await api.createFeeBilling(input); logger.info({ name: 'verband.billing.create' }, 'Fee billing created'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const updateFeeBilling = authActionClient .inputSchema( CreateClubFeeBillingSchema.partial().extend({ billingId: z.string().uuid(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); const { billingId, ...updates } = input; logger.info({ name: 'verband.billing.update' }, 'Updating fee billing...'); const result = await api.updateFeeBilling(billingId, updates); logger.info({ name: 'verband.billing.update' }, 'Fee billing updated'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const deleteFeeBilling = authActionClient .inputSchema( z.object({ billingId: z.string().uuid(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.billing.delete' }, 'Deleting fee billing...'); await api.deleteFeeBilling(input.billingId); logger.info({ name: 'verband.billing.delete' }, 'Fee billing deleted'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true }; }); export const markBillingPaid = authActionClient .inputSchema( z.object({ billingId: z.string().uuid(), paidDate: z.string().optional(), paymentMethod: z.string().optional(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info( { name: 'verband.billing.markPaid' }, 'Marking billing as paid...', ); const result = await api.updateFeeBilling(input.billingId, { status: 'bezahlt', paidDate: input.paidDate ?? todayISO(), paymentMethod: input.paymentMethod as | 'bar' | 'lastschrift' | 'ueberweisung' | 'paypal' | undefined, }); logger.info({ name: 'verband.billing.markPaid' }, 'Billing marked as paid'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); // ===================================================== // Notes (Notizen / Aufgaben) // ===================================================== export const createClubNote = authActionClient .inputSchema(CreateClubNoteSchema) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.note.create' }, 'Creating note...'); const result = await api.createNote(input); logger.info({ name: 'verband.note.create' }, 'Note created'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const updateClubNote = authActionClient .inputSchema( CreateClubNoteSchema.partial().extend({ noteId: z.string().uuid(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); const { noteId, ...updates } = input; logger.info({ name: 'verband.note.update' }, 'Updating note...'); const result = await api.updateNote(noteId, updates); logger.info({ name: 'verband.note.update' }, 'Note updated'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const completeClubNote = authActionClient .inputSchema( z.object({ noteId: z.string().uuid(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.note.complete' }, 'Completing note...'); const result = await api.completeNote(input.noteId); logger.info({ name: 'verband.note.complete' }, 'Note completed'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; }); export const deleteClubNote = authActionClient .inputSchema( z.object({ noteId: z.string().uuid(), }), ) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info({ name: 'verband.note.delete' }, 'Deleting note...'); await api.deleteNote(input.noteId); logger.info({ name: 'verband.note.delete' }, 'Note deleted'); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true }; }); // ===================================================== // Association History (Verbandshistorie) // ===================================================== export const upsertAssociationHistory = authActionClient .inputSchema(CreateAssociationHistorySchema) .action(async ({ parsedInput: input }) => { const client = getSupabaseServerClient(); const logger = await getLogger(); const api = createVerbandApi(client); logger.info( { name: 'verband.history.upsert' }, 'Upserting association history...', ); const result = await api.upsertHistory(input); logger.info( { name: 'verband.history.upsert' }, 'Association history upserted', ); revalidatePath(REVALIDATE_PATH, 'page'); return { success: true, data: result }; });