Add Planned activities column to Exec Summary district table
Split the Activities column into Activities (occurred) and Planned (future) to match the Executive Overview's District Performance chart. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -80,11 +80,12 @@ export default function ExecutiveSummary() {
|
|||||||
}, [accounts]);
|
}, [accounts]);
|
||||||
|
|
||||||
const districtPerformance = useMemo(() => {
|
const districtPerformance = useMemo(() => {
|
||||||
const districts = new Map<string, { pipeline: number; activities: number; accountsTouched: Set<string>; totalAccounts: number }>();
|
const todayStr = format(now, 'yyyy-MM-dd');
|
||||||
|
const districts = new Map<string, { pipeline: number; activities: number; planned: number; accountsTouched: Set<string>; totalAccounts: number }>();
|
||||||
|
|
||||||
accounts.forEach(a => {
|
accounts.forEach(a => {
|
||||||
const d = DISTRICT_SHORT[a.District_Name] || a.District_Name;
|
const d = DISTRICT_SHORT[a.District_Name] || a.District_Name;
|
||||||
if (!districts.has(d)) districts.set(d, { pipeline: 0, activities: 0, accountsTouched: new Set(), totalAccounts: 0 });
|
if (!districts.has(d)) districts.set(d, { pipeline: 0, activities: 0, planned: 0, accountsTouched: new Set(), totalAccounts: 0 });
|
||||||
const entry = districts.get(d)!;
|
const entry = districts.get(d)!;
|
||||||
entry.totalAccounts++;
|
entry.totalAccounts++;
|
||||||
if ((a.Touch_Count || 0) > 0) entry.accountsTouched.add(a.Account_Name);
|
if ((a.Touch_Count || 0) > 0) entry.accountsTouched.add(a.Account_Name);
|
||||||
@@ -92,14 +93,19 @@ export default function ExecutiveSummary() {
|
|||||||
|
|
||||||
pipeline.filter(p => p.Stage !== '06-Closed Won' && p.Stage !== '07-Closed Lost').forEach(p => {
|
pipeline.filter(p => p.Stage !== '06-Closed Won' && p.Stage !== '07-Closed Lost').forEach(p => {
|
||||||
const d = DISTRICT_SHORT[p.District_Name] || p.District_Name;
|
const d = DISTRICT_SHORT[p.District_Name] || p.District_Name;
|
||||||
if (!districts.has(d)) districts.set(d, { pipeline: 0, activities: 0, accountsTouched: new Set(), totalAccounts: 0 });
|
if (!districts.has(d)) districts.set(d, { pipeline: 0, activities: 0, planned: 0, accountsTouched: new Set(), totalAccounts: 0 });
|
||||||
districts.get(d)!.pipeline += p.Amount_USD;
|
districts.get(d)!.pipeline += p.Amount_USD;
|
||||||
});
|
});
|
||||||
|
|
||||||
activities.forEach(a => {
|
activities.forEach(a => {
|
||||||
const d = DISTRICT_SHORT[a.District_Name] || a.District_Name;
|
const d = DISTRICT_SHORT[a.District_Name] || a.District_Name;
|
||||||
if (!districts.has(d)) districts.set(d, { pipeline: 0, activities: 0, accountsTouched: new Set(), totalAccounts: 0 });
|
if (!districts.has(d)) districts.set(d, { pipeline: 0, activities: 0, planned: 0, accountsTouched: new Set(), totalAccounts: 0 });
|
||||||
districts.get(d)!.activities++;
|
const entry = districts.get(d)!;
|
||||||
|
if (a.Status === 'Planned' || a.Activity_Date > todayStr) {
|
||||||
|
entry.planned++;
|
||||||
|
} else {
|
||||||
|
entry.activities++;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Array.from(districts.entries())
|
return Array.from(districts.entries())
|
||||||
@@ -107,11 +113,12 @@ export default function ExecutiveSummary() {
|
|||||||
name,
|
name,
|
||||||
pipeline: data.pipeline,
|
pipeline: data.pipeline,
|
||||||
activities: data.activities,
|
activities: data.activities,
|
||||||
|
planned: data.planned,
|
||||||
accountsTouched: data.accountsTouched.size,
|
accountsTouched: data.accountsTouched.size,
|
||||||
totalAccounts: data.totalAccounts,
|
totalAccounts: data.totalAccounts,
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => b.pipeline - a.pipeline);
|
.sort((a, b) => b.pipeline - a.pipeline);
|
||||||
}, [pipeline, accounts, activities]);
|
}, [pipeline, accounts, activities, now]);
|
||||||
|
|
||||||
const keyWins = useMemo(() => {
|
const keyWins = useMemo(() => {
|
||||||
return pipeline
|
return pipeline
|
||||||
@@ -290,6 +297,7 @@ export default function ExecutiveSummary() {
|
|||||||
<th className="text-left py-1.5 font-medium text-gray-600 text-xs">District</th>
|
<th className="text-left py-1.5 font-medium text-gray-600 text-xs">District</th>
|
||||||
<th className="text-right py-1.5 font-medium text-gray-600 text-xs">Pipeline</th>
|
<th className="text-right py-1.5 font-medium text-gray-600 text-xs">Pipeline</th>
|
||||||
<th className="text-right py-1.5 font-medium text-gray-600 text-xs">Activities</th>
|
<th className="text-right py-1.5 font-medium text-gray-600 text-xs">Activities</th>
|
||||||
|
<th className="text-right py-1.5 font-medium text-gray-600 text-xs">Planned</th>
|
||||||
<th className="text-right py-1.5 font-medium text-gray-600 text-xs">Touched</th>
|
<th className="text-right py-1.5 font-medium text-gray-600 text-xs">Touched</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -299,6 +307,7 @@ export default function ExecutiveSummary() {
|
|||||||
<td className="py-1.5 font-medium text-gray-700">{d.name}</td>
|
<td className="py-1.5 font-medium text-gray-700">{d.name}</td>
|
||||||
<td className="py-1.5 text-right text-gray-700">{formatCurrency(d.pipeline, true)}</td>
|
<td className="py-1.5 text-right text-gray-700">{formatCurrency(d.pipeline, true)}</td>
|
||||||
<td className="py-1.5 text-right text-gray-700">{d.activities}</td>
|
<td className="py-1.5 text-right text-gray-700">{d.activities}</td>
|
||||||
|
<td className="py-1.5 text-right text-gray-700">{d.planned}</td>
|
||||||
<td className="py-1.5 text-right text-gray-700">
|
<td className="py-1.5 text-right text-gray-700">
|
||||||
{d.accountsTouched}/{d.totalAccounts}
|
{d.accountsTouched}/{d.totalAccounts}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
Reference in New Issue
Block a user