fix(owner): replace native Team Management select with custom dark-mode-aware project picker

This commit is contained in:
Satyam Rastogi
2026-05-29 18:59:50 +05:30
parent 6a5b857de3
commit 94ddc1b030
2 changed files with 104 additions and 16 deletions
+43
View File
@@ -101,3 +101,46 @@ export function stormAttribution(kanbanLeads = [], projects = []) {
revenuePct: totalRevenue ? Math.round((stormRevenue / totalRevenue) * 100) : 0,
};
}
// Owner Financial-Overview metrics, each carrying the underlying line items so the dashboard
// cards can drill down to the real records. Pass `today` (ISO date) to flag payouts due soon.
// - collected: cash received from clients (paid paymentSchedule entries)
// - outstandingAR: client money still owed (unpaid paymentSchedule entries)
// - pendingPayouts: money owed to vendors (pending invoices); dueSoon = within 7 days of `today`
// - vendorSpend: cash paid out to vendors (paid invoices)
export function financialOverview(projects = [], today) {
const now = today ? new Date(today) : null;
const within7 = (d) => {
if (!now || !d) return false;
const diff = (new Date(d) - now) / 86400000;
return diff >= 0 && diff <= 7;
};
const collected = { total: 0, items: [] };
const outstandingAR = { total: 0, count: 0, items: [] };
const pendingPayouts = { total: 0, dueSoonCount: 0, dueSoonTotal: 0, items: [] };
const vendorSpend = { total: 0, items: [] };
for (const p of projects) {
const project = p.customerName || p.projectType || p.id;
for (const ps of p.paymentSchedule || []) {
if (ps.status === 'paid') {
collected.total += ps.amount || 0;
collected.items.push({ projectId: p.id, project, label: ps.milestone, amount: ps.amount || 0, date: ps.paidDate || ps.dueDate });
} else {
outstandingAR.total += ps.amount || 0;
outstandingAR.count += 1;
outstandingAR.items.push({ projectId: p.id, project, label: ps.milestone, amount: ps.amount || 0, dueDate: ps.dueDate });
}
}
for (const inv of p.invoices || []) {
if (inv.status === 'pending') {
pendingPayouts.total += inv.amount || 0;
pendingPayouts.items.push({ projectId: p.id, project, label: inv.submittedBy, amount: inv.amount || 0, dueDate: inv.dueDate });
if (within7(inv.dueDate)) { pendingPayouts.dueSoonCount += 1; pendingPayouts.dueSoonTotal += inv.amount || 0; }
} else if (inv.status === 'paid') {
vendorSpend.total += inv.amount || 0;
vendorSpend.items.push({ projectId: p.id, project, label: inv.submittedBy, amount: inv.amount || 0, date: inv.datePaid });
}
}
}
return { collected, outstandingAR, pendingPayouts, vendorSpend };
}