Files
myeasycms-v2/packages/features/verbandsverwaltung/src/server/actions/verband-actions.ts

498 lines
17 KiB
TypeScript

'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 };
});