fix: crash bugs in TeamInvoices + faster load

Bug fixes:
- TeamInvoices: add useAuth import/currentUser (invoice-create crash)
- TeamInvoices: setChartYear -> setExportYear (year-dropdown crash)
- TeamDashboard: drop redundant setState-in-effect (cascading renders)
- Companies: delete dead _UnusedClientCompanies (illegal hook calls)
- annotate intentional empty PDF-fallback catches

Load speed:
- preconnect/dns-prefetch to Supabase origin
- lazy-load heic-to in Converters: page chunk 2737KB -> 9KB
- split recharts into its own 'charts' vendor chunk

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Krao Hasanee
2026-06-08 12:59:11 -04:00
parent 85625f4d95
commit 04e0911e9f
101 changed files with 11786 additions and 7445 deletions
@@ -0,0 +1,112 @@
import SortTh from './SortTh';
function fmt(val) {
return `$${Number(val || 0).toFixed(2)}`;
}
function inferItemType(item) {
const match = String(item?.description || '').match(/\bR(\d{2})\b/i);
if (match) {
return Number(match[1]) <= 0
? { label: 'New', badgeClass: 'badge-initial' }
: { label: 'Revision', badgeClass: 'badge-client_revision' };
}
if (item?.task_id) return { label: 'Task', badgeClass: 'badge-in_progress' };
return { label: 'Other', badgeClass: 'badge-initial' };
}
export default function SubcontractorInvoiceDetailView({
error,
headerActions,
leftCardTitle,
leftCardBody,
rightCardTitle,
rightCardBody,
sortKey,
sortDir,
onSort,
items,
notes,
total,
}) {
return (
<div className="invoice-detail-shell">
{error ? <div className="notification notification-info" style={{ marginBottom: 16, flexShrink: 0 }}>{error}</div> : null}
<div className="invoice-detail-stack">
<div className="invoice-detail-summary-grid">
<div className="card invoice-detail-card">
<div className="invoice-detail-section-title">{leftCardTitle}</div>
{leftCardBody}
</div>
<div className="card invoice-detail-card">
<div className="invoice-detail-card-header">
<div className="invoice-detail-section-title" style={{ marginBottom: 0 }}>{rightCardTitle}</div>
{headerActions ? <div className="invoice-detail-card-actions">{headerActions}</div> : null}
</div>
{rightCardBody}
</div>
</div>
<div className="card invoice-detail-card invoice-detail-line-items-card">
<div className="invoice-detail-section-title">Line Items</div>
{items.length === 0 ? (
<div className="card-empty-center" style={{ minHeight: 120 }}>No line items.</div>
) : (
<div className="scrollbar-thin-theme table-scroll-hidden" style={{ overflowY: 'auto' }}>
<table className="table-sticky-head invoice-detail-table" style={{ width: '100%', borderCollapse: 'collapse', tableLayout: 'fixed' }}>
<colgroup>
<col style={{ width: '12%' }} />
<col style={{ width: '46%' }} />
<col style={{ width: '14%' }} />
<col style={{ width: '14%' }} />
<col style={{ width: '14%' }} />
</colgroup>
<thead>
<tr>
<SortTh col="type" sortKey={sortKey} sortDir={sortDir} onSort={onSort}>Type</SortTh>
<SortTh col="description" sortKey={sortKey} sortDir={sortDir} onSort={onSort}>Description</SortTh>
<SortTh col="quantity" sortKey={sortKey} sortDir={sortDir} onSort={onSort} style={{ textAlign: 'center' }}>Qty</SortTh>
<SortTh col="unit_price" sortKey={sortKey} sortDir={sortDir} onSort={onSort} style={{ textAlign: 'right' }}>Unit Price</SortTh>
<SortTh col="line_total" sortKey={sortKey} sortDir={sortDir} onSort={onSort} style={{ textAlign: 'right' }}>Total</SortTh>
</tr>
</thead>
<tbody>
{items.map((item) => {
const itemType = inferItemType(item);
return (
<tr key={item.id}>
<td style={{ padding: '5px 0' }}>
<span className={`badge ${itemType.badgeClass}`}>{itemType.label}</span>
</td>
<td className="invoice-detail-cell">{item.description}</td>
<td className="invoice-detail-cell" style={{ textAlign: 'center' }}>{item.quantity}</td>
<td className="invoice-detail-cell" style={{ textAlign: 'right' }}>{fmt(item.unit_price)}</td>
<td className="invoice-detail-cell" style={{ textAlign: 'right', fontWeight: 400 }}>
{fmt(Number(item.unit_price || 0) * Number(item.quantity || 1))}
</td>
</tr>
);
})}
</tbody>
</table>
</div>
)}
<div className="invoice-detail-total-row">
<div style={{ textAlign: 'right' }}>
<div className="invoice-detail-total-label">Total</div>
<div className="invoice-detail-total-value">{fmt(total)}</div>
</div>
</div>
</div>
{notes ? (
<div className="card invoice-detail-card">
<div className="invoice-detail-section-title">Notes</div>
<p className="invoice-detail-notes">{notes}</p>
</div>
) : null}
</div>
</div>
);
}