wulf-pulse/components/mobile/FinanceRow.tsx
lorentz 180ab517e6 feat(05-01): create FinanceRow component
- 2-line stacked row for invoice and payment lists (D-06)
- Exports FinanceRow + FinanceRowProps per UI-SPEC contract
- Supports amountTone destructive/positive/default variants
- No priority stripe, no interactive handlers (read-only per D-22)
- Phase comment block per Phase 3/4 convention
2026-05-03 19:52:02 -04:00

43 lines
1.9 KiB
TypeScript

'use client';
/* FinanceRow — phase 05 (FIN-02).
* Purpose: 2-line stacked row used by Open Invoices and Recent Payments lists.
* Line 1: primary label (left, text-sm font-semibold truncate) + amount (right, text-sm font-semibold).
* Line 2: secondary metadata (left, text-xs text-muted-foreground) + optional date (right, text-xs text-muted-foreground).
* Pure presentational — parent owns the data.
* Props: see FinanceRowProps. */
import { cn } from '@/lib/utils';
export interface FinanceRowProps {
/** Primary label on line 1 (e.g., customer name) */
primary: string;
/** Amount string already formatted (e.g., "$1,234") — caller passes fmt$(value) */
amount: string;
/** Secondary metadata on line 2 (e.g., "#1234 · Due May 1" or just a date) */
secondary?: React.ReactNode;
/** Optional right-side date on line 2 (used by payment rows; invoice rows put date in `secondary`) */
rightSecondary?: React.ReactNode;
/** When true, amount renders in destructive color (overdue invoices). */
amountTone?: 'default' | 'destructive' | 'positive';
}
export function FinanceRow({ primary, amount, secondary, rightSecondary, amountTone = 'default' }: FinanceRowProps) {
const amountClass = cn(
'text-sm font-semibold shrink-0',
amountTone === 'destructive' && 'text-destructive',
amountTone === 'positive' && 'text-emerald-600'
);
return (
<div className="px-4 py-3 flex items-start justify-between gap-2 hover:bg-muted/50 transition-colors">
<div className="flex-1 min-w-0">
<p className="text-sm font-semibold truncate">{primary}</p>
{secondary && <p className="text-xs text-muted-foreground mt-0.5">{secondary}</p>}
</div>
<div className="shrink-0 text-right">
<p className={amountClass}>{amount}</p>
{rightSecondary && <p className="text-xs text-muted-foreground mt-0.5">{rightSecondary}</p>}
</div>
</div>
);
}