Add account hierarchy framework with migrations, RLS policies, and UI components

This commit is contained in:
T. Zehetbauer
2026-03-31 22:18:04 +02:00
parent 7e7da0b465
commit 59546ad6d2
262 changed files with 11671 additions and 3927 deletions

View File

@@ -1,14 +1,18 @@
'use client';
import { useState, useCallback } from 'react';
import { useForm } from 'react-hook-form';
import { useAction } from 'next-safe-action/hooks';
import { useRouter } from 'next/navigation';
import { toast } from '@kit/ui/sonner';
import { useAction } from 'next-safe-action/hooks';
import { useForm } from 'react-hook-form';
import { formatDate } from '@kit/shared/dates';
import { Badge } from '@kit/ui/badge';
import { Button } from '@kit/ui/button';
import { Input } from '@kit/ui/input';
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
import { Input } from '@kit/ui/input';
import { toast } from '@kit/ui/sonner';
import { formatIban } from '../lib/member-utils';
import { createMandate, revokeMandate } from '../server/actions/member-actions';
@@ -119,7 +123,7 @@ export function MandateManager({
bic: values.bic,
accountHolder: values.accountHolder,
mandateDate: values.mandateDate,
sequence: values.sequence as "FRST" | "RCUR" | "FNAL" | "OOFF",
sequence: values.sequence as 'FRST' | 'RCUR' | 'FNAL' | 'OOFF',
});
},
[executeCreate, memberId, accountId],
@@ -127,11 +131,7 @@ export function MandateManager({
const handleRevoke = useCallback(
(mandateId: string, reference: string) => {
if (
!window.confirm(
`Mandat "${reference}" wirklich widerrufen?`,
)
) {
if (!window.confirm(`Mandat "${reference}" wirklich widerrufen?`)) {
return;
}
executeRevoke({ mandateId });
@@ -185,10 +185,7 @@ export function MandateManager({
</div>
<div className="space-y-1">
<label className="text-sm font-medium">BIC</label>
<Input
placeholder="COBADEFFXXX"
{...form.register('bic')}
/>
<Input placeholder="COBADEFFXXX" {...form.register('bic')} />
</div>
<div className="space-y-1">
<label className="text-sm font-medium">Kontoinhaber *</label>
@@ -207,7 +204,7 @@ export function MandateManager({
<div className="space-y-1">
<label className="text-sm font-medium">Sequenz</label>
<select
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"
className="border-input bg-background flex h-10 w-full rounded-md border px-3 py-2 text-sm"
{...form.register('sequence')}
>
<option value="FRST">FRST Erstlastschrift</option>
@@ -230,7 +227,7 @@ export function MandateManager({
<div className="rounded-md border">
<table className="w-full text-sm">
<thead>
<tr className="border-b bg-muted/50">
<tr className="bg-muted/50 border-b">
<th className="px-4 py-3 text-left font-medium">Referenz</th>
<th className="px-4 py-3 text-left font-medium">IBAN</th>
<th className="px-4 py-3 text-left font-medium">Kontoinhaber</th>
@@ -245,7 +242,7 @@ export function MandateManager({
<tr>
<td
colSpan={7}
className="px-4 py-8 text-center text-muted-foreground"
className="text-muted-foreground px-4 py-8 text-center"
>
Keine SEPA-Mandate vorhanden.
</td>
@@ -261,21 +258,15 @@ export function MandateManager({
return (
<tr key={mandateId} className="border-b">
<td className="px-4 py-3 font-mono text-xs">
{reference}
</td>
<td className="px-4 py-3 font-mono text-xs">{reference}</td>
<td className="px-4 py-3 font-mono text-xs">
{formatIban(mandate.iban as string | null | undefined)}
</td>
<td className="px-4 py-3">
{String(mandate.account_holder ?? '—')}
</td>
<td className="px-4 py-3 text-muted-foreground">
{mandate.mandate_date
? new Date(
String(mandate.mandate_date),
).toLocaleDateString('de-DE')
: '—'}
<td className="text-muted-foreground px-4 py-3">
{formatDate(mandate.mandate_date as string)}
</td>
<td className="px-4 py-3">
<Badge variant={getMandateStatusColor(mandateStatus)}>