+
setSelectedAccount(null)} className="flex items-center gap-1.5 text-xs text-brand-azure hover:text-brand-navy mb-4 transition">
+
+ Back to accounts
+
+
+ {/* Account Header */}
+
+
+
+
{selectedAccount.Account_Name}
+
+ {selectedAccount.Tier || 'N/A'}
+ {selectedAccount.AgentMinder_Status}
+ {selectedAccount.Priority} Priority
+ {DISTRICT_SHORT[selectedAccount.District_Name]}
+
+
+
+ {selectedAccount.Current_ARR_USD != null && selectedAccount.Current_ARR_USD > 0 && (
+
+
Current ARR
+
{formatCurrency(selectedAccount.Current_ARR_USD, true)}
+
+ )}
+
+
+
+ {/* Suggested Priority */}
+ {suggestion.level !== selectedAccount.Priority && (
+
+
+
+
+ Suggested: {suggestion.level} Priority
+
+
— {suggestion.reason}
+
+
+ )}
+
+
+
+
Touches
+
{selectedAccount.Touch_Count || 0}
+
+
+
First Touched
+
{selectedAccount.Date_First_Touched || '—'}
+
+
+
Last Touched
+
{selectedAccount.Date_Last_Touched || '—'}
+
+
+
MAP in Place
+
{selectedAccount.MAP_In_Place_YN === 'Y' ? 'Yes' : 'No'}
+
+
+
+
+
+
Next Renewal
+
{selectedAccount.Next_Renewal_Date || '—'}
+
+
+
Renewal EAR
+
{selectedAccount.Next_Renewal_EAR ? formatCurrency(selectedAccount.Next_Renewal_EAR, true) : '—'}
+
+
+
Anchor Contract
+
{selectedAccount.Anchor_Contract_Date || '—'}
+
+
+
Anchor EAR
+
{selectedAccount.Anchor_Contract_EAR ? formatCurrency(selectedAccount.Anchor_Contract_EAR, true) : '—'}
+
+
+
+ {(selectedAccount.AD || selectedAccount.IMS_BA || selectedAccount.Area_Sales_Leader || selectedAccount.DM) && (
+
+ {selectedAccount.Area_Sales_Leader && (
+
+
Area Sales Leader
+
{selectedAccount.Area_Sales_Leader}
+
+ )}
+ {selectedAccount.DM && (
+
+
DM
+
{selectedAccount.DM}
+
+ )}
+ {selectedAccount.AD && (
+
+
AD
+
{selectedAccount.AD}
+
+ )}
+ {selectedAccount.IMS_BA && (
+
+
IMS BA
+
{selectedAccount.IMS_BA}
+
+ )}
+
+ )}
+
+
+
+ {/* Pipeline Section */}
+
+
Pipeline ({accountPipeline.length} opportunities)
+ {accountPipeline.length === 0 ? (
+
No pipeline opportunities
+ ) : (
+
+ {accountPipeline.map(opp => (
+
+
+ {formatCurrency(opp.Amount_USD, true)}
+ {opp.Stage}
+
+
+ {opp.Forecast_Category}
+ {opp.Probability_Pct}% prob
+ {opp.Expected_Close_Date && Close: {format(parseISO(opp.Expected_Close_Date), 'MMM d')} }
+
+ {opp.Next_Step &&
{opp.Next_Step}
}
+
+ ))}
+
+ )}
+
+
+ {/* Activity Timeline */}
+
+
Activity Timeline ({accountActivities.length} activities)
+ {accountActivities.length === 0 ? (
+
No activities logged
+ ) : (
+
+
+
+ {accountActivities.slice(0, 20).map((a, i) => (
+
+
+
+
+ {a.Activity_Type}
+ {format(parseISO(a.Activity_Date), 'MMM d, yyyy')}
+
+ {a.Contact_Name &&
with {a.Contact_Name}
}
+ {a.Notes &&
{a.Notes}
}
+
+
+ ))}
+
+
+ )}
+
+
+
+ {/* Implementation Status */}
+ {accountTarget && (
+
+
Implementation Status
+
+
+
Stage
+
{accountTarget.Implementation_Stage}
+
+
+
Health
+
+
+
{accountTarget.Health_Status || '—'}
+
+
+
+
Go-Live Date
+
{accountTarget.Go_Live_Date || '—'}
+
+ {accountTarget.Notes && (
+
+
Notes
+
{accountTarget.Notes}
+
+ )}
+
+
+ )}
+
+ );
+ }
+
+ return (
+
+
+
+ {/* KPI Summary Cards */}
+
+
+ 0 ? `${Math.round((kpis.touched / kpis.numAccounts) * 100)}%` : '0%'} color={kpis.touched > 0 ? 'green' : undefined} />
+
+
+ 0 ? 'green' : undefined} />
+
+
+
+ {/* Summary Charts */}
+
+ {/* Chart 1: Priority Breakdown */}
+
+
+
+
+
+
+
+ [value, 'Accounts']} />
+
+ {priorityChartData.map(entry => (
+ |
+ ))}
+
+
+
+
+
+ {priorityChartData.map(d => (
+
+
+
+ {d.value}
+ {filteredAccounts.length > 0 ? `${Math.round((d.value / filteredAccounts.length) * 100)}%` : '0%'}
+
+
+ ))}
+
+
+
+
+ {/* Chart 2: Activity Heatmap */}
+
+
+
+ {Array.from({ length: Math.max(...heatmapData.map(d => d.week), 0) + 1 }, (_, weekIdx) => (
+
+ {Array.from({ length: 7 }, (_, dayIdx) => {
+ const cell = heatmapData.find(d => d.week === weekIdx && d.day === dayIdx);
+ const intensity = cell ? cell.count / maxHeatVal : 0;
+ return (
+
+ );
+ })}
+
+ ))}
+
+
+
Less
+ {[0, 0.25, 0.5, 0.75, 1].map(i => (
+
+ ))}
+
More
+
+
+
+
+
+ {/* Search & Filters */}
+
+ setSearch(e.target.value)}
+ className="text-xs border border-card-border rounded-lg px-3 py-2 w-56 focus:outline-none focus:ring-2 focus:ring-brand-azure/30"
+ />
+ {['Tier 1', 'Tier 2', 'Tier 3', 'Tier 4'].map(t => (
+ setTierFilter(tierFilter === t ? null : t)}
+ className={`px-3 py-1.5 rounded-lg text-xs font-medium transition ${tierFilter === t ? 'text-white' : 'bg-gray-100 text-muted hover:bg-gray-200'}`}
+ style={tierFilter === t ? { backgroundColor: TIER_COLORS[t] } : undefined}
+ >{t}
+ ))}
+ {Array.from(new Set(accounts.map(a => a.AgentMinder_Status))).sort().map(s => (
+ setStatusFilter(statusFilter === s ? null : s)}
+ className={`px-3 py-1.5 rounded-lg text-xs font-medium transition ${statusFilter === s ? 'text-white' : 'bg-gray-100 text-muted hover:bg-gray-200'}`}
+ style={statusFilter === s ? { backgroundColor: STATUS_COLORS[s] || CHART_COLORS.navy } : undefined}
+ >{s}
+ ))}
+
+
+ {/* Priority filter pills */}
+
+ {['High', 'Medium', 'Low'].map(p => (
+ setPriorityFilter(priorityFilter === p ? null : p)}
+ className={`px-3 py-1.5 rounded-lg text-xs font-medium transition ${priorityFilter === p ? 'text-white' : 'bg-gray-100 text-muted hover:bg-gray-200'}`}
+ style={priorityFilter === p ? { backgroundColor: PRIORITY_COLORS[p] } : undefined}
+ >{p} Priority
+ ))}
+
+
+ {/* District, AD, IMS BA, Renewal dropdowns */}
+
+ setDistrictFilter(e.target.value || null)}
+ className="text-xs border border-card-border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-brand-azure/30 bg-white"
+ >
+ All Districts
+ {Array.from(new Set(accounts.map(a => a.District_Name))).sort().map(d => (
+ {DISTRICT_SHORT[d] || d}
+ ))}
+
+ {adValues.length > 0 && (
+ setAdFilter(e.target.value || null)}
+ className="text-xs border border-card-border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-brand-azure/30 bg-white"
+ >
+ All ADs
+ {adValues.map(v => {v} )}
+
+ )}
+ {imsbaValues.length > 0 && (
+ setImsbaFilter(e.target.value || null)}
+ className="text-xs border border-card-border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-brand-azure/30 bg-white"
+ >
+ All IMS BAs
+ {imsbaValues.map(v => {v} )}
+
+ )}
+ setRenewalFilter(e.target.value)}
+ className="text-xs border border-card-border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-brand-azure/30 bg-white"
+ >
+ {RENEWAL_FILTER_OPTIONS.map(opt => (
+ {opt.label}
+ ))}
+
+ {hasFilters && (
+
+ Clear all
+
+ )}
+
+
+ {/* Account Cards Grid */}
+
+ {filteredAccounts.map(account => {
+ const stats = getAccountStats(account);
+ const suggestion = getSuggestedPriority(account);
+ const mismatch = suggestion.level !== account.Priority;
+ return (
+
setSelectedAccount(account)}
+ className="bg-card-bg rounded-xl border border-card-border p-4 cursor-pointer hover:shadow-md hover:border-brand-azure/30 transition-all"
+ >
+
+
{account.Account_Name}
+
+
{account.Tier || 'N/A'}
+
+
+
+
+
{account.Priority}
+
{account.AgentMinder_Status}
+
{DISTRICT_SHORT[account.District_Name]}
+ {account.AD &&
| {account.AD} }
+ {(account.Google_Drive_URL || account.Campaign_Artifacts_URL) && (
+
+ )}
+
+ {mismatch && (
+
+
+ Suggested: {suggestion.level}
+
+ )}
+
+
+
ARR
+
{account.Current_ARR_USD ? formatCurrency(account.Current_ARR_USD, true) : '—'}
+
+
+
Pipeline
+
{stats.pipelineTotal > 0 ? formatCurrency(stats.pipelineTotal, true) : '—'}
+
+
+
Next Renewal
+
{account.Next_Renewal_Date || '—'}
+
+
+
Renewal EAR
+
{account.Next_Renewal_EAR ? formatCurrency(account.Next_Renewal_EAR, true) : '—'}
+
+
+
+ );
+ })}
+
+
+ );
+}
diff --git a/src/app/(dashboard)/activity/page.tsx b/src/app/(dashboard)/activity/page.tsx
new file mode 100644
index 0000000..045f049
--- /dev/null
+++ b/src/app/(dashboard)/activity/page.tsx
@@ -0,0 +1,598 @@
+'use client';
+
+import { useData } from '@/lib/data-context';
+import { ChartCard } from '@/components/ui/ChartCard';
+import { PageHeader } from '@/components/ui/PageHeader';
+import { CHART_COLORS, CHART_PALETTE, DISTRICT_SHORT, formatPercent, formatCurrency, STATUS_COLORS, TIER_COLORS, STAGE_COLORS } from '@/lib/formatters';
+import { useMemo, useState } from 'react';
+import {
+ BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Legend,
+ PieChart, Pie, Cell,
+} from 'recharts';
+import { parseISO, format, startOfWeek, differenceInDays, eachDayOfInterval } from 'date-fns';
+import { ActivityRecord } from '@/types/data';
+
+const TYPE_COLORS: Record