Add District Performance chart and count planned activities as touched

Executive Overview now shows a District Performance bar chart with
Activities (occurred), Planned (future), and Accounts Touched per
district. Planned activities now count toward the account's touch
data so scheduling future engagement flips an account to "touched."

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-09-04 12:20:33 -04:00
parent 1435fb5efc
commit c8c867ff66
2 changed files with 39 additions and 3 deletions

View File

@@ -76,6 +76,28 @@ export default function ExecutiveOverview() {
return Array.from(districtMap.entries()).map(([name, data]) => ({ name, ...data }));
}, [accounts, allStatuses]);
const districtActivity = useMemo(() => {
const todayStr = new Date().toISOString().split('T')[0];
const districtMap = new Map<string, { occurred: number; planned: number; touchedAccounts: Set<string> }>();
activities.forEach(a => {
const d = DISTRICT_SHORT[a.District_Name] || a.District_Name;
if (!districtMap.has(d)) districtMap.set(d, { occurred: 0, planned: 0, touchedAccounts: new Set() });
const m = districtMap.get(d)!;
if (a.Status === 'Planned' || a.Activity_Date > todayStr) {
m.planned++;
} else {
m.occurred++;
}
m.touchedAccounts.add(a.Account_Name);
});
return Array.from(districtMap.entries()).map(([name, data]) => ({
name,
'Activities': data.occurred,
'Planned': data.planned,
'Accounts Touched': data.touchedAccounts.size,
}));
}, [activities]);
const pipelineByForecast = useMemo(() => {
const districtMap = new Map<string, Record<string, number>>();
pipeline.filter(p => p.Stage !== '06-Closed Won' && p.Stage !== '07-Closed Lost').forEach(p => {
@@ -170,6 +192,22 @@ export default function ExecutiveOverview() {
</ChartCard>
</div>
<div className="mb-4">
<ChartCard title="District Performance" subtitle="Activities completed vs. planned by district">
<ResponsiveContainer width="100%" height={260}>
<BarChart data={districtActivity} margin={{ left: 10, right: 10, top: 5, bottom: 5 }}>
<XAxis dataKey="name" tick={{ fontSize: 11, fill: '#64748B' }} />
<YAxis tick={{ fontSize: 11, fill: '#64748B' }} />
<Tooltip content={<CustomTooltip />} />
<Legend wrapperStyle={{ fontSize: 11 }} />
<Bar dataKey="Activities" fill={CHART_COLORS.azure} />
<Bar dataKey="Planned" fill={CHART_COLORS.aqua} />
<Bar dataKey="Accounts Touched" fill={CHART_COLORS.green} />
</BarChart>
</ResponsiveContainer>
</ChartCard>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 mb-4">
<ChartCard title="Campaign Funnel" subtitle="Conversion through the pipeline">
<div className="space-y-2">

View File

@@ -428,9 +428,7 @@ export function addActivity(record: {
Status: status,
});
if (!status || status !== 'Planned') {
updateLastTouched(record.Account_Name, record.Activity_Date);
}
}
export function updateActivityStatus(id: number, updates: { Status: string; Outcome?: string | null; Notes?: string | null }) {