/** * AmaniQuery v2 Response Display Component * * Displays structured JSON responses with persona-specific theming: * - wanjiku: Warm orange/green (Kenyan flag vibes) * - wakili: Navy blue + gold (legal professional) * - mwanahabari: Neutral grey + data visualization */ import React, { useState } from 'react'; import { ChevronDown, ChevronUp, ExternalLink, BookOpen, TrendingUp, Users } from 'lucide-react'; import { cn } from "@/lib/utils"; import { ThinkingProcess } from './ThinkingProcess'; import { FactCheckAlert } from './FactCheckAlert'; // ============================================================================ // TYPES // ============================================================================ export type QueryType = 'public_interest' | 'legal' | 'research'; export interface AmaniQueryResponse { query_type: QueryType; language_detected: string; response: { summary_card: { title: string; content: string; }; detailed_breakdown: { points: string[]; }; kenyan_context: { impact: string; related_topic: string | null; }; citations: Array<{ source: string; url: string; quote: string | null; }>; }; follow_up_suggestions: string[]; metadata?: { reasoning_path?: { query: string; thoughts: Array<{ step: number; action: string; observation: string; reasoning: string; duration_ms?: number; confidence?: number; }>; total_duration_ms: number; final_conclusion: string; }; quality_issues?: string[]; [key: string]: unknown; }; } interface AmaniQueryResponseProps { data: AmaniQueryResponse; className?: string; onFollowUpClick?: (suggestion: string) => void; } // ============================================================================ // THEME CONFIGURATION // ============================================================================ const PERSONA_THEMES = { public_interest: { name: 'wanjiku', classes: { container: 'bg-orange-50/50 dark:bg-orange-950/20', card: 'bg-white dark:bg-gray-900 border-orange-100 dark:border-orange-900/50', summaryGradient: 'from-orange-600 to-green-600', primaryText: 'text-orange-900 dark:text-orange-100', secondaryText: 'text-orange-700 dark:text-orange-300', accentBg: 'bg-orange-500', accentText: 'text-orange-600 dark:text-orange-400', border: 'border-orange-200 dark:border-orange-800', contextBorder: 'border-green-600 dark:border-green-500', iconColor: 'text-green-600 dark:text-green-500', buttonHover: 'hover:bg-orange-100 dark:hover:bg-orange-900/50' }, icon: '🇰🇪', summaryTitle: 'Kwa Ufupi', contextIcon: '🚌' // Matatu }, legal: { name: 'wakili', classes: { container: 'bg-indigo-50/50 dark:bg-indigo-950/20', card: 'bg-white dark:bg-gray-900 border-indigo-100 dark:border-indigo-900/50', summaryGradient: 'from-indigo-700 to-blue-900', primaryText: 'text-indigo-900 dark:text-indigo-100', secondaryText: 'text-indigo-700 dark:text-indigo-300', accentBg: 'bg-indigo-500', accentText: 'text-indigo-600 dark:text-indigo-400', border: 'border-indigo-200 dark:border-indigo-800', contextBorder: 'border-amber-400 dark:border-amber-500', iconColor: 'text-amber-500 dark:text-amber-400', buttonHover: 'hover:bg-indigo-100 dark:hover:bg-indigo-900/50' }, icon: '⚖️', summaryTitle: 'Legal Summary', contextIcon: '📜' }, research: { name: 'mwanahabari', classes: { container: 'bg-slate-50/50 dark:bg-slate-950/20', card: 'bg-white dark:bg-gray-900 border-slate-100 dark:border-slate-800', summaryGradient: 'from-slate-700 to-teal-700', primaryText: 'text-slate-900 dark:text-slate-100', secondaryText: 'text-slate-700 dark:text-slate-300', accentBg: 'bg-teal-500', accentText: 'text-teal-600 dark:text-teal-400', border: 'border-slate-200 dark:border-slate-700', contextBorder: 'border-teal-500 dark:border-teal-400', iconColor: 'text-teal-600 dark:text-teal-500', buttonHover: 'hover:bg-slate-100 dark:hover:bg-slate-800' }, icon: '📊', summaryTitle: 'The Bottom Line', contextIcon: '📈' } }; // ============================================================================ // KENYAN CONTEXT ICONS // ============================================================================ const KENYAN_CONTEXT_ICONS: Record = { 'transport': '🚌', // Matatu 'money': '💰', 'government': '🏛️', 'food': '🌽', // Maize/ugali 'housing': '🏘️', 'health': '🏥', 'education': '📚', 'default': '🇰🇪' }; const getContextIcon = (impact: string): string => { const lowercaseImpact = impact.toLowerCase(); if (lowercaseImpact.includes('transport') || lowercaseImpact.includes('matatu') || lowercaseImpact.includes('parking')) { return KENYAN_CONTEXT_ICONS.transport; } if (lowercaseImpact.includes('money') || lowercaseImpact.includes('fee') || lowercaseImpact.includes('cost')) { return KENYAN_CONTEXT_ICONS.money; } if (lowercaseImpact.includes('food') || lowercaseImpact.includes('mama mboga')) { return KENYAN_CONTEXT_ICONS.food; } if (lowercaseImpact.includes('housing') || lowercaseImpact.includes('rent')) { return KENYAN_CONTEXT_ICONS.housing; } return KENYAN_CONTEXT_ICONS.default; }; // ============================================================================ // MAIN COMPONENT // ============================================================================ export const AmaniQueryResponse: React.FC = ({ data, className = '', onFollowUpClick }) => { const [citationsExpanded, setCitationsExpanded] = useState(false); const [detailsExpanded, setDetailsExpanded] = useState(true); const theme = PERSONA_THEMES[data.query_type]; const contextIcon = getContextIcon(data.response.kenyan_context.impact); return (
{/* THINKING PROCESS - Display if available */} {data.metadata?.reasoning_path && (
)} {/* FACT CHECK ALERT - Display if issues found */} {data.metadata?.quality_issues && Array.isArray(data.metadata.quality_issues) && data.metadata.quality_issues.length > 0 && ( )} {/* SUMMARY CARD - HUGE AND PROMINENT */} {/* DETAILED BREAKDOWN */} setDetailsExpanded(!detailsExpanded)} /> {/* KENYAN CONTEXT */} {/* CITATIONS */} setCitationsExpanded(!citationsExpanded)} /> {/* FOLLOW-UP SUGGESTIONS */}
); }; // ============================================================================ // SUB-COMPONENTS // ============================================================================ interface ThemeProps { theme: typeof PERSONA_THEMES[keyof typeof PERSONA_THEMES]; } // SUMMARY CARD - TikTok-style prominence const SummaryCard: React.FC<{ title: string; content: string } & ThemeProps> = ({ title, content, theme }) => { return (
{/* Background pattern */}
{theme.icon}
{/* Header */}
{theme.icon}

{theme.summaryTitle}

{/* Title - HUGE */}

{title}

{/* Content */}

{content}

); }; // DETAILED BREAKDOWN const DetailedBreakdown: React.FC<{ points: string[]; isExpanded: boolean; onToggle: () => void; } & ThemeProps> = ({ points, theme, isExpanded, onToggle }) => { return (
{/* Header */} {/* Points */} {isExpanded && (
    {points.map((point, idx) => (
  • {idx + 1} {point}
  • ))}
)}
); }; // KENYAN CONTEXT const KenyanContext: React.FC<{ impact: string; relatedTopic: string | null; icon: string; } & ThemeProps> = ({ impact, relatedTopic, icon, theme }) => { return (
{/* Header with icon */}
{icon}

🇰🇪 Kenyan Context

{impact}

{/* Related Topic */} {relatedTopic && (
Related: {relatedTopic}
)}
); }; // CITATIONS (Collapsible) const Citations: React.FC<{ citations: AmaniQueryResponse['response']['citations']; isExpanded: boolean; onToggle: () => void; } & ThemeProps> = ({ citations, theme, isExpanded, onToggle }) => { return (
{/* Header */} {/* Citation List */} {isExpanded && (
{citations.map((citation, idx) => (
{citation.source}
{citation.quote && (
"{citation.quote}"
)} {citation.url !== 'N/A' && ( View source )}
))}
)}
); }; // FOLLOW-UP SUGGESTIONS const FollowUpSuggestions: React.FC<{ suggestions: string[]; onFollowUpClick?: (suggestion: string) => void; } & ThemeProps> = ({ suggestions, theme, onFollowUpClick }) => { return (

Want to know more?

{suggestions.map((suggestion, idx) => ( ))}
); }; export default AmaniQueryResponse;