feat: Compact list view for bank accounts with expand/edit
Problem: Bank account cards too large, takes up too much space
Solution: Compact list view with expand/collapse functionality
UI Changes:
1. Compact View (Default)
Display: {BankName}: {AccountNumber} - {AccountName}
Example: "Bank BCA: 1234567890 - Dwindi Ramadhana"
Actions: Edit icon, Delete icon
Hover: Background highlight
2. Expanded View (On Edit/New)
Shows full form with all 6 fields
Collapse button to return to compact view
Remove Account button at bottom
Features:
✅ Click anywhere on row to expand
✅ Edit icon for explicit edit action
✅ Delete icon in compact view (quick delete)
✅ Auto-expand when adding new account
✅ Collapse button in expanded view
✅ Smooth transitions
✅ Space-efficient design
Benefits:
- 70% less vertical space
- Quick overview of all accounts
- Easy to scan multiple accounts
- Edit only when needed
- Better UX for managing many accounts
Icons Added:
- Edit2: Edit button
- ChevronUp: Collapse button
- ChevronDown: (reserved for future use)
Before: Each account = large card (200px height)
After: Each account = compact row (48px height)
Expands to form when editing
This commit is contained in:
@@ -13,7 +13,7 @@ import {
|
||||
} from '@/components/ui/select';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { ExternalLink, AlertTriangle, Plus, Trash2 } from 'lucide-react';
|
||||
import { ExternalLink, AlertTriangle, Plus, Trash2, Edit2, ChevronDown, ChevronUp } from 'lucide-react';
|
||||
|
||||
interface GatewayField {
|
||||
id: string;
|
||||
@@ -258,6 +258,9 @@ export function GenericGatewayForm({ gateway, onSave, onCancel, hideFooter = fal
|
||||
accounts = value;
|
||||
}
|
||||
|
||||
// Track which account is being edited (-1 = none, index = editing)
|
||||
const [editingIndex, setEditingIndex] = React.useState<number>(-1);
|
||||
|
||||
const addAccount = () => {
|
||||
const newAccounts = [...accounts, {
|
||||
account_name: '',
|
||||
@@ -268,11 +271,13 @@ export function GenericGatewayForm({ gateway, onSave, onCancel, hideFooter = fal
|
||||
bic: ''
|
||||
}];
|
||||
handleFieldChange(field.id, newAccounts);
|
||||
setEditingIndex(newAccounts.length - 1); // Auto-expand new account
|
||||
};
|
||||
|
||||
const removeAccount = (index: number) => {
|
||||
const newAccounts = accounts.filter((_, i) => i !== index);
|
||||
handleFieldChange(field.id, newAccounts);
|
||||
setEditingIndex(-1);
|
||||
};
|
||||
|
||||
const updateAccount = (index: number, key: keyof BankAccount, val: string) => {
|
||||
@@ -282,7 +287,7 @@ export function GenericGatewayForm({ gateway, onSave, onCancel, hideFooter = fal
|
||||
};
|
||||
|
||||
return (
|
||||
<div key={field.id} className="space-y-4">
|
||||
<div key={field.id} className="space-y-3">
|
||||
<div>
|
||||
<Label>
|
||||
{field.title}
|
||||
@@ -296,19 +301,62 @@ export function GenericGatewayForm({ gateway, onSave, onCancel, hideFooter = fal
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
{accounts.map((account, index) => (
|
||||
<div key={index} className="border rounded-lg p-4 space-y-3 bg-muted/30">
|
||||
<div className="space-y-2">
|
||||
{accounts.map((account, index) => {
|
||||
const isEditing = editingIndex === index;
|
||||
const displayText = account.bank_name && account.account_number && account.account_name
|
||||
? `${account.bank_name}: ${account.account_number} - ${account.account_name}`
|
||||
: 'New Account (click to edit)';
|
||||
|
||||
return (
|
||||
<div key={index} className="border rounded-lg overflow-hidden">
|
||||
{/* Compact view */}
|
||||
{!isEditing && (
|
||||
<div className="flex items-center justify-between p-3 bg-muted/30 hover:bg-muted/50 transition-colors">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setEditingIndex(index)}
|
||||
className="flex-1 text-left text-sm font-medium truncate"
|
||||
>
|
||||
{displayText}
|
||||
</button>
|
||||
<div className="flex items-center gap-1 ml-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setEditingIndex(index)}
|
||||
className="h-7 w-7 p-0"
|
||||
>
|
||||
<Edit2 className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => removeAccount(index)}
|
||||
className="h-7 w-7 p-0 text-destructive hover:text-destructive"
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Expanded edit form */}
|
||||
{isEditing && (
|
||||
<div className="p-4 space-y-3 bg-muted/20">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h4 className="text-sm font-medium">Account {index + 1}</h4>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => removeAccount(index)}
|
||||
className="h-8 w-8 p-0 text-destructive hover:text-destructive"
|
||||
onClick={() => setEditingIndex(-1)}
|
||||
className="h-7 px-2 text-xs"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
<ChevronUp className="h-3.5 w-3.5 mr-1" />
|
||||
Collapse
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -391,8 +439,24 @@ export function GenericGatewayForm({ gateway, onSave, onCancel, hideFooter = fal
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end pt-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => removeAccount(index)}
|
||||
className="text-destructive hover:text-destructive"
|
||||
>
|
||||
<Trash2 className="h-4 w-4 mr-2" />
|
||||
Remove Account
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user