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:
@@ -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">
|
||||
|
||||
@@ -428,10 +428,8 @@ 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 }) {
|
||||
const db = getDb();
|
||||
|
||||
Reference in New Issue
Block a user