/** * OpportunityPrioritizer - v1.0 * * Redesigned Opportunity Matrix that clearly shows: * 1. WHERE are the opportunities (ranked list with context) * 2. WHERE to START (highlighted #1 with full justification) * 3. WHY this prioritization (tier-based rationale + metrics) * * Design principles: * - Scannable in 5 seconds (executive summary) * - Actionable in 30 seconds (clear next steps) * - Deep-dive available (expandable details) */ import React, { useState, useMemo } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { useTranslation } from 'react-i18next'; import { Opportunity, DrilldownDataPoint, AgenticTier } from '../types'; import { ChevronRight, ChevronDown, TrendingUp, Zap, Clock, Users, Bot, Headphones, BookOpen, AlertTriangle, CheckCircle2, ArrowRight, Info, Target, DollarSign, BarChart3, Sparkles } from 'lucide-react'; interface OpportunityPrioritizerProps { opportunities: Opportunity[]; drilldownData?: DrilldownDataPoint[]; costPerHour?: number; } interface EnrichedOpportunity extends Opportunity { rank: number; tier: AgenticTier; volume: number; cv_aht: number; transfer_rate: number; fcr_rate: number; agenticScore: number; timelineMonths: number; effortLevel: 'low' | 'medium' | 'high'; riskLevel: 'low' | 'medium' | 'high'; whyPrioritized: string[]; nextSteps: string[]; annualCost?: number; } // Tier configuration - labels and descriptions will be translated at usage time const TIER_CONFIG: Record = { 'AUTOMATE': { icon: , labelKey: 'opportunityPrioritizer.tierLabels.automate', color: 'text-emerald-700', bgColor: 'bg-emerald-50', borderColor: 'border-emerald-300', savingsRate: '70%', timelineKey: 'opportunityPrioritizer.timelines.automate', descriptionKey: 'opportunityPrioritizer.tierDescriptions.automate' }, 'ASSIST': { icon: , labelKey: 'opportunityPrioritizer.tierLabels.assist', color: 'text-blue-700', bgColor: 'bg-blue-50', borderColor: 'border-blue-300', savingsRate: '30%', timelineKey: 'opportunityPrioritizer.timelines.assist', descriptionKey: 'opportunityPrioritizer.tierDescriptions.assist' }, 'AUGMENT': { icon: , labelKey: 'opportunityPrioritizer.tierLabels.augment', color: 'text-amber-700', bgColor: 'bg-amber-50', borderColor: 'border-amber-300', savingsRate: '15%', timelineKey: 'opportunityPrioritizer.timelines.augment', descriptionKey: 'opportunityPrioritizer.tierDescriptions.augment' }, 'HUMAN-ONLY': { icon: , labelKey: 'opportunityPrioritizer.tierLabels.human', color: 'text-slate-600', bgColor: 'bg-slate-50', borderColor: 'border-slate-300', savingsRate: '0%', timelineKey: 'N/A', descriptionKey: 'opportunityPrioritizer.tierDescriptions.humanOnly' } }; const OpportunityPrioritizer: React.FC = ({ opportunities, drilldownData, costPerHour = 20 }) => { const { t } = useTranslation(); const [expandedId, setExpandedId] = useState(null); const [showAllOpportunities, setShowAllOpportunities] = useState(false); // Enrich opportunities with drilldown data const enrichedOpportunities = useMemo((): EnrichedOpportunity[] => { if (!opportunities || opportunities.length === 0) return []; // Create a lookup map from drilldown data const queueLookup = new Map(); if (drilldownData) { drilldownData.forEach(skill => { skill.originalQueues?.forEach(q => { queueLookup.set(q.original_queue_id.toLowerCase(), { tier: q.tier || 'HUMAN-ONLY', volume: q.volume, cv_aht: q.cv_aht, transfer_rate: q.transfer_rate, fcr_rate: q.fcr_rate, agenticScore: q.agenticScore, annualCost: q.annualCost }); }); }); } return opportunities.map((opp, index) => { // Extract queue name (remove tier emoji prefix) const cleanName = opp.name.replace(/^[^\w\s]+\s*/, '').toLowerCase(); const lookupData = queueLookup.get(cleanName); // Determine tier from emoji prefix or lookup let tier: AgenticTier = 'ASSIST'; if (opp.name.startsWith('🤖')) tier = 'AUTOMATE'; else if (opp.name.startsWith('🤝')) tier = 'ASSIST'; else if (opp.name.startsWith('📚')) tier = 'AUGMENT'; else if (lookupData) tier = lookupData.tier; // Calculate effort and risk based on metrics const cv = lookupData?.cv_aht || 50; const transfer = lookupData?.transfer_rate || 15; const effortLevel: 'low' | 'medium' | 'high' = tier === 'AUTOMATE' && cv < 60 ? 'low' : tier === 'ASSIST' || cv < 80 ? 'medium' : 'high'; const riskLevel: 'low' | 'medium' | 'high' = cv < 50 && transfer < 15 ? 'low' : cv < 80 && transfer < 30 ? 'medium' : 'high'; // Timeline based on tier const timelineMonths = tier === 'AUTOMATE' ? 4 : tier === 'ASSIST' ? 7 : 10; // Generate "why" explanation - store keys for translation const whyPrioritized: { key: string; params?: any }[] = []; if (opp.savings > 50000) whyPrioritized.push({ key: 'reasons.highSavingsPotential', params: { amount: (opp.savings / 1000).toFixed(0) } }); if (lookupData?.volume && lookupData.volume > 1000) whyPrioritized.push({ key: 'reasons.highVolume', params: { volume: lookupData.volume.toLocaleString() } }); if (tier === 'AUTOMATE') whyPrioritized.push({ key: 'reasons.highlyPredictable' }); if (cv < 60) whyPrioritized.push({ key: 'reasons.lowVariability' }); if (transfer < 15) whyPrioritized.push({ key: 'reasons.lowTransferRate' }); if (opp.feasibility >= 7) whyPrioritized.push({ key: 'reasons.highFeasibility' }); // Generate next steps - store keys for translation const nextSteps: string[] = []; if (tier === 'AUTOMATE') { nextSteps.push('steps.automate1', 'steps.automate2', 'steps.automate3'); } else if (tier === 'ASSIST') { nextSteps.push('steps.assist1', 'steps.assist2', 'steps.assist3'); } else { nextSteps.push('steps.augment1', 'steps.augment2', 'steps.augment3'); } return { ...opp, rank: index + 1, tier, volume: lookupData?.volume || Math.round(opp.savings / 10), cv_aht: cv, transfer_rate: transfer, fcr_rate: lookupData?.fcr_rate || 75, agenticScore: lookupData?.agenticScore || opp.feasibility, timelineMonths, effortLevel, riskLevel, whyPrioritized, nextSteps, annualCost: lookupData?.annualCost }; }); }, [opportunities, drilldownData]); // Summary stats const summary = useMemo(() => { const totalSavings = enrichedOpportunities.reduce((sum, o) => sum + o.savings, 0); const byTier = { AUTOMATE: enrichedOpportunities.filter(o => o.tier === 'AUTOMATE'), ASSIST: enrichedOpportunities.filter(o => o.tier === 'ASSIST'), AUGMENT: enrichedOpportunities.filter(o => o.tier === 'AUGMENT') }; const quickWins = enrichedOpportunities.filter(o => o.tier === 'AUTOMATE' && o.effortLevel === 'low'); return { totalSavings, totalVolume: enrichedOpportunities.reduce((sum, o) => sum + o.volume, 0), byTier, quickWinsCount: quickWins.length, quickWinsSavings: quickWins.reduce((sum, o) => sum + o.savings, 0) }; }, [enrichedOpportunities]); const displayedOpportunities = showAllOpportunities ? enrichedOpportunities : enrichedOpportunities.slice(0, 5); const topOpportunity = enrichedOpportunities[0]; if (!enrichedOpportunities.length) { return (

{t('opportunityPrioritizer.noOpportunitiesTitle')}

{t('opportunityPrioritizer.noOpportunitiesDescription')}

); } return (
{/* Header - matching app's visual style */}

{t('opportunityPrioritizer.title')}

{t('opportunityPrioritizer.subtitle', { count: enrichedOpportunities.length })}

{/* Executive Summary - Answer "Where are opportunities?" in 5 seconds */}
{t('opportunityPrioritizer.totalSavingsIdentified')}
€{(summary.totalSavings / 1000).toFixed(0)}K
{t('opportunityPrioritizer.annual')}
{t('opportunityPrioritizer.quickWins')}
{summary.byTier.AUTOMATE.length}
€{(summary.byTier.AUTOMATE.reduce((s, o) => s + o.savings, 0) / 1000).toFixed(0)}K {t('opportunityPrioritizer.inMonths', { months: '3-6' })}
{t('opportunityPrioritizer.assistance')}
{summary.byTier.ASSIST.length}
€{(summary.byTier.ASSIST.reduce((s, o) => s + o.savings, 0) / 1000).toFixed(0)}K {t('opportunityPrioritizer.inMonths', { months: '6-9' })}
{t('opportunityPrioritizer.optimization')}
{summary.byTier.AUGMENT.length}
€{(summary.byTier.AUGMENT.reduce((s, o) => s + o.savings, 0) / 1000).toFixed(0)}K {t('opportunityPrioritizer.inMonths', { months: '9-12' })}
{/* START HERE - Answer "Where do I start?" */} {topOpportunity && (
{t('opportunityPrioritizer.startHere')} {t('opportunityPrioritizer.priority1')}
{/* Left: Main info */}
{TIER_CONFIG[topOpportunity.tier].icon}

{topOpportunity.name.replace(/^[^\w\s]+\s*/, '')}

{t(TIER_CONFIG[topOpportunity.tier].labelKey)} • {t(TIER_CONFIG[topOpportunity.tier].descriptionKey)}
{/* Key metrics */}
{t('opportunityPrioritizer.annualSavings')}
€{(topOpportunity.savings / 1000).toFixed(0)}K
{t('opportunityPrioritizer.volume')}
{topOpportunity.volume.toLocaleString()}
{t('opportunityPrioritizer.timeline')}
{topOpportunity.timelineMonths} {t('opportunityPrioritizer.months')}
{t('opportunityPrioritizer.agenticScore')}
{topOpportunity.agenticScore.toFixed(1)}/10
{/* Why this is #1 */}

{t('opportunityPrioritizer.whyPriority1')}

    {topOpportunity.whyPrioritized.slice(0, 4).map((reason, i) => (
  • {t(`opportunityPrioritizer.${reason.key}`, reason.params)}
  • ))}
{/* Right: Next steps */}

{t('opportunityPrioritizer.nextSteps')}

    {topOpportunity.nextSteps.map((step, i) => (
  1. {i + 1} {t(`opportunityPrioritizer.${step}`)}
  2. ))}
)} {/* Full Opportunity List - Answer "What else?" */}

{t('opportunityPrioritizer.allOpportunities')}

{displayedOpportunities.slice(1).map((opp) => ( {/* Collapsed view */}
setExpandedId(expandedId === opp.id ? null : opp.id)} >
{/* Rank */}
#{opp.rank}
{/* Tier icon and name */}
{TIER_CONFIG[opp.tier].icon}

{opp.name.replace(/^[^\w\s]+\s*/, '')}

{t(TIER_CONFIG[opp.tier].labelKey)} • {t(TIER_CONFIG[opp.tier].timelineKey)}
{/* Quick stats */}
{t('opportunityPrioritizer.savings')}
€{(opp.savings / 1000).toFixed(0)}K
{t('opportunityPrioritizer.volume')}
{opp.volume.toLocaleString()}
Score
{opp.agenticScore.toFixed(1)}
{/* Visual bar: Value vs Effort */}
{t('opportunityPrioritizer.valueEffort')}
{t('opportunityPrioritizer.value')} {t('opportunityPrioritizer.effort')}
{/* Expand icon */}
{/* Expanded details */} {expandedId === opp.id && (
{/* Why prioritized */}
{t('opportunityPrioritizer.whyThisPosition')}
    {opp.whyPrioritized.map((reason, i) => (
  • {t(`opportunityPrioritizer.${reason.key}`, reason.params)}
  • ))}
{/* Metrics */}
{t('opportunityPrioritizer.keyMetrics')}
CV AHT
{opp.cv_aht.toFixed(1)}%
Transfer Rate
{opp.transfer_rate.toFixed(1)}%
FCR
{opp.fcr_rate.toFixed(1)}%
{t('roadmap.risk')}
{t(`roadmap.risk${opp.riskLevel.charAt(0).toUpperCase() + opp.riskLevel.slice(1)}`)}
{/* Next steps */}
{t('opportunityPrioritizer.nextSteps')}
{opp.nextSteps.map((step, i) => ( {i + 1}. {t(`opportunityPrioritizer.${step}`)} ))}
)}
))}
{/* Show more button */} {enrichedOpportunities.length > 5 && ( )}
{/* Methodology note */}
{t('opportunityPrioritizer.methodology')} {t('opportunityPrioritizer.methodologyDescription')}
); }; export default OpportunityPrioritizer;