Backend (@backend-dev): - Add ReportService with PDF/CSV generation (reportlab, pandas) - Implement Report API endpoints (POST, GET, DELETE, download) - Add ReportRepository and schemas - Configure storage with auto-cleanup (30 days) - Rate limiting: 10 downloads/minute - Professional PDF templates with charts support Frontend (@frontend-dev): - Integrate Recharts for data visualization - Add CostBreakdown, TimeSeries, ComparisonBar charts - Implement scenario comparison page with multi-select - Add dark/light mode toggle with ThemeProvider - Create Reports page with generation form and list - Add new UI components: checkbox, dialog, tabs, label, skeleton - Implement useComparison and useReports hooks QA (@qa-engineer): - Setup Playwright E2E testing framework - Create 7 test spec files with 94 test cases - Add visual regression testing with baselines - Configure multi-browser testing (Chrome, Firefox, WebKit) - Add mobile responsive tests - Create test fixtures and helpers - Setup GitHub Actions CI workflow Documentation (@spec-architect): - Create detailed kanban-v0.4.0.md with 27 tasks - Update progress.md with v0.4.0 tracking - Create v0.4.0 planning prompt Features: ✅ PDF/CSV Report Generation ✅ Interactive Charts (Pie, Area, Bar) ✅ Scenario Comparison (2-4 scenarios) ✅ Dark/Light Mode Toggle ✅ E2E Test Suite (94 tests) Dependencies added: - Backend: reportlab, pandas, slowapi - Frontend: recharts, date-fns, @radix-ui/react-checkbox/dialog/tabs - Testing: @playwright/test 27 tasks completed, 100% v0.4.0 implementation
44 lines
1.2 KiB
TypeScript
44 lines
1.2 KiB
TypeScript
import { useMutation, useQuery } from '@tanstack/react-query';
|
|
import api from '@/lib/api';
|
|
import type { Scenario, MetricSummary } from '@/types/api';
|
|
|
|
const COMPARISON_KEY = 'comparison';
|
|
|
|
export interface ComparisonScenario {
|
|
scenario: Scenario;
|
|
summary: MetricSummary;
|
|
}
|
|
|
|
export interface ComparisonResult {
|
|
scenarios: ComparisonScenario[];
|
|
deltas: Record<string, { value: number; percentage: number }[]>;
|
|
}
|
|
|
|
export interface CompareRequest {
|
|
scenario_ids: string[];
|
|
metrics?: string[];
|
|
}
|
|
|
|
export function useCompareScenarios() {
|
|
return useMutation<ComparisonResult, Error, CompareRequest>({
|
|
mutationFn: async (data) => {
|
|
const response = await api.post('/scenarios/compare', data);
|
|
return response.data;
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useComparisonCache(scenarioIds: string[]) {
|
|
return useQuery<ComparisonResult>({
|
|
queryKey: [COMPARISON_KEY, scenarioIds.sort().join(',')],
|
|
queryFn: async () => {
|
|
const response = await api.post('/scenarios/compare', {
|
|
scenario_ids: scenarioIds,
|
|
});
|
|
return response.data;
|
|
},
|
|
enabled: scenarioIds.length >= 2 && scenarioIds.length <= 4,
|
|
staleTime: 5 * 60 * 1000, // 5 minutes cache
|
|
});
|
|
}
|