'use client';
import {
Star,
TrendingUp,
TrendingDown,
Minus,
AlertTriangle,
CheckCircle,
Quote,
Zap,
Clock,
Target,
Users,
Trophy,
Megaphone,
AlertCircle,
Calendar,
DollarSign,
Shield,
Activity,
BarChart3,
} from 'lucide-react';
import type {
SynthesisV2,
ExecutiveSummary,
RiskScorecard,
RiskIndicator,
CriticalIssue,
StrengthToProtect,
ActionMatrixItem,
TrackingKPI,
} from './types';
interface BusinessReportProps {
synthesis: SynthesisV2;
}
/**
* The €60 Business Reputation Report - 6-Section Format
* A productized, high-value report for SMB owners.
*/
export function BusinessReport({ synthesis }: BusinessReportProps) {
const { executive_summary, risk_scorecard, critical_issues, strengths, action_matrix, tracking_kpis } = synthesis;
return (
{/* Report Header */}
{/* Section 1: Executive Summary */}
{/* Section 2: Risk Scorecard */}
{/* Section 3: Critical Issues */}
{critical_issues.length > 0 && (
)}
{/* Section 4: Strengths to Protect */}
{strengths.length > 0 && (
)}
{/* Section 5: Action Matrix */}
{action_matrix.length > 0 && (
)}
{/* Section 6: 90-Day Tracking */}
{tracking_kpis.length > 0 && (
)}
{/* Footer */}
);
}
// ═══════════════════════════════════════════════════════════════════════════
// Section 1: Executive Summary
// ═══════════════════════════════════════════════════════════════════════════
function ExecutiveSummarySection({ summary, reviewCount }: { summary: ExecutiveSummary; reviewCount: number }) {
const healthColor = summary.health_score >= 70 ? 'emerald' : summary.health_score >= 50 ? 'amber' : 'red';
return (
{/* Health Score Gauge */}
{summary.health_label}
{reviewCount.toLocaleString()} reviews analyzed
{/* Rating Display */}
{summary.current_rating.toFixed(1)}
{[1, 2, 3, 4, 5].map((star) => (
))}
{summary.rating_gap > 0 && (
→ {summary.potential_rating.toFixed(1)}★ potential
)}
{/* One-liner */}
{summary.one_liner}
{/* Key Insight */}
{summary.key_insight}
{/* Revenue at Risk + Momentum */}
{summary.estimated_revenue_at_risk} at risk
);
}
// ═══════════════════════════════════════════════════════════════════════════
// Section 2: Risk Scorecard
// ═══════════════════════════════════════════════════════════════════════════
function RiskScorecardSection({ scorecard }: { scorecard: RiskScorecard }) {
const riskColors = {
low: 'emerald',
medium: 'amber',
high: 'orange',
critical: 'red',
};
const riskColor = riskColors[scorecard.overall_risk] || 'amber';
return (
Risk Scorecard
Health indicators by area
{scorecard.overall_risk} Risk
{/* Risk Indicators Grid */}
{scorecard.indicators.map((indicator, i) => (
))}
{/* Immediate Attention */}
{scorecard.immediate_attention && (
Immediate Attention Required
{scorecard.immediate_attention}
)}
);
}
function RiskIndicatorCard({ indicator }: { indicator: RiskIndicator }) {
const colorMap = {
green: { bg: 'bg-emerald-50', border: 'border-emerald-200', text: 'text-emerald-700', bar: 'bg-emerald-500' },
yellow: { bg: 'bg-amber-50', border: 'border-amber-200', text: 'text-amber-700', bar: 'bg-amber-500' },
red: { bg: 'bg-red-50', border: 'border-red-200', text: 'text-red-700', bar: 'bg-red-500' },
};
const colors = colorMap[indicator.color] || colorMap.yellow;
const TrendIcon = indicator.trend === 'improving' ? TrendingUp : indicator.trend === 'declining' ? TrendingDown : Minus;
return (
{indicator.name}
{indicator.score}
/10
{indicator.complaint_count} complaints
);
}
// ═══════════════════════════════════════════════════════════════════════════
// Section 3: Critical Issues
// ═══════════════════════════════════════════════════════════════════════════
function CriticalIssuesSection({ issues }: { issues: CriticalIssue[] }) {
return (
Critical Issues
Top problems requiring immediate action
{issues.map((issue) => (
))}
);
}
function CriticalIssueCard({ issue }: { issue: CriticalIssue }) {
const effortColors = {
quick_win: 'bg-emerald-100 text-emerald-700',
moderate: 'bg-blue-100 text-blue-700',
strategic: 'bg-purple-100 text-purple-700',
};
return (
{/* Header */}
{issue.rank}
{issue.title}
{issue.urt_code} · {issue.complaint_count} complaints
{issue.revenue_impact}
{issue.effort.replace('_', ' ')} · {issue.timeline}
{/* Body */}
{/* Root Cause */}
Root Cause
{issue.root_cause}
{/* Evidence */}
{issue.evidence.length > 0 && (
Customer Evidence
{issue.evidence.slice(0, 2).map((quote, i) => (
))}
)}
{/* Solution */}
Recommended Solution
{issue.solution}
);
}
// ═══════════════════════════════════════════════════════════════════════════
// Section 4: Strengths to Protect
// ═══════════════════════════════════════════════════════════════════════════
function StrengthsSection({ strengths }: { strengths: StrengthToProtect[] }) {
return (
Protect Your Strengths
Competitive advantages to leverage
{strengths.map((strength, i) => (
))}
);
}
function StrengthCard({ strength }: { strength: StrengthToProtect }) {
return (
{/* Header */}
{strength.title}
{strength.mention_count} mentions
{strength.percentage.toFixed(0)}%
{/* Quotes */}
{strength.top_quotes.length > 0 && (
{strength.top_quotes.slice(0, 2).map((quote, i) => (
"{quote.slice(0, 100)}{quote.length > 100 ? '...' : ''}"
))}
)}
{/* Risk of Loss */}
{strength.risk_of_loss && (
)}
{/* Leverage Action */}
{strength.leverage_action && (
Leverage: {strength.leverage_action}
)}
);
}
// ═══════════════════════════════════════════════════════════════════════════
// Section 5: Action Matrix
// ═══════════════════════════════════════════════════════════════════════════
function ActionMatrixSection({ actions }: { actions: ActionMatrixItem[] }) {
const quickWins = actions.filter(a => a.quadrant === 'quick_win');
const majorProjects = actions.filter(a => a.quadrant === 'major_project');
const others = actions.filter(a => !['quick_win', 'major_project'].includes(a.quadrant));
return (
{/* Header */}
Action Matrix
{actions.length} prioritized actions
{/* Quick Wins */}
{quickWins.length > 0 && (
}
iconBg="bg-amber-100 text-amber-600"
actions={quickWins}
/>
)}
{/* Major Projects */}
{majorProjects.length > 0 && (
}
iconBg="bg-blue-100 text-blue-600"
actions={majorProjects}
/>
)}
{/* Others */}
{others.length > 0 && (
}
iconBg="bg-slate-100 text-slate-600"
actions={others}
/>
)}
);
}
function ActionGroup({
title,
subtitle,
icon,
iconBg,
actions,
}: {
title: string;
subtitle: string;
icon: React.ReactNode;
iconBg: string;
actions: ActionMatrixItem[];
}) {
return (
{actions.map((action, i) => (
))}
);
}
function ActionCard({ action }: { action: ActionMatrixItem }) {
return (
{action.action}
{action.owner}
{action.deadline}
{action.expected_lift}
{action.success_metric && (
Success: {action.success_metric}
)}
);
}
// ═══════════════════════════════════════════════════════════════════════════
// Section 6: 90-Day Tracking
// ═══════════════════════════════════════════════════════════════════════════
function TrackingSection({ kpis }: { kpis: TrackingKPI[] }) {
return (
90-Day Tracking Framework
Monitor these KPIs monthly
| Metric |
Current |
30-Day |
60-Day |
90-Day |
{kpis.map((kpi, i) => (
|
{kpi.metric}
{kpi.measurement}
|
{kpi.current_value}
|
{kpi.target_30_day}
|
{kpi.target_60_day}
|
{kpi.target_90_day}
|
))}
);
}
// ═══════════════════════════════════════════════════════════════════════════
// Shared Components
// ═══════════════════════════════════════════════════════════════════════════
function MomentumBadge({ momentum, detail }: { momentum: string; detail: string }) {
const config = {
improving: {
icon: ,
bg: 'bg-emerald-500/20',
text: 'text-emerald-300',
label: 'Improving',
},
declining: {
icon: ,
bg: 'bg-red-500/20',
text: 'text-red-300',
label: 'Declining',
},
stable: {
icon: ,
bg: 'bg-slate-500/20',
text: 'text-slate-300',
label: 'Stable',
},
};
const c = config[momentum as keyof typeof config] || config.stable;
return (
{c.icon}
{c.label}
{detail && · {detail}}
);
}