feat: add bar/pie and #/% toggles to district performance chart
All checks were successful
Deploy HiHala Dashboard / deploy (push) Successful in 7s
All checks were successful
Deploy HiHala Dashboard / deploy (push) Successful in 7s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -84,6 +84,8 @@ function Dashboard({ data, seasons, userRole, showDataLabels, setShowDataLabels,
|
||||
const [channelChartType, setChannelChartType] = useState<'bar' | 'pie'>('pie');
|
||||
const [channelDisplayMode, setChannelDisplayMode] = useState<'absolute' | 'percent'>('absolute');
|
||||
const [eventDisplayMode, setEventDisplayMode] = useState<'absolute' | 'percent'>('absolute');
|
||||
const [districtChartType, setDistrictChartType] = useState<'bar' | 'pie'>('bar');
|
||||
const [districtDisplayMode, setDistrictDisplayMode] = useState<'absolute' | 'percent'>('absolute');
|
||||
|
||||
const filteredData = useMemo(() => filterData(data, filters), [data, filters]);
|
||||
|
||||
@@ -290,6 +292,16 @@ function Dashboard({ data, seasons, userRole, showDataLabels, setShowDataLabels,
|
||||
};
|
||||
}, [seasonFilteredData, includeVAT]);
|
||||
|
||||
const districtChartData = useMemo(() => {
|
||||
if (districtDisplayMode === 'absolute') return districtData;
|
||||
const total = districtData.datasets[0].data.reduce((s: number, v: number) => s + v, 0);
|
||||
if (total === 0) return districtData;
|
||||
return {
|
||||
...districtData,
|
||||
datasets: [{ ...districtData.datasets[0], data: districtData.datasets[0].data.map((v: number) => parseFloat(((v / total) * 100).toFixed(1))) }]
|
||||
};
|
||||
}, [districtData, districtDisplayMode]);
|
||||
|
||||
// Quarterly YoY
|
||||
const quarterlyYoYData = useMemo(() => {
|
||||
const revenueField = includeVAT ? 'revenue_gross' : 'revenue_net';
|
||||
@@ -720,8 +732,36 @@ function Dashboard({ data, seasons, userRole, showDataLabels, setShowDataLabels,
|
||||
</div>
|
||||
|
||||
<div className="chart-card half-width">
|
||||
<ExportableChart filename="district-performance" title={t('dashboard.districtPerformance')} className="chart-container">
|
||||
<Bar data={districtData} options={{...baseOptions, indexAxis: 'y'}} />
|
||||
<ExportableChart
|
||||
filename="district-performance"
|
||||
title={t('dashboard.districtPerformance')}
|
||||
className="chart-container"
|
||||
controls={
|
||||
<div style={{ display: 'flex', gap: '6px' }}>
|
||||
<div className="toggle-switch">
|
||||
<button className={districtChartType === 'bar' ? 'active' : ''} onClick={() => setDistrictChartType('bar')}>{t('metrics.bar')}</button>
|
||||
<button className={districtChartType === 'pie' ? 'active' : ''} onClick={() => setDistrictChartType('pie')}>{t('metrics.pie')}</button>
|
||||
</div>
|
||||
<div className="toggle-switch">
|
||||
<button className={districtDisplayMode === 'absolute' ? 'active' : ''} onClick={() => setDistrictDisplayMode('absolute')}>#</button>
|
||||
<button className={districtDisplayMode === 'percent' ? 'active' : ''} onClick={() => setDistrictDisplayMode('percent')}>%</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{districtChartType === 'bar'
|
||||
? <Bar data={districtChartData} options={{...baseOptions, indexAxis: 'y'}} />
|
||||
: <Pie data={districtChartData} options={{
|
||||
...pieOptions,
|
||||
plugins: {
|
||||
...pieOptions.plugins,
|
||||
datalabels: districtDisplayMode === 'percent'
|
||||
? { display: true, color: '#fff', font: { size: 11, weight: 'bold' as const }, formatter: (v: number) => v > 3 ? v.toFixed(1) + '%' : '' }
|
||||
: { display: false },
|
||||
tooltip: { ...pieOptions.plugins.tooltip, callbacks: { label: (ctx: any) => districtDisplayMode === 'percent' ? ` ${ctx.parsed.toFixed(1)}%` : ` ${formatCurrency(ctx.parsed)}` } }
|
||||
}
|
||||
}} />
|
||||
}
|
||||
</ExportableChart>
|
||||
</div>
|
||||
|
||||
@@ -867,8 +907,30 @@ function Dashboard({ data, seasons, userRole, showDataLabels, setShowDataLabels,
|
||||
<div className="carousel-slide">
|
||||
<div className="chart-card">
|
||||
<h2>{t('dashboard.districtPerformance')}</h2>
|
||||
<div style={{ display: 'flex', gap: '6px', marginBottom: '8px' }}>
|
||||
<div className="toggle-switch">
|
||||
<button className={districtChartType === 'bar' ? 'active' : ''} onClick={() => setDistrictChartType('bar')}>{t('metrics.bar')}</button>
|
||||
<button className={districtChartType === 'pie' ? 'active' : ''} onClick={() => setDistrictChartType('pie')}>{t('metrics.pie')}</button>
|
||||
</div>
|
||||
<div className="toggle-switch">
|
||||
<button className={districtDisplayMode === 'absolute' ? 'active' : ''} onClick={() => setDistrictDisplayMode('absolute')}>#</button>
|
||||
<button className={districtDisplayMode === 'percent' ? 'active' : ''} onClick={() => setDistrictDisplayMode('percent')}>%</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="chart-container">
|
||||
<Bar data={districtData} options={{...baseOptions, indexAxis: 'y'}} />
|
||||
{districtChartType === 'bar'
|
||||
? <Bar data={districtChartData} options={{...baseOptions, indexAxis: 'y'}} />
|
||||
: <Pie data={districtChartData} options={{
|
||||
...pieOptions,
|
||||
plugins: {
|
||||
...pieOptions.plugins,
|
||||
datalabels: districtDisplayMode === 'percent'
|
||||
? { display: true, color: '#fff', font: { size: 11, weight: 'bold' as const }, formatter: (v: number) => v > 3 ? v.toFixed(1) + '%' : '' }
|
||||
: { display: false },
|
||||
tooltip: { ...pieOptions.plugins.tooltip, callbacks: { label: (ctx: any) => districtDisplayMode === 'percent' ? ` ${ctx.parsed.toFixed(1)}%` : ` ${formatCurrency(ctx.parsed)}` } }
|
||||
}
|
||||
}} />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user