feat(frontend): Add BusinessReport component for 6-section €60 report
- Create BusinessReport.tsx with 6 sections: 1. Executive Summary (health score, rating, momentum) 2. Risk Scorecard (indicators with colors/trends) 3. Critical Issues (evidence, solutions, timelines) 4. Strengths to Protect (quotes, leverage actions) 5. Action Matrix (effort/impact quadrants) 6. 90-Day Tracking (KPI targets table) - Update types.ts with new interfaces: - SynthesisV2 for new report format - LegacySynthesis for backwards compatibility - Type guard isSynthesisV2() for runtime detection - Update ReportTab to auto-detect synthesis version - Update AnalystReport, ReviewIQDashboard, StoryView for backwards compatibility with union type Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
101
web/components/reviewiq/ReportTab.tsx
Normal file
101
web/components/reviewiq/ReportTab.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
'use client';
|
||||
|
||||
import { Loader2, FileWarning } from 'lucide-react';
|
||||
import { useReviewIQAnalytics } from '@/hooks/useReviewIQAnalytics';
|
||||
import { AnalystReport } from './AnalystReport';
|
||||
import { BusinessReport } from './BusinessReport';
|
||||
import { isSynthesisV2 } from './types';
|
||||
import type { ReviewIQFilters, LegacySynthesis, SynthesisV2 } from './types';
|
||||
|
||||
interface ReportTabProps {
|
||||
jobId?: string;
|
||||
businessId?: string;
|
||||
}
|
||||
|
||||
// Default filters for Report view - uses 'all' time range for comprehensive analysis
|
||||
const defaultFilters: ReviewIQFilters = {
|
||||
timeRange: 'all',
|
||||
sentiment: [],
|
||||
urtDomain: null,
|
||||
intensity: [],
|
||||
brushRange: null,
|
||||
};
|
||||
|
||||
/**
|
||||
* Report Tab - Wraps report components with data fetching.
|
||||
* Automatically detects report version and renders appropriate component.
|
||||
*/
|
||||
export function ReportTab({ jobId, businessId }: ReportTabProps) {
|
||||
const { data, loading, error } = useReviewIQAnalytics({
|
||||
jobId,
|
||||
businessId,
|
||||
filters: defaultFilters,
|
||||
});
|
||||
|
||||
// Loading state
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-[400px]">
|
||||
<Loader2 className="w-8 h-8 animate-spin text-indigo-600" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Error state
|
||||
if (error) {
|
||||
return (
|
||||
<div className="bg-red-50 border border-red-200 rounded-lg p-6 text-center">
|
||||
<p className="text-red-700">{error}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// No data state
|
||||
if (!data) {
|
||||
return (
|
||||
<div className="bg-slate-50 border border-slate-200 rounded-lg p-6 text-center">
|
||||
<p className="text-slate-600">No data available for this report.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// No synthesis - AI report not generated yet
|
||||
if (!data.synthesis) {
|
||||
return (
|
||||
<div className="max-w-2xl mx-auto mt-12">
|
||||
<div className="bg-amber-50 border border-amber-200 rounded-2xl p-8 text-center">
|
||||
<FileWarning className="w-12 h-12 text-amber-500 mx-auto mb-4" />
|
||||
<h3 className="text-xl font-semibold text-amber-900 mb-2">
|
||||
AI Report Not Generated Yet
|
||||
</h3>
|
||||
<p className="text-amber-700 mb-4">
|
||||
The AI-powered analyst report hasn't been generated for this dataset.
|
||||
Run the pipeline with the "synthesize" stage to generate the report.
|
||||
</p>
|
||||
<div className="text-sm text-amber-600 bg-amber-100 rounded-lg p-3 font-mono">
|
||||
Stage 5: Synthesize → Generates narratives, actions & insights
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Render the appropriate report based on synthesis version
|
||||
if (isSynthesisV2(data.synthesis)) {
|
||||
// New 6-section Business Report (v2.0)
|
||||
return <BusinessReport synthesis={data.synthesis} />;
|
||||
}
|
||||
|
||||
// Legacy Analyst Report (v1.x)
|
||||
return (
|
||||
<AnalystReport
|
||||
synthesis={data.synthesis}
|
||||
overview={data.overview}
|
||||
sentiment={data.sentiment.distribution}
|
||||
domains={data.urt.domains}
|
||||
timeline={data.timeline}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default ReportTab;
|
||||
Reference in New Issue
Block a user