feat(dashboard): show analytics+financial cards to owner; ground Top Sales leaderboard in real reps; fix en-US currency formatting
This commit is contained in:
@@ -144,3 +144,22 @@ export function financialOverview(projects = [], today) {
|
||||
}
|
||||
return { collected, outstandingAR, pendingPayouts, vendorSpend };
|
||||
}
|
||||
|
||||
// Top performers leaderboard — credits each project to its closer (canvasser/sales rep on the team),
|
||||
// ranked by sales (Σ contract value). Returns [{ id, name, deals, sales, commission }].
|
||||
export function repLeaderboard(projects = [], resolvePerson) {
|
||||
const by = {};
|
||||
for (const p of projects) {
|
||||
const members = p.teamMembers || [];
|
||||
const closer = members.find((t) => /Canvasser|Sales|Estimator/i.test(t.jobRole || ''))
|
||||
|| members.find((t) => /FIELD_AGENT|SALES/i.test(t.orgRole || ''));
|
||||
const id = closer?.userId || p.salesRepId;
|
||||
if (!id) continue;
|
||||
const name = closer?.name || resolvePerson?.(id)?.name || id;
|
||||
by[id] = by[id] || { id, name, deals: 0, sales: 0, commission: 0 };
|
||||
by[id].deals += 1;
|
||||
by[id].sales += Number(p.approvedBudget ?? p.budget ?? 0);
|
||||
by[id].commission += Number(p.commission || 0);
|
||||
}
|
||||
return Object.values(by).sort((a, b) => b.sales - a.sales);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user