- 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
43 lines
1.9 KiB
TypeScript
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>
|
|
);
|
|
}
|