feat: implement analytics endpoints (task 28)
- Created analytics service with summary, trends, comparison, and aggregated data methods - Implemented 5 analytics endpoints: summary, trends, comparison, aggregated, and CSV export - Added time series data with day/week/month interval support - Implemented period-over-period comparison metrics with percentage changes - Added CSV export functionality using json2csv - Updated frontend analytics service to unwrap API responses - Fixed chart components to work with new data structure (reportCount, eventCount, litterCollected) - Updated TypeScript types to match backend API structure - All endpoints tested and verified working Requirements satisfied: 5.1, 5.2, 5.3, 5.4, 5.5
This commit is contained in:
@@ -47,11 +47,14 @@ export function LitterTypeChart({ data, loading }: LitterTypeChartProps) {
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate total for percentages
|
||||
const total = data.reduce((sum, item) => sum + item.count, 0);
|
||||
|
||||
// Format data for the chart
|
||||
const chartData = data.map(item => ({
|
||||
name: LITTER_TYPE_LABELS[item.type] || item.type,
|
||||
value: item.count,
|
||||
percentage: item.percentage,
|
||||
percentage: total > 0 ? (item.count / total) * 100 : 0,
|
||||
}));
|
||||
|
||||
const renderCustomLabel = (entry: { name: string; percentage: number }) => {
|
||||
|
||||
@@ -43,12 +43,15 @@ export function QuantityChart({ data, loading }: QuantityChartProps) {
|
||||
);
|
||||
}
|
||||
|
||||
// Calculate total for percentages
|
||||
const total = data.reduce((sum, item) => sum + item.count, 0);
|
||||
|
||||
// Format data for the chart
|
||||
const chartData = data.map(item => ({
|
||||
name: QUANTITY_LABELS[item.quantity] || item.quantity,
|
||||
name: QUANTITY_LABELS[item.level] || item.level,
|
||||
count: item.count,
|
||||
percentage: item.percentage,
|
||||
quantity: item.quantity,
|
||||
percentage: total > 0 ? (item.count / total) * 100 : 0,
|
||||
quantity: item.level,
|
||||
}));
|
||||
|
||||
return (
|
||||
|
||||
@@ -57,17 +57,17 @@ export function TimeSeriesChart({ data, loading }: TimeSeriesChartProps) {
|
||||
/>
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="reports"
|
||||
dataKey="reportCount"
|
||||
stroke="#3b82f6"
|
||||
strokeWidth={2}
|
||||
name="Reports"
|
||||
dot={{ fill: '#3b82f6', r: 4 }}
|
||||
activeDot={{ r: 6 }}
|
||||
/>
|
||||
{data.some(d => d.events !== undefined) && (
|
||||
{data.some(d => d.eventCount !== undefined) && (
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="events"
|
||||
dataKey="eventCount"
|
||||
stroke="#10b981"
|
||||
strokeWidth={2}
|
||||
name="Events"
|
||||
@@ -75,6 +75,17 @@ export function TimeSeriesChart({ data, loading }: TimeSeriesChartProps) {
|
||||
activeDot={{ r: 6 }}
|
||||
/>
|
||||
)}
|
||||
{data.some(d => d.litterCollected > 0) && (
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="litterCollected"
|
||||
stroke="#f59e0b"
|
||||
strokeWidth={2}
|
||||
name="Litter Collected (kg)"
|
||||
dot={{ fill: '#f59e0b', r: 4 }}
|
||||
activeDot={{ r: 6 }}
|
||||
/>
|
||||
)}
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user