-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathExpenseRow.tsx
More file actions
69 lines (62 loc) · 3.1 KB
/
Copy pathExpenseRow.tsx
File metadata and controls
69 lines (62 loc) · 3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
'use client';
import Link from 'next/link';
import { useMemo, useState } from 'react';
import { ExpenseDto } from '@fairshare/shared-types';
import dynamic from 'next/dynamic';
const ReceiptUploadModal = dynamic(() => import('./ReceiptUploadModal').then((mod) => mod.ReceiptUploadModal), {
ssr: false,
});
const categoryLabels: Record<string, string> = {
FOOD: 'Food',
TRAVEL: 'Travel',
UTILITIES: 'Utilities',
GROCERIES: 'Groceries',
ENTERTAINMENT: 'Entertainment',
OTHER: 'Other',
};
export function ExpenseRow({ expense, payerName }: { expense: ExpenseDto; payerName?: string }) {
const [open, setOpen] = useState(false);
const formattedAmount = useMemo(() => {
const amount = Number(expense.totalAmountCents) / 100;
return amount.toLocaleString(undefined, { style: 'currency', currency: expense.currency });
}, [expense.currency, expense.totalAmountCents]);
return (
<>
<tr className="hover:bg-[var(--fs-background)]/50 transition-colors group">
<td className="px-6 py-4 text-base font-semibold text-[var(--fs-text-primary)]">
<div className="space-y-1">
<Link href={`/dashboard/expenses/${expense.id}`} className="hover:text-[var(--fs-primary)] transition-colors">
{expense.description}
</Link>
<div className="flex flex-wrap items-center gap-2 text-[11px] font-bold uppercase tracking-[0.12em] text-[var(--fs-text-muted)]">
<span>{payerName ? `Paid by ${payerName}` : `Payer ${expense.payerId.slice(0, 6)}`}</span>
{expense.category ? (
<span className="rounded-full border border-[var(--fs-border)] bg-[var(--fs-background)] px-2 py-1 text-[10px] text-[var(--fs-text-primary)]">
{categoryLabels[expense.category] ?? expense.category}
</span>
) : null}
{expense.receiptFileKey ? (
<span className="rounded-full border border-emerald-500/20 bg-emerald-500/10 px-2 py-1 text-[10px] text-emerald-600">
Receipt attached
</span>
) : null}
</div>
</div>
</td>
<td className="px-6 py-4 text-right text-base font-bold text-[var(--fs-primary)]">{formattedAmount}</td>
<td className="px-6 py-4 text-right text-[12px] font-medium text-[var(--fs-text-muted)] group-hover:text-[var(--fs-text-primary)] transition-colors">
{new Date(expense.createdAt).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: '2-digit' })}
</td>
<td className="px-6 py-4 text-right">
<button
className="rounded-xl border border-[var(--fs-border)] bg-[var(--fs-background)] px-3 py-2 text-xs font-bold text-[var(--fs-text-primary)] hover:border-[var(--fs-primary)] transition-colors"
onClick={() => setOpen(true)}
>
{expense.receiptFileKey ? 'Replace receipt' : 'Upload receipt'}
</button>
</td>
</tr>
<ReceiptUploadModal expenseId={expense.id} open={open} onClose={() => setOpen(false)} onUploaded={() => setOpen(false)} />
</>
);
}