'use client'; import { useState, useCallback } from 'react'; import { useRouter } from 'next/navigation'; 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 { 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'; interface MandateManagerProps { mandates: Array>; memberId: string; accountId: string; } const SEQUENCE_LABELS: Record = { FRST: 'Erstlastschrift', RCUR: 'Wiederkehrend', FNAL: 'Letzte', OOFF: 'Einmalig', }; function getMandateStatusColor( status: string, ): 'default' | 'secondary' | 'destructive' | 'outline' { switch (status) { case 'active': return 'default'; case 'pending': return 'outline'; case 'revoked': case 'expired': return 'destructive'; default: return 'secondary'; } } const MANDATE_STATUS_LABELS: Record = { active: 'Aktiv', pending: 'Ausstehend', revoked: 'Widerrufen', expired: 'Abgelaufen', }; interface MandateFormValues { mandateReference: string; iban: string; bic: string; accountHolder: string; mandateDate: string; sequence: string; } export function MandateManager({ mandates, memberId, accountId, }: MandateManagerProps) { const router = useRouter(); const [showForm, setShowForm] = useState(false); const form = useForm({ defaultValues: { mandateReference: '', iban: '', bic: '', accountHolder: '', mandateDate: new Date().toISOString().split('T')[0]!, sequence: 'FRST', }, }); const { execute: executeCreate, isPending: isCreating } = useAction( createMandate, { onSuccess: ({ data }) => { if (data?.success) { toast.success('SEPA-Mandat erstellt'); form.reset(); setShowForm(false); router.refresh(); } }, onError: ({ error }) => { toast.error(error.serverError ?? 'Fehler beim Erstellen'); }, }, ); const { execute: executeRevoke, isPending: isRevoking } = useAction( revokeMandate, { onSuccess: ({ data }) => { if (data?.success) { toast.success('Mandat widerrufen'); router.refresh(); } }, onError: ({ error }) => { toast.error(error.serverError ?? 'Fehler beim Widerrufen'); }, }, ); const handleSubmit = useCallback( (values: MandateFormValues) => { executeCreate({ memberId, accountId, mandateReference: values.mandateReference, iban: values.iban, bic: values.bic, accountHolder: values.accountHolder, mandateDate: values.mandateDate, sequence: values.sequence as 'FRST' | 'RCUR' | 'FNAL' | 'OOFF', }); }, [executeCreate, memberId, accountId], ); const handleRevoke = useCallback( (mandateId: string, reference: string) => { if (!window.confirm(`Mandat "${reference}" wirklich widerrufen?`)) { return; } executeRevoke({ mandateId }); }, [executeRevoke], ); return (

SEPA-Mandate

{/* Inline Create Form */} {showForm && ( Neues SEPA-Mandat
{ const value = e.target.value .toUpperCase() .replace(/[^A-Z0-9]/g, ''); form.setValue('iban', value); }} />
)} {/* Table */}
{mandates.length === 0 ? ( ) : ( mandates.map((mandate) => { const mandateId = String(mandate.id ?? ''); const reference = String(mandate.mandate_reference ?? '—'); const mandateStatus = String(mandate.status ?? 'pending'); const isPrimary = Boolean(mandate.is_primary); const canRevoke = mandateStatus === 'active' || mandateStatus === 'pending'; return ( ); }) )}
Referenz IBAN Kontoinhaber Datum Status Primär Aktionen
Keine SEPA-Mandate vorhanden.
{reference} {formatIban(mandate.iban as string | null | undefined)} {String(mandate.account_holder ?? '—')} {formatDate(mandate.mandate_date as string)} {MANDATE_STATUS_LABELS[mandateStatus] ?? mandateStatus} {isPrimary ? '✓' : '✗'} {canRevoke && ( )}
); }