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
This commit is contained in:
parent
a0ccd14044
commit
180ab517e6
1 changed files with 43 additions and 0 deletions
43
components/mobile/FinanceRow.tsx
Normal file
43
components/mobile/FinanceRow.tsx
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
'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>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue