add commission section

This commit is contained in:
Satyam Rastogi
2026-05-11 19:53:32 +05:30
parent 0b6ee9d626
commit 178d033864
2 changed files with 184 additions and 31 deletions
+24
View File
@@ -2011,6 +2011,8 @@ const MOCK_PROJECTS = [
spent: 22500, spent: 22500,
variancePercent: -50.0, variancePercent: -50.0,
margin: 0.40, margin: 0.40,
commissionType: 'percent_gross',
commissionRate: 10,
commission: 4500, commission: 4500,
additionalExpenses: 1200, additionalExpenses: 1200,
startDate: '2026-01-20', startDate: '2026-01-20',
@@ -2086,6 +2088,8 @@ const MOCK_PROJECTS = [
spent: 8500, spent: 8500,
variancePercent: 0, variancePercent: 0,
margin: 0.35, margin: 0.35,
commissionType: 'flat',
commissionRate: 850,
commission: 850, commission: 850,
additionalExpenses: 350, additionalExpenses: 350,
startDate: '2025-11-15', startDate: '2025-11-15',
@@ -2134,6 +2138,8 @@ const MOCK_PROJECTS = [
spent: 18400, spent: 18400,
variancePercent: -42.5, variancePercent: -42.5,
margin: 0.30, margin: 0.30,
commissionType: 'percent_net',
commissionRate: 15,
commission: 3200, commission: 3200,
additionalExpenses: 900, additionalExpenses: 900,
startDate: '2026-01-06', startDate: '2026-01-06',
@@ -2208,6 +2214,8 @@ const MOCK_PROJECTS = [
spent: 62300, spent: 62300,
variancePercent: 13.3, variancePercent: 13.3,
margin: -0.13, margin: -0.13,
commissionType: 'custom',
commissionRate: 5500,
commission: 5500, commission: 5500,
additionalExpenses: 3800, additionalExpenses: 3800,
startDate: '2025-12-01', startDate: '2025-12-01',
@@ -2293,6 +2301,8 @@ const MOCK_PROJECTS = [
spent: 14200, spent: 14200,
variancePercent: -49.3, variancePercent: -49.3,
margin: 0.25, margin: 0.25,
commissionType: 'percent_gross',
commissionRate: 10,
commission: 2800, commission: 2800,
additionalExpenses: 600, additionalExpenses: 600,
startDate: '2026-01-06', startDate: '2026-01-06',
@@ -2365,6 +2375,8 @@ const MOCK_PROJECTS = [
spent: 5600, spent: 5600,
variancePercent: -69.7, variancePercent: -69.7,
margin: 0.38, margin: 0.38,
commissionType: 'flat',
commissionRate: 1850,
commission: 1850, commission: 1850,
additionalExpenses: 450, additionalExpenses: 450,
startDate: '2026-02-03', startDate: '2026-02-03',
@@ -2416,6 +2428,8 @@ const MOCK_PROJECTS = [
spent: 48000, spent: 48000,
variancePercent: -61.6, variancePercent: -61.6,
margin: 0.35, margin: 0.35,
commissionType: 'percent_gross',
commissionRate: 10,
commission: 12500, commission: 12500,
additionalExpenses: 2800, additionalExpenses: 2800,
startDate: '2026-01-27', startDate: '2026-01-27',
@@ -2509,6 +2523,8 @@ const MOCK_PROJECTS = [
spent: 91500, spent: 91500,
variancePercent: 22.0, variancePercent: 22.0,
margin: -0.22, margin: -0.22,
commissionType: 'percent_net',
commissionRate: 12,
commission: 7500, commission: 7500,
additionalExpenses: 4200, additionalExpenses: 4200,
startDate: '2025-11-18', startDate: '2025-11-18',
@@ -2558,6 +2574,8 @@ const MOCK_PROJECTS = [
budget: 42000, budget: 42000,
spent: 25800, spent: 25800,
margin: 0.28, margin: 0.28,
commissionType: 'percent_gross',
commissionRate: 10,
commission: 4200, commission: 4200,
additionalExpenses: 1100, additionalExpenses: 1100,
startDate: '2026-01-13', startDate: '2026-01-13',
@@ -2605,6 +2623,8 @@ const MOCK_PROJECTS = [
budget: 35000, budget: 35000,
spent: 35000, spent: 35000,
margin: 0.30, margin: 0.30,
commissionType: 'custom',
commissionRate: 3500,
commission: 3500, commission: 3500,
additionalExpenses: 800, additionalExpenses: 800,
startDate: '2025-09-15', startDate: '2025-09-15',
@@ -2652,6 +2672,8 @@ const MOCK_PROJECTS = [
budget: 95000, budget: 95000,
spent: 68400, spent: 68400,
margin: 0.20, margin: 0.20,
commissionType: 'flat',
commissionRate: 9500,
commission: 9500, commission: 9500,
additionalExpenses: 5200, additionalExpenses: 5200,
startDate: '2025-12-08', startDate: '2025-12-08',
@@ -2707,6 +2729,8 @@ const MOCK_PROJECTS = [
budget: 58000, budget: 58000,
spent: 22600, spent: 22600,
margin: 0.32, margin: 0.32,
commissionType: 'percent_gross',
commissionRate: 10,
commission: 5800, commission: 5800,
additionalExpenses: 1500, additionalExpenses: 1500,
startDate: '2026-01-13', startDate: '2026-01-13',
+160 -31
View File
@@ -121,6 +121,16 @@ function seedPaymentsMock(projectId) {
const PAYMENTS_PER_PAGE = 5; const PAYMENTS_PER_PAGE = 5;
const COMMISSION_TYPES = [
{ value: 'flat', label: 'Flat Amount', hint: 'Fixed dollar amount' },
{ value: 'percent_gross', label: '% of Gross', hint: 'Percentage of Total Received' },
{ value: 'percent_net', label: '% of Net', hint: 'Percentage of Gross Profit' },
{ value: 'custom', label: 'Custom / Manual', hint: 'Manually entered value' },
];
const formatCurrency = (amt) =>
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(Number(amt) || 0);
const OwnerProjectDetail = () => { const OwnerProjectDetail = () => {
const { projectId } = useParams(); const { projectId } = useParams();
const { user } = useAuth(); const { user } = useAuth();
@@ -136,6 +146,11 @@ const OwnerProjectDetail = () => {
const [paymentSort, setPaymentSort] = useState({ field: 'date', dir: 'desc' }); const [paymentSort, setPaymentSort] = useState({ field: 'date', dir: 'desc' });
const [paymentPage, setPaymentPage] = useState(0); const [paymentPage, setPaymentPage] = useState(0);
const [openTooltip, setOpenTooltip] = useState(null);
// ── Commission config state ─────────────────────────────────────────────
const [commissionConfig, setCommissionConfig] = useState(null);
// ── Docs state ──────────────────────────────────────────────────────────── // ── Docs state ────────────────────────────────────────────────────────────
const [docs, setDocs] = useState(() => seedDocsMock(projectId)); const [docs, setDocs] = useState(() => seedDocsMock(projectId));
const [viewDoc, setViewDoc] = useState(null); // doc object being viewed const [viewDoc, setViewDoc] = useState(null); // doc object being viewed
@@ -220,17 +235,53 @@ const OwnerProjectDetail = () => {
projects.find(p => p.id === projectId && p.ownerId === user?.id) projects.find(p => p.id === projectId && p.ownerId === user?.id)
, [projects, projectId, user]); , [projects, projectId, user]);
const activeCommissionConfig = useMemo(() => {
if (commissionConfig) return commissionConfig;
if (!project) return { type: 'flat', rate: 0 };
return {
type: project.commissionType || 'flat',
rate: Number(project.commissionRate) || 0,
};
}, [commissionConfig, project]);
const profitMetrics = useMemo(() => { const profitMetrics = useMemo(() => {
if (!project) return { totalCosts: 0, commission: 0, additionalExp: 0, grossProfit: 0, netProfit: 0, grossMargin: 0, netMargin: 0 }; if (!project) return { totalCosts: 0, commission: 0, commissionFormula: '', additionalExp: 0, grossProfit: 0, netProfit: 0, grossMargin: 0, netMargin: 0 };
const totalCosts = Number(project.actualCost ?? project.spent) || 0; const totalCosts = Number(project.actualCost ?? project.spent) || 0;
const commission = Number(project.commission) || 0;
const additionalExp = Number(project.additionalExpenses) || 0; const additionalExp = Number(project.additionalExpenses) || 0;
const gross = totalReceived - totalCosts; const gross = totalReceived - totalCosts;
const { type, rate } = activeCommissionConfig;
const safeRate = Number(rate) || 0;
let commission = 0;
let commissionFormula = '';
switch (type) {
case 'flat':
commission = safeRate;
commissionFormula = `Flat Amount: ${formatCurrency(safeRate)}`;
break;
case 'percent_gross':
commission = totalReceived * (safeRate / 100);
commissionFormula = `${safeRate}% of Total Received (${formatCurrency(totalReceived)})`;
break;
case 'percent_net':
commission = gross * (safeRate / 100);
commissionFormula = `${safeRate}% of Gross Profit (${formatCurrency(gross)})`;
break;
case 'custom':
commission = safeRate;
commissionFormula = `Manual Entry: ${formatCurrency(safeRate)}`;
break;
default:
commission = safeRate;
commissionFormula = `${formatCurrency(safeRate)}`;
}
commission = Number.isFinite(commission) ? commission : 0;
const net = gross - commission - additionalExp; const net = gross - commission - additionalExp;
const grossMargin = totalReceived > 0 ? (gross / totalReceived) * 100 : 0; const grossMargin = totalReceived > 0 ? (gross / totalReceived) * 100 : 0;
const netMargin = totalReceived > 0 ? (net / totalReceived) * 100 : 0; const netMargin = totalReceived > 0 ? (net / totalReceived) * 100 : 0;
return { totalCosts, commission, additionalExp, grossProfit: gross, netProfit: net, grossMargin, netMargin }; return { totalCosts, commission, commissionFormula, additionalExp, grossProfit: gross, netProfit: net, grossMargin, netMargin };
}, [project, totalReceived]); }, [project, totalReceived, activeCommissionConfig]);
if (!project) { if (!project) {
return ( return (
@@ -252,9 +303,6 @@ const OwnerProjectDetail = () => {
const contractor = vendors.find(v => v.id === project.contractorId) || null; const contractor = vendors.find(v => v.id === project.contractorId) || null;
const formatCurrency = (amt) =>
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(amt);
const getHealthColor = (s) => s >= 70 ? 'text-emerald-500' : s >= 40 ? 'text-amber-500' : 'text-red-500'; const getHealthColor = (s) => s >= 70 ? 'text-emerald-500' : s >= 40 ? 'text-amber-500' : 'text-red-500';
const getMilestoneColor = (status) => { const getMilestoneColor = (status) => {
@@ -916,9 +964,9 @@ const OwnerProjectDetail = () => {
{/* PAYMENTS TAB */} {/* PAYMENTS TAB */}
{activeTab === 'payments' && ( {activeTab === 'payments' && (
<div className="space-y-6 max-w-7xl mx-auto"> <div className="space-y-6 max-w-7xl mx-auto" onClick={() => openTooltip && setOpenTooltip(null)}>
{/* Financial Summary Row */} {/* Financial Summary Row */}
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4"> <div className="grid grid-cols-2 sm:grid-cols-3 gap-4">
<SpotlightCard className="p-4"> <SpotlightCard className="p-4">
<div className={`text-xl font-extrabold ${NEON_GREEN}`}>{formatCurrency(totalReceived)}</div> <div className={`text-xl font-extrabold ${NEON_GREEN}`}>{formatCurrency(totalReceived)}</div>
<div className="text-[10px] uppercase font-bold tracking-wider text-zinc-500 mt-1">Total Received</div> <div className="text-[10px] uppercase font-bold tracking-wider text-zinc-500 mt-1">Total Received</div>
@@ -927,16 +975,91 @@ const OwnerProjectDetail = () => {
<div className="text-xl font-extrabold text-zinc-900 dark:text-white">{formatCurrency(profitMetrics.totalCosts)}</div> <div className="text-xl font-extrabold text-zinc-900 dark:text-white">{formatCurrency(profitMetrics.totalCosts)}</div>
<div className="text-[10px] uppercase font-bold tracking-wider text-zinc-500 mt-1">Total Costs</div> <div className="text-[10px] uppercase font-bold tracking-wider text-zinc-500 mt-1">Total Costs</div>
</SpotlightCard> </SpotlightCard>
<SpotlightCard className="p-4">
<div className="text-xl font-extrabold text-zinc-900 dark:text-white">{formatCurrency(profitMetrics.commission)}</div>
<div className="text-[10px] uppercase font-bold tracking-wider text-zinc-500 mt-1">Commission</div>
</SpotlightCard>
<SpotlightCard className="p-4"> <SpotlightCard className="p-4">
<div className="text-xl font-extrabold text-zinc-900 dark:text-white">{formatCurrency(profitMetrics.additionalExp)}</div> <div className="text-xl font-extrabold text-zinc-900 dark:text-white">{formatCurrency(profitMetrics.additionalExp)}</div>
<div className="text-[10px] uppercase font-bold tracking-wider text-zinc-500 mt-1">Addl. Expenses</div> <div className="text-[10px] uppercase font-bold tracking-wider text-zinc-500 mt-1">Addl. Expenses</div>
</SpotlightCard> </SpotlightCard>
</div> </div>
{/* Commission Configuration Card */}
<NeoCard spotlightColor="rgba(253, 169, 19, 0.1)" innerClassName="!p-5">
<div className="flex items-start justify-between mb-4">
<div className="flex items-center gap-2">
<DollarSign size={18} className={NEON_GOLD} />
<h4 className="text-sm font-mono font-bold text-zinc-900 dark:text-white uppercase tracking-widest">Commission</h4>
</div>
<div className="relative">
<button type="button" onClick={(e) => { e.stopPropagation(); setOpenTooltip(prev => prev === 'commission' ? null : 'commission'); }} className="p-1 rounded-lg hover:bg-zinc-100 dark:hover:bg-white/10 transition-colors">
<Info size={14} className="text-zinc-400 dark:text-zinc-500" />
</button>
{openTooltip === 'commission' && (
<div className="absolute right-0 top-2 z-30 w-72 p-3 rounded-xl bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-white/10 shadow-xl text-xs text-zinc-600 dark:text-zinc-300">
<p className="font-bold text-zinc-900 dark:text-white mb-2">Commission Types</p>
<div className="space-y-1.5">
<p><span className="font-bold text-amber-600 dark:text-amber-400">Flat:</span> Fixed dollar amount</p>
<p><span className="font-bold text-amber-600 dark:text-amber-400">% of Gross:</span> Total Received x %</p>
<p><span className="font-bold text-amber-600 dark:text-amber-400">% of Net:</span> Gross Profit x %</p>
<p><span className="font-bold text-amber-600 dark:text-amber-400">Custom:</span> Manual dollar entry</p>
</div>
</div>
)}
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-12 gap-4 items-end">
{/* Type Selector */}
<div className="sm:col-span-4">
<label className="text-[10px] font-bold uppercase tracking-wider text-zinc-500 dark:text-zinc-400 block mb-1.5">Type</label>
<select
value={activeCommissionConfig.type}
onChange={e => setCommissionConfig(prev => ({ ...(prev || activeCommissionConfig), type: e.target.value, rate: '' }))}
className="w-full bg-zinc-50 dark:bg-[#18181b] border border-zinc-200 dark:border-white/10 rounded-xl px-4 py-2.5 text-sm text-zinc-900 dark:text-white outline-none focus:border-amber-500 dark:focus:border-amber-500 focus:ring-1 focus:ring-amber-500/30 transition-all"
>
{COMMISSION_TYPES.map(ct => (
<option key={ct.value} value={ct.value}>{ct.label}</option>
))}
</select>
</div>
{/* Rate / Value Input */}
<div className="sm:col-span-4">
<label className="text-[10px] font-bold uppercase tracking-wider text-zinc-500 dark:text-zinc-400 block mb-1.5">
{activeCommissionConfig.type === 'percent_gross' || activeCommissionConfig.type === 'percent_net' ? 'Rate (%)' : 'Amount ($)'}
</label>
<div className="relative">
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-sm text-zinc-400 dark:text-zinc-500 pointer-events-none">
{activeCommissionConfig.type === 'percent_gross' || activeCommissionConfig.type === 'percent_net' ? '%' : '$'}
</span>
<input
type="number"
step="any"
min="0"
value={activeCommissionConfig.rate}
onChange={e => setCommissionConfig(prev => ({ ...(prev || activeCommissionConfig), type: activeCommissionConfig.type, rate: e.target.value }))}
placeholder={activeCommissionConfig.type === 'percent_gross' || activeCommissionConfig.type === 'percent_net' ? 'e.g. 10' : 'e.g. 5000'}
className="w-full bg-zinc-50 dark:bg-[#18181b] border border-zinc-200 dark:border-white/10 rounded-xl pl-8 pr-4 py-2.5 text-sm text-zinc-900 dark:text-white placeholder-zinc-400 dark:placeholder-zinc-600 outline-none focus:border-amber-500 dark:focus:border-amber-500 focus:ring-1 focus:ring-amber-500/30 transition-all"
/>
</div>
</div>
{/* Calculated Result */}
<div className="sm:col-span-4">
<label className="text-[10px] font-bold uppercase tracking-wider text-zinc-500 dark:text-zinc-400 block mb-1.5">Calculated Commission</label>
<div className="bg-zinc-100 dark:bg-black/40 border border-zinc-200 dark:border-white/5 rounded-xl px-4 py-2.5 flex items-center justify-between">
<span className="text-lg font-black font-mono text-amber-600 dark:text-[#fda913]">{formatCurrency(profitMetrics.commission)}</span>
</div>
</div>
</div>
{/* Live Formula Preview */}
<div className="mt-3 px-3 py-2 bg-zinc-50 dark:bg-black/30 rounded-lg border border-zinc-100 dark:border-white/5">
<p className="text-[11px] font-mono text-zinc-500 dark:text-zinc-400">
<span className="text-amber-600 dark:text-amber-500 font-bold">Formula: </span>
{profitMetrics.commissionFormula}
</p>
</div>
</NeoCard>
{/* Profit Summary Cards */} {/* Profit Summary Cards */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{/* Gross Profit */} {/* Gross Profit */}
@@ -949,16 +1072,19 @@ const OwnerProjectDetail = () => {
<TrendingUp size={18} className={profitMetrics.grossProfit >= 0 ? NEON_GREEN : NEON_RED} /> <TrendingUp size={18} className={profitMetrics.grossProfit >= 0 ? NEON_GREEN : NEON_RED} />
<h4 className="text-xs font-mono font-bold text-zinc-500 dark:text-zinc-400 uppercase tracking-widest">Gross Profit</h4> <h4 className="text-xs font-mono font-bold text-zinc-500 dark:text-zinc-400 uppercase tracking-widest">Gross Profit</h4>
</div> </div>
<div className="relative group"> <div className="relative">
<Info size={14} className="text-zinc-400 dark:text-zinc-500 cursor-help" /> <button type="button" onClick={(e) => { e.stopPropagation(); setOpenTooltip(prev => prev === 'gross' ? null : 'gross'); }} className="p-1 rounded-lg hover:bg-zinc-100 dark:hover:bg-white/10 transition-colors">
<div className="absolute right-0 top-6 z-30 w-64 p-3 rounded-xl bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-white/10 shadow-xl text-xs text-zinc-600 dark:text-zinc-300 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all pointer-events-none"> <Info size={14} className="text-zinc-400 dark:text-zinc-500" />
<p className="font-bold text-zinc-900 dark:text-white mb-1">Gross Profit Formula</p> </button>
<p className="font-mono text-[11px]">Total Received Total Actual Costs</p> {openTooltip === 'gross' && (
<div className="mt-2 pt-2 border-t border-zinc-100 dark:border-white/5 space-y-1"> <div className="absolute right-0 top-2 z-30 w-64 p-3 rounded-xl bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-white/10 shadow-xl text-xs text-zinc-600 dark:text-zinc-300">
<p>{formatCurrency(totalReceived)} {formatCurrency(profitMetrics.totalCosts)}</p> <p className="font-bold text-zinc-900 dark:text-white mb-1">Gross Profit Formula</p>
<p className="font-bold">= {formatCurrency(profitMetrics.grossProfit)}</p> <p className="font-mono text-[11px]">Total Received Total Actual Costs</p>
<div className="mt-2 pt-2 border-t border-zinc-100 dark:border-white/5 space-y-1">
<p>{formatCurrency(totalReceived)} {formatCurrency(profitMetrics.totalCosts)} = {formatCurrency(profitMetrics.grossProfit)}</p>
</div>
</div> </div>
</div> )}
</div> </div>
</div> </div>
<div className={`text-3xl sm:text-4xl font-black font-mono tracking-tight ${profitMetrics.grossProfit >= 0 ? NEON_GREEN : NEON_RED}`}> <div className={`text-3xl sm:text-4xl font-black font-mono tracking-tight ${profitMetrics.grossProfit >= 0 ? NEON_GREEN : NEON_RED}`}>
@@ -985,16 +1111,19 @@ const OwnerProjectDetail = () => {
<DollarSign size={18} className={profitMetrics.netProfit >= 0 ? NEON_GREEN : NEON_RED} /> <DollarSign size={18} className={profitMetrics.netProfit >= 0 ? NEON_GREEN : NEON_RED} />
<h4 className="text-xs font-mono font-bold text-zinc-500 dark:text-zinc-400 uppercase tracking-widest">Net Profit</h4> <h4 className="text-xs font-mono font-bold text-zinc-500 dark:text-zinc-400 uppercase tracking-widest">Net Profit</h4>
</div> </div>
<div className="relative group"> <div className="relative">
<Info size={14} className="text-zinc-400 dark:text-zinc-500 cursor-help" /> <button type="button" onClick={(e) => { e.stopPropagation(); setOpenTooltip(prev => prev === 'net' ? null : 'net'); }} className="p-1 rounded-lg hover:bg-zinc-100 dark:hover:bg-white/10 transition-colors">
<div className="absolute right-0 top-6 z-50 w-64 p-3 rounded-xl bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-white/10 shadow-xl text-xs text-zinc-600 dark:text-zinc-300 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all pointer-events-none"> <Info size={14} className="text-zinc-400 dark:text-zinc-500" />
<p className="font-bold text-zinc-900 dark:text-white mb-1">Net Profit Formula</p> </button>
<p className="font-mono text-[11px]">Gross Profit Commission Addl. Expenses</p> {openTooltip === 'net' && (
<div className="mt-2 pt-2 border-t border-zinc-100 dark:border-white/5 space-y-1"> <div className="absolute right-0 top-2 z-30 w-72 p-3 rounded-xl bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-white/10 shadow-xl text-xs text-zinc-600 dark:text-zinc-300">
<p>{formatCurrency(profitMetrics.grossProfit)} {formatCurrency(profitMetrics.commission)} {formatCurrency(profitMetrics.additionalExp)}</p> <p className="font-bold text-zinc-900 dark:text-white mb-1">Net Profit Formula</p>
<p className="font-bold">= {formatCurrency(profitMetrics.netProfit)}</p> <p className="font-mono text-[11px]">Gross Profit Commission Addl. Expenses</p>
<div className="mt-2 pt-2 border-t border-zinc-100 dark:border-white/5 space-y-1">
<p>{formatCurrency(profitMetrics.grossProfit)} {formatCurrency(profitMetrics.commission)} {formatCurrency(profitMetrics.additionalExp)} = {formatCurrency(profitMetrics.netProfit)}</p>
</div>
</div> </div>
</div> )}
</div> </div>
</div> </div>
<div className={`text-3xl sm:text-4xl font-black font-mono tracking-tight ${profitMetrics.netProfit >= 0 ? NEON_GREEN : NEON_RED}`}> <div className={`text-3xl sm:text-4xl font-black font-mono tracking-tight ${profitMetrics.netProfit >= 0 ? NEON_GREEN : NEON_RED}`}>