Bankkarte: optionales Beschreibung-Feld

Neues optionales Freitext-Feld `description` (TEXT NULL) auf
BankCard – z.B. "Geschäftskonto", "gemeinsames Konto mit Partner".
Migration mit IF NOT EXISTS.

Backend service create/update nimmt description entgegen.
Frontend:
- BankCard-Type um description ergänzt.
- BankCardModal: neue Textarea zwischen Ablaufdatum und Aktiv-
  Checkbox mit Placeholder-Hilfetext.
- Bank-Kartenübersicht zeigt die Beschreibung kursiv unter den
  bestehenden Feldern, falls gesetzt (whitespace-pre-line für
  mehrzeilige Notizen).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-09 12:22:17 +02:00
co-authored by Claude Opus 4.7
parent e49133fd64
commit 616cb77c0d
5 changed files with 28 additions and 1 deletions
@@ -0,0 +1,6 @@
-- Optionale Freitext-Beschreibung pro Bankkarte (z.B. "Geschäftskonto",
-- "gemeinsames Konto mit Partner"). TEXT statt VARCHAR, weil Notizen
-- gelegentlich länger werden dürfen.
ALTER TABLE `BankCard`
ADD COLUMN IF NOT EXISTS `description` TEXT NULL;
+1
View File
@@ -327,6 +327,7 @@ model BankCard {
bankName String?
expiryDate DateTime?
documentPath String? // Pfad zur hochgeladenen PDF
description String? @db.Text // Freitext-Notiz (z.B. "Geschäftskonto", "gemeinsames Konto mit Partner")
isActive Boolean @default(true)
contracts Contract[]
createdAt DateTime @default(now())
+2
View File
@@ -317,6 +317,7 @@ export async function createBankCard(
bic?: string;
bankName?: string;
expiryDate?: Date;
description?: string;
}
) {
return prisma.bankCard.create({
@@ -336,6 +337,7 @@ export async function updateBankCard(
bic?: string;
bankName?: string;
expiryDate?: Date;
description?: string;
isActive?: boolean;
}
) {
@@ -961,6 +961,11 @@ function BankCardsTab({
Gültig bis: {formatDate(card.expiryDate)}
</p>
)}
{card.description && (
<p className="text-sm text-gray-600 mt-1 italic whitespace-pre-line">
{card.description}
</p>
)}
{/* Dokument-Upload Bereich */}
<div className="mt-3 pt-3 border-t">
@@ -2657,6 +2662,7 @@ function BankCardModal({
bic: bankCard?.bic || '',
bankName: bankCard?.bankName || '',
expiryDate: bankCard?.expiryDate ? new Date(bankCard.expiryDate).toISOString().split('T')[0] : '',
description: bankCard?.description || '',
isActive: bankCard?.isActive ?? true,
});
@@ -2672,7 +2678,7 @@ function BankCardModal({
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['customer', customerId] });
onClose();
setFormData({ accountHolder: '', iban: '', bic: '', bankName: '', expiryDate: '', isActive: true });
setFormData({ accountHolder: '', iban: '', bic: '', bankName: '', expiryDate: '', description: '', isActive: true });
},
});
@@ -2743,6 +2749,17 @@ function BankCardModal({
onClear={() => setFormData({ ...formData, expiryDate: '' })}
/>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Beschreibung</label>
<textarea
value={formData.description}
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
rows={2}
placeholder="z.B. Geschäftskonto, gemeinsames Konto mit Partner…"
className="block w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
{isEditing && (
<label className="flex items-center gap-2">
<input
+1
View File
@@ -150,6 +150,7 @@ export interface BankCard {
bankName?: string;
expiryDate?: string;
documentPath?: string;
description?: string;
isActive: boolean;
}