Merge pull request #13 from sujucu70/claude/check-agent-readiness-status-Exnpc

Claude/check agent readiness status exnpc
This commit is contained in:
sujucu70
2026-02-08 00:36:05 +01:00
committed by GitHub
4 changed files with 203 additions and 93 deletions

View File

@@ -1862,7 +1862,7 @@ function SkillClassificationSection({ drilldownData }: { drilldownData: Drilldow
{/* Header */} {/* Header */}
<div className="px-5 py-3" style={{ backgroundColor: COLORS.dark }}> <div className="px-5 py-3" style={{ backgroundColor: COLORS.dark }}>
<h2 className="font-bold text-sm" style={{ color: COLORS.white }}> <h2 className="font-bold text-sm" style={{ color: COLORS.white }}>
CLASIFICACIÓN POR SKILL {t('agenticReadiness.sections.classificationBySkill')}
</h2> </h2>
</div> </div>
@@ -1872,18 +1872,18 @@ function SkillClassificationSection({ drilldownData }: { drilldownData: Drilldow
<table className="w-full text-sm"> <table className="w-full text-sm">
<thead> <thead>
<tr style={{ color: COLORS.medium }}> <tr style={{ color: COLORS.medium }}>
<th className="text-left py-2 font-medium">Skill</th> <th className="text-left py-2 font-medium">{t('agenticReadiness.table.skill')}</th>
<th className="text-right py-2 font-medium">Volumen</th> <th className="text-right py-2 font-medium">{t('agenticReadiness.table.volume')}</th>
<th className="text-center py-2 font-medium" colSpan={4}>Distribución Colas por Tier</th> <th className="text-center py-2 font-medium" colSpan={4}>{t('agenticReadiness.classification.distribution')}</th>
<th className="text-left py-2 font-medium pl-4">Acción</th> <th className="text-left py-2 font-medium pl-4">{t('agenticReadiness.classification.action')}</th>
</tr> </tr>
<tr style={{ color: COLORS.medium }} className="text-xs"> <tr style={{ color: COLORS.medium }} className="text-xs">
<th></th> <th></th>
<th></th> <th></th>
<th className="text-center py-1">AUTO</th> <th className="text-center py-1">{t('agenticReadiness.classification.auto')}</th>
<th className="text-center py-1">ASIST</th> <th className="text-center py-1">{t('agenticReadiness.classification.assist')}</th>
<th className="text-center py-1">AUGM</th> <th className="text-center py-1">{t('agenticReadiness.classification.augm')}</th>
<th className="text-center py-1">HUMAN</th> <th className="text-center py-1">{t('agenticReadiness.classification.human')}</th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
@@ -2298,7 +2298,7 @@ function ExpandableSkillRow({
// ============================================ // ============================================
// Configuración de colores y estilos por tier // Configuración de colores y estilos por tier
const TIER_SECTION_CONFIG: Record<AgenticTier, { const getTierSectionConfig = (t: any): Record<AgenticTier, {
color: string; color: string;
bgColor: string; bgColor: string;
borderColor: string; borderColor: string;
@@ -2308,7 +2308,7 @@ const TIER_SECTION_CONFIG: Record<AgenticTier, {
title: string; title: string;
subtitle: string; subtitle: string;
emptyMessage: string; emptyMessage: string;
}> = { }> => ({
'AUTOMATE': { 'AUTOMATE': {
color: '#10b981', color: '#10b981',
bgColor: '#d1fae5', bgColor: '#d1fae5',
@@ -2316,9 +2316,9 @@ const TIER_SECTION_CONFIG: Record<AgenticTier, {
gradientFrom: 'from-emerald-50', gradientFrom: 'from-emerald-50',
gradientTo: 'to-emerald-100/50', gradientTo: 'to-emerald-100/50',
icon: Sparkles, icon: Sparkles,
title: 'Colas AUTOMATE', title: t('agenticReadiness.sections.queuesAutomate'),
subtitle: 'Listas para automatización completa con agente virtual (Score ≥7.5)', subtitle: t('agenticReadiness.sections.readyForFullAutomation'),
emptyMessage: 'No hay colas clasificadas como AUTOMATE' emptyMessage: t('agenticReadiness.emptyStates.noQueuesClassifiedAs', { tier: 'AUTOMATE' })
}, },
'ASSIST': { 'ASSIST': {
color: '#3b82f6', color: '#3b82f6',
@@ -2327,9 +2327,9 @@ const TIER_SECTION_CONFIG: Record<AgenticTier, {
gradientFrom: 'from-blue-50', gradientFrom: 'from-blue-50',
gradientTo: 'to-blue-100/50', gradientTo: 'to-blue-100/50',
icon: Bot, icon: Bot,
title: 'Colas ASSIST', title: t('agenticReadiness.sections.queuesAssist'),
subtitle: 'Candidatas a Copilot - IA asiste al agente humano (Score 5.5-7.5)', subtitle: t('agenticReadiness.sections.candidatesForCopilot'),
emptyMessage: 'No hay colas clasificadas como ASSIST' emptyMessage: t('agenticReadiness.emptyStates.noQueuesClassifiedAs', { tier: 'ASSIST' })
}, },
'AUGMENT': { 'AUGMENT': {
color: '#f59e0b', color: '#f59e0b',
@@ -2338,9 +2338,9 @@ const TIER_SECTION_CONFIG: Record<AgenticTier, {
gradientFrom: 'from-amber-50', gradientFrom: 'from-amber-50',
gradientTo: 'to-amber-100/50', gradientTo: 'to-amber-100/50',
icon: TrendingUp, icon: TrendingUp,
title: 'Colas AUGMENT', title: t('agenticReadiness.sections.queuesAugment'),
subtitle: 'Requieren optimización previa: estandarizar procesos, reducir variabilidad (Score 3.5-5.5)', subtitle: t('agenticReadiness.sections.requireOptimization'),
emptyMessage: 'No hay colas clasificadas como AUGMENT' emptyMessage: t('agenticReadiness.emptyStates.noQueuesClassifiedAs', { tier: 'AUGMENT' })
}, },
'HUMAN-ONLY': { 'HUMAN-ONLY': {
color: '#6b7280', color: '#6b7280',
@@ -2349,24 +2349,26 @@ const TIER_SECTION_CONFIG: Record<AgenticTier, {
gradientFrom: 'from-gray-50', gradientFrom: 'from-gray-50',
gradientTo: 'to-gray-100/50', gradientTo: 'to-gray-100/50',
icon: Users, icon: Users,
title: 'Colas HUMAN-ONLY', title: t('agenticReadiness.sections.queuesHumanOnly'),
subtitle: 'No aptas para automatización: volumen insuficiente, datos de baja calidad o complejidad extrema', subtitle: t('agenticReadiness.sections.notSuitableForAutomation'),
emptyMessage: 'No hay colas clasificadas como HUMAN-ONLY' emptyMessage: t('agenticReadiness.emptyStates.noQueuesClassifiedAs', { tier: 'HUMAN-ONLY' })
} }
}; });
// Componente de tabla de colas por Tier (AUTOMATE, ASSIST, AUGMENT) // Componente de tabla de colas por Tier (AUTOMATE, ASSIST, AUGMENT)
function TierQueueSection({ function TierQueueSection({
drilldownData, drilldownData,
tier, tier,
redFlagConfigs redFlagConfigs,
t
}: { }: {
drilldownData: DrilldownDataPoint[]; drilldownData: DrilldownDataPoint[];
tier: 'AUTOMATE' | 'ASSIST' | 'AUGMENT'; tier: 'AUTOMATE' | 'ASSIST' | 'AUGMENT';
redFlagConfigs: RedFlagConfig[]; redFlagConfigs: RedFlagConfig[];
t: any;
}) { }) {
const [expandedSkills, setExpandedSkills] = useState<Set<string>>(new Set()); const [expandedSkills, setExpandedSkills] = useState<Set<string>>(new Set());
const config = TIER_SECTION_CONFIG[tier]; const config = getTierSectionConfig(t)[tier];
const IconComponent = config.icon; const IconComponent = config.icon;
// Extraer todas las colas del tier específico, agrupadas por skill // Extraer todas las colas del tier específico, agrupadas por skill
@@ -2418,7 +2420,7 @@ function TierQueueSection({
</div> </div>
<div className="text-right"> <div className="text-right">
<span className="text-3xl font-bold" style={{ color: config.color }}>{totalQueues}</span> <span className="text-3xl font-bold" style={{ color: config.color }}>{totalQueues}</span>
<p className="text-sm" style={{ color: config.color + 'cc' }}>colas en {skillsWithTierQueues.length} skills</p> <p className="text-sm" style={{ color: config.color + 'cc' }}>{t('agenticReadiness.sections.queuesIn', { count: skillsWithTierQueues.length })}</p>
</div> </div>
</div> </div>
</div> </div>
@@ -2427,14 +2429,14 @@ function TierQueueSection({
<div className="px-5 py-3 border-b flex items-center justify-between text-sm" style={{ backgroundColor: config.bgColor + '40' }}> <div className="px-5 py-3 border-b flex items-center justify-between text-sm" style={{ backgroundColor: config.bgColor + '40' }}>
<div className="flex gap-4 flex-wrap"> <div className="flex gap-4 flex-wrap">
<span className="text-gray-600"> <span className="text-gray-600">
Volumen: <strong className="text-gray-800">{totalVolume.toLocaleString()}</strong> int/mes {t('agenticReadiness.sections.volumeColon')} <strong className="text-gray-800">{totalVolume.toLocaleString()}</strong> {t('agenticReadiness.table.int')}/{t('agenticReadiness.table.perMonth').replace('/', '')}
</span> </span>
<span className="text-gray-600"> <span className="text-gray-600">
Coste: <strong className="text-gray-800">{formatCurrency(totalCost)}</strong>/año {t('agenticReadiness.sections.costColon')} <strong className="text-gray-800">{formatCurrency(totalCost)}</strong>{t('agenticReadiness.table.perYear')}
</span> </span>
</div> </div>
<span className="font-bold" style={{ color: config.color }}> <span className="font-bold" style={{ color: config.color }}>
Ahorro potencial: {formatCurrency(potentialSavings)}/año {t('agenticReadiness.sections.potentialSavingsColon')} {formatCurrency(potentialSavings)}{t('agenticReadiness.table.perYear')}
</span> </span>
</div> </div>
@@ -2444,13 +2446,13 @@ function TierQueueSection({
<thead> <thead>
<tr className="text-xs text-gray-500 uppercase tracking-wider bg-gray-50 border-b border-gray-200"> <tr className="text-xs text-gray-500 uppercase tracking-wider bg-gray-50 border-b border-gray-200">
<th className="px-3 py-2.5 text-left font-medium w-8"></th> <th className="px-3 py-2.5 text-left font-medium w-8"></th>
<th className="px-3 py-2.5 text-left font-medium">Business Unit (Skill)</th> <th className="px-3 py-2.5 text-left font-medium">{t('agenticReadiness.table.businessUnit')}</th>
<th className="px-3 py-2.5 text-center font-medium">Colas</th> <th className="px-3 py-2.5 text-center font-medium">{t('agenticReadiness.table.queues')}</th>
<th className="px-3 py-2.5 text-right font-medium">Volumen</th> <th className="px-3 py-2.5 text-right font-medium">{t('agenticReadiness.table.volume')}</th>
<th className="px-3 py-2.5 text-right font-medium">AHT Prom.</th> <th className="px-3 py-2.5 text-right font-medium">{t('agenticReadiness.table.avgAht')}</th>
<th className="px-3 py-2.5 text-right font-medium">CV Prom.</th> <th className="px-3 py-2.5 text-right font-medium">{t('agenticReadiness.table.avgCv')}</th>
<th className="px-3 py-2.5 text-right font-medium">FCR</th> <th className="px-3 py-2.5 text-right font-medium">{t('agenticReadiness.table.fcr')}</th>
<th className="px-3 py-2.5 text-right font-medium">Ahorro Potencial</th> <th className="px-3 py-2.5 text-right font-medium">{t('agenticReadiness.table.potentialSavings')}</th>
</tr> </tr>
</thead> </thead>
<tbody className="divide-y divide-gray-100"> <tbody className="divide-y divide-gray-100">
@@ -2510,14 +2512,14 @@ function TierQueueSection({
<table className="w-full text-sm"> <table className="w-full text-sm">
<thead> <thead>
<tr className="text-xs text-gray-500 uppercase tracking-wider" style={{ backgroundColor: config.bgColor + '60' }}> <tr className="text-xs text-gray-500 uppercase tracking-wider" style={{ backgroundColor: config.bgColor + '60' }}>
<th className="px-4 py-2 text-left font-medium">Cola (ID)</th> <th className="px-4 py-2 text-left font-medium">{t('agenticReadiness.table.queueId')}</th>
<th className="px-3 py-2 text-right font-medium">Volumen</th> <th className="px-3 py-2 text-right font-medium">{t('agenticReadiness.table.volume')}</th>
<th className="px-3 py-2 text-right font-medium">AHT</th> <th className="px-3 py-2 text-right font-medium">{t('agenticReadiness.table.aht')}</th>
<th className="px-3 py-2 text-right font-medium">CV</th> <th className="px-3 py-2 text-right font-medium">{t('agenticReadiness.table.cv')}</th>
<th className="px-3 py-2 text-right font-medium">Transfer</th> <th className="px-3 py-2 text-right font-medium">{t('agenticReadiness.table.transfer')}</th>
<th className="px-3 py-2 text-right font-medium">FCR</th> <th className="px-3 py-2 text-right font-medium">{t('agenticReadiness.table.fcr')}</th>
<th className="px-3 py-2 text-center font-medium">Score</th> <th className="px-3 py-2 text-center font-medium">{t('agenticReadiness.table.score')}</th>
<th className="px-3 py-2 text-right font-medium">Ahorro</th> <th className="px-3 py-2 text-right font-medium">{t('agenticReadiness.table.savingsPerMonth')}</th>
</tr> </tr>
</thead> </thead>
<tbody className="divide-y divide-gray-100"> <tbody className="divide-y divide-gray-100">
@@ -2570,9 +2572,9 @@ function TierQueueSection({
} }
// Componente para colas HUMAN-ONLY agrupadas por razón/red flag // Componente para colas HUMAN-ONLY agrupadas por razón/red flag
function HumanOnlyByReasonSection({ drilldownData, redFlagConfigs }: { drilldownData: DrilldownDataPoint[]; redFlagConfigs: RedFlagConfig[] }) { function HumanOnlyByReasonSection({ drilldownData, redFlagConfigs, t }: { drilldownData: DrilldownDataPoint[]; redFlagConfigs: RedFlagConfig[]; t: any }) {
const [expandedReasons, setExpandedReasons] = useState<Set<string>>(new Set()); const [expandedReasons, setExpandedReasons] = useState<Set<string>>(new Set());
const config = TIER_SECTION_CONFIG['HUMAN-ONLY']; const config = getTierSectionConfig(t)['HUMAN-ONLY'];
// Extraer todas las colas HUMAN-ONLY // Extraer todas las colas HUMAN-ONLY
const allHumanOnlyQueues = drilldownData.flatMap(skill => const allHumanOnlyQueues = drilldownData.flatMap(skill =>
@@ -2665,7 +2667,7 @@ function HumanOnlyByReasonSection({ drilldownData, redFlagConfigs }: { drilldown
</div> </div>
<div className="text-right"> <div className="text-right">
<span className="text-3xl font-bold" style={{ color: config.color }}>{totalQueues}</span> <span className="text-3xl font-bold" style={{ color: config.color }}>{totalQueues}</span>
<p className="text-sm text-gray-500">colas agrupadas por {reasonGroups.length} razones</p> <p className="text-sm text-gray-500">{t('agenticReadiness.summary.groupedBy', { count: reasonGroups.length })}</p>
</div> </div>
</div> </div>
</div> </div>
@@ -2673,10 +2675,10 @@ function HumanOnlyByReasonSection({ drilldownData, redFlagConfigs }: { drilldown
{/* Resumen */} {/* Resumen */}
<div className="px-5 py-3 border-b bg-gray-50 flex items-center justify-between text-sm"> <div className="px-5 py-3 border-b bg-gray-50 flex items-center justify-between text-sm">
<span className="text-gray-600"> <span className="text-gray-600">
Volumen total: <strong className="text-gray-800">{totalVolume.toLocaleString()}</strong> int/mes {t('agenticReadiness.humanOnlyReasons.volumeTotal')} <strong className="text-gray-800">{totalVolume.toLocaleString()}</strong> {t('agenticReadiness.table.int')}/{t('agenticReadiness.table.perMonth').replace('/', '')}
</span> </span>
<span className="text-gray-500"> <span className="text-gray-500">
Estas colas requieren intervención antes de considerar automatización {t('agenticReadiness.summary.requiresIntervention')}
</span> </span>
</div> </div>
@@ -2686,10 +2688,10 @@ function HumanOnlyByReasonSection({ drilldownData, redFlagConfigs }: { drilldown
<thead> <thead>
<tr className="text-xs text-gray-500 uppercase tracking-wider bg-gray-50 border-b border-gray-200"> <tr className="text-xs text-gray-500 uppercase tracking-wider bg-gray-50 border-b border-gray-200">
<th className="px-3 py-2.5 text-left font-medium w-8"></th> <th className="px-3 py-2.5 text-left font-medium w-8"></th>
<th className="px-3 py-2.5 text-left font-medium">Razón / Red Flag</th> <th className="px-3 py-2.5 text-left font-medium">{t('agenticReadiness.table.reason')}</th>
<th className="px-3 py-2.5 text-center font-medium">Colas</th> <th className="px-3 py-2.5 text-center font-medium">{t('agenticReadiness.table.queues')}</th>
<th className="px-3 py-2.5 text-right font-medium">Volumen</th> <th className="px-3 py-2.5 text-right font-medium">{t('agenticReadiness.table.volume')}</th>
<th className="px-3 py-2.5 text-left font-medium">Acción Recomendada</th> <th className="px-3 py-2.5 text-left font-medium">{t('agenticReadiness.table.recommendedAction')}</th>
</tr> </tr>
</thead> </thead>
<tbody className="divide-y divide-gray-100"> <tbody className="divide-y divide-gray-100">
@@ -2742,13 +2744,13 @@ function HumanOnlyByReasonSection({ drilldownData, redFlagConfigs }: { drilldown
<table className="w-full text-sm"> <table className="w-full text-sm">
<thead> <thead>
<tr className="text-xs text-gray-500 uppercase tracking-wider bg-gray-100"> <tr className="text-xs text-gray-500 uppercase tracking-wider bg-gray-100">
<th className="px-4 py-2 text-left font-medium">Cola (ID)</th> <th className="px-4 py-2 text-left font-medium">{t('agenticReadiness.table.queueId')}</th>
<th className="px-3 py-2 text-left font-medium">Skill</th> <th className="px-3 py-2 text-left font-medium">{t('agenticReadiness.table.skill')}</th>
<th className="px-3 py-2 text-right font-medium">Volumen</th> <th className="px-3 py-2 text-right font-medium">{t('agenticReadiness.table.volume')}</th>
<th className="px-3 py-2 text-right font-medium">CV AHT</th> <th className="px-3 py-2 text-right font-medium">{t('agenticReadiness.table.cv')}</th>
<th className="px-3 py-2 text-right font-medium">Transfer</th> <th className="px-3 py-2 text-right font-medium">{t('agenticReadiness.table.transfer')}</th>
<th className="px-3 py-2 text-center font-medium">Score</th> <th className="px-3 py-2 text-center font-medium">{t('agenticReadiness.table.score')}</th>
<th className="px-3 py-2 text-left font-medium">Red Flags</th> <th className="px-3 py-2 text-left font-medium">{t('agenticReadiness.table.redFlags')}</th>
</tr> </tr>
</thead> </thead>
<tbody className="divide-y divide-gray-100 bg-white"> <tbody className="divide-y divide-gray-100 bg-white">
@@ -2864,10 +2866,10 @@ function PriorityCandidatesSection({ drilldownData, redFlagConfigs, t }: { drill
<div> <div>
<h3 className="text-lg font-bold text-emerald-800 flex items-center gap-2"> <h3 className="text-lg font-bold text-emerald-800 flex items-center gap-2">
<Sparkles className="w-5 h-5" /> <Sparkles className="w-5 h-5" />
CLASIFICACIÓN POR TIER DE AUTOMATIZACIÓN {t('agenticReadiness.sections.classificationByTier')}
</h3> </h3>
<p className="text-sm text-emerald-600 mt-1"> <p className="text-sm text-emerald-600 mt-1">
Skills con colas clasificadas como AUTOMATE (score 7.5, CV 75%, transfer 20%) {t('agenticReadiness.classification.subtitle')}
</p> </p>
</div> </div>
<div className="text-right"> <div className="text-right">
@@ -3729,16 +3731,16 @@ export function AgenticReadinessTab({ data, onTabChange }: AgenticReadinessTabPr
{data.drilldownData && data.drilldownData.length > 0 ? ( {data.drilldownData && data.drilldownData.length > 0 ? (
<> <>
{/* TABLA 1: Colas AUTOMATE - Listas para automatización */} {/* TABLA 1: Colas AUTOMATE - Listas para automatización */}
<TierQueueSection drilldownData={data.drilldownData} tier="AUTOMATE" redFlagConfigs={redFlagConfigs} /> <TierQueueSection drilldownData={data.drilldownData} tier="AUTOMATE" redFlagConfigs={redFlagConfigs} t={t} />
{/* TABLA 2: Colas ASSIST - Candidatas a Copilot */} {/* TABLA 2: Colas ASSIST - Candidatas a Copilot */}
<TierQueueSection drilldownData={data.drilldownData} tier="ASSIST" redFlagConfigs={redFlagConfigs} /> <TierQueueSection drilldownData={data.drilldownData} tier="ASSIST" redFlagConfigs={redFlagConfigs} t={t} />
{/* TABLA 3: Colas AUGMENT - Requieren optimización */} {/* TABLA 3: Colas AUGMENT - Requieren optimización */}
<TierQueueSection drilldownData={data.drilldownData} tier="AUGMENT" redFlagConfigs={redFlagConfigs} /> <TierQueueSection drilldownData={data.drilldownData} tier="AUGMENT" redFlagConfigs={redFlagConfigs} t={t} />
{/* TABLA 4: Colas HUMAN-ONLY - Agrupadas por razón/red flag */} {/* TABLA 4: Colas HUMAN-ONLY - Agrupadas por razón/red flag */}
<HumanOnlyByReasonSection drilldownData={data.drilldownData} redFlagConfigs={redFlagConfigs} /> <HumanOnlyByReasonSection drilldownData={data.drilldownData} redFlagConfigs={redFlagConfigs} t={t} />
</> </>
) : ( ) : (
/* Fallback a tabla por Línea de Negocio si no hay drilldown data */ /* Fallback a tabla por Línea de Negocio si no hay drilldown data */

View File

@@ -1160,11 +1160,11 @@ function WaveCard({
<p className="text-sm font-bold text-amber-700">{formatCurrency(wave.costoRecurrenteAnual)}</p> <p className="text-sm font-bold text-amber-700">{formatCurrency(wave.costoRecurrenteAnual)}</p>
</div> </div>
<div className="p-2 bg-emerald-50 rounded border border-emerald-100"> <div className="p-2 bg-emerald-50 rounded border border-emerald-100">
<p className="text-[10px] text-emerald-600 font-medium">Ahorro/año</p> <p className="text-[10px] text-emerald-600 font-medium">{t('roadmap.comparison.savingsPerYear')}</p>
<p className="text-sm font-bold text-emerald-700">{formatCurrency(wave.ahorroAnual)}</p> <p className="text-sm font-bold text-emerald-700">{formatCurrency(wave.ahorroAnual)}</p>
</div> </div>
<div className="p-2 bg-blue-50 rounded border border-blue-100"> <div className="p-2 bg-blue-50 rounded border border-blue-100">
<p className="text-[10px] text-blue-600 font-medium">Margen/año</p> <p className="text-[10px] text-blue-600 font-medium">{t('roadmap.comparison.marginPerYear')}</p>
<p className="text-sm font-bold text-blue-700">{formatCurrency(margenAnual)}</p> <p className="text-sm font-bold text-blue-700">{formatCurrency(margenAnual)}</p>
</div> </div>
</div> </div>
@@ -1248,11 +1248,11 @@ function ScenarioComparison({ escenarios }: { escenarios: EscenarioData[] }) {
<div className="p-4 border-b border-gray-200 bg-gray-50"> <div className="p-4 border-b border-gray-200 bg-gray-50">
<h3 className="font-semibold text-gray-800 flex items-center gap-2"> <h3 className="font-semibold text-gray-800 flex items-center gap-2">
<Target className="w-5 h-5 text-blue-500" /> <Target className="w-5 h-5 text-blue-500" />
Escenarios de Inversión {t('roadmap.comparison.title')}
</h3> </h3>
<p className="text-xs text-gray-500 mt-1"> <p className="text-xs text-gray-500 mt-1">
Comparación de opciones según nivel de compromiso {t('roadmap.comparison.subtitle')}
<span className="ml-2 text-gray-400" title="ROI basado en benchmarks de industria. El ROI ajustado considera factores de riesgo de implementación."> <span className="ml-2 text-gray-400" title={t('roadmap.comparison.tooltip')}>
</span> </span>
</p> </p>
@@ -1262,20 +1262,20 @@ function ScenarioComparison({ escenarios }: { escenarios: EscenarioData[] }) {
<table className="w-full text-sm"> <table className="w-full text-sm">
<thead className="bg-gray-50"> <thead className="bg-gray-50">
<tr> <tr>
<th className="text-left py-3 px-4 font-medium text-gray-600">Escenario</th> <th className="text-left py-3 px-4 font-medium text-gray-600">{t('roadmap.comparison.scenario')}</th>
<th className="text-right py-3 px-4 font-medium text-gray-600">Inversión</th> <th className="text-right py-3 px-4 font-medium text-gray-600">{t('roadmap.comparison.investment')}</th>
<th className="text-right py-3 px-4 font-medium text-gray-600">Recurrente</th> <th className="text-right py-3 px-4 font-medium text-gray-600">{t('roadmap.comparison.recurring')}</th>
<th className="text-right py-3 px-4 font-medium text-gray-600"> <th className="text-right py-3 px-4 font-medium text-gray-600">
Ahorro {t('roadmap.comparison.savings')}
<span className="block text-[10px] text-gray-400 font-normal">(ajustado)</span> <span className="block text-[10px] text-gray-400 font-normal">({t('roadmap.comparison.adjusted')})</span>
</th> </th>
<th className="text-right py-3 px-4 font-medium text-gray-600">Margen</th> <th className="text-right py-3 px-4 font-medium text-gray-600">{t('roadmap.comparison.margin')}</th>
<th className="text-right py-3 px-4 font-medium text-gray-600">Payback</th> <th className="text-right py-3 px-4 font-medium text-gray-600">{t('roadmap.comparison.payback')}</th>
<th className="text-right py-3 px-4 font-medium text-gray-600"> <th className="text-right py-3 px-4 font-medium text-gray-600">
ROI 3a {t('roadmap.comparison.roi3y')}
<span className="block text-[10px] text-gray-400 font-normal">(ajustado)</span> <span className="block text-[10px] text-gray-400 font-normal">({t('roadmap.comparison.adjusted')})</span>
</th> </th>
<th className="text-center py-3 px-4 font-medium text-gray-600">Riesgo</th> <th className="text-center py-3 px-4 font-medium text-gray-600">{t('roadmap.comparison.risk')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -1296,10 +1296,10 @@ function ScenarioComparison({ escenarios }: { escenarios: EscenarioData[] }) {
<td className="py-3 px-4"> <td className="py-3 px-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{esc.esHabilitador && ( {esc.esHabilitador && (
<span className="text-blue-500" title="Wave habilitadora - su valor está en desbloquear waves posteriores">💡</span> <span className="text-blue-500" title={t('roadmap.comparison.enablerWaveTooltip')}>💡</span>
)} )}
{!esc.esRentable && !esc.esHabilitador && ( {!esc.esRentable && !esc.esHabilitador && (
<span className="text-red-500" title="Margen anual negativo"></span> <span className="text-red-500" title={t('roadmap.comparison.negativeMarginTooltip')}></span>
)} )}
<span className={`font-medium ${ <span className={`font-medium ${
esc.esHabilitador ? 'text-blue-700' : esc.esHabilitador ? 'text-blue-700' :
@@ -1383,12 +1383,12 @@ function ScenarioComparison({ escenarios }: { escenarios: EscenarioData[] }) {
}`}> }`}>
{roiInfo.text} {roiInfo.text}
{roiInfo.isHighWarning && ( {roiInfo.isHighWarning && (
<span className="ml-1" title="ROI proyectado. Validar con piloto."></span> <span className="ml-1" title={t('roadmap.comparison.projectedRoiTooltip')}></span>
)} )}
</span> </span>
{roiInfo.showAjustado && esc.roi3AnosAjustado > 0 && ( {roiInfo.showAjustado && esc.roi3AnosAjustado > 0 && (
<span className="text-[10px] text-gray-500" title="ROI ajustado por riesgo de implementación"> <span className="text-[10px] text-gray-500" title={t('roadmap.comparison.adjustedRoiTooltip')}>
({esc.roi3AnosAjustado.toFixed(1)}% ajust.) ({esc.roi3AnosAjustado.toFixed(1)}% {t('roadmap.comparison.adjusted').slice(0, 5)}.)
</span> </span>
)} )}
</div> </div>
@@ -1396,7 +1396,7 @@ function ScenarioComparison({ escenarios }: { escenarios: EscenarioData[] }) {
</td> </td>
<td className="text-center py-3 px-4"> <td className="text-center py-3 px-4">
<span className={`text-xs px-2 py-1 rounded-full ${riesgoColors[esc.riesgo]}`}> <span className={`text-xs px-2 py-1 rounded-full ${riesgoColors[esc.riesgo]}`}>
{esc.riesgo.charAt(0).toUpperCase() + esc.riesgo.slice(1)} {t(`roadmap.comparison.risk${esc.riesgo.charAt(0).toUpperCase() + esc.riesgo.slice(1)}`)}
</span> </span>
</td> </td>
</tr> </tr>
@@ -1566,7 +1566,7 @@ function RoadmapTimeline({ waves }: { waves: WaveData[] }) {
<span className="font-semibold text-gray-700 ml-1">{formatCurrency(wave.inversionSetup)}</span> <span className="font-semibold text-gray-700 ml-1">{formatCurrency(wave.inversionSetup)}</span>
</div> </div>
<div className="bg-white/60 rounded px-1.5 py-1"> <div className="bg-white/60 rounded px-1.5 py-1">
<span className="text-gray-500">Ahorro:</span> <span className="text-gray-500">{t('roadmap.comparison.savingsLabel')}</span>
<span className="font-semibold text-emerald-600 ml-1">{formatCurrency(wave.ahorroAnual)}</span> <span className="font-semibold text-emerald-600 ml-1">{formatCurrency(wave.ahorroAnual)}</span>
</div> </div>
</div> </div>
@@ -1574,7 +1574,7 @@ function RoadmapTimeline({ waves }: { waves: WaveData[] }) {
{/* Conditional badge */} {/* Conditional badge */}
{wave.esCondicional && ( {wave.esCondicional && (
<div className="absolute -top-2 -right-2 bg-amber-500 text-white text-[8px] px-1.5 py-0.5 rounded-full font-medium"> <div className="absolute -top-2 -right-2 bg-amber-500 text-white text-[8px] px-1.5 py-0.5 rounded-full font-medium">
Condicional {t('roadmap.comparison.conditional')}
</div> </div>
)} )}
@@ -1584,7 +1584,7 @@ function RoadmapTimeline({ waves }: { waves: WaveData[] }) {
wave.riesgo === 'medio' ? 'bg-amber-500 text-white' : wave.riesgo === 'medio' ? 'bg-amber-500 text-white' :
'bg-red-500 text-white' 'bg-red-500 text-white'
}`}> }`}>
{wave.riesgo === 'bajo' ? '● Bajo' : wave.riesgo === 'medio' ? '● Medio' : '● Alto'} {t(`roadmap.comparison.risk${wave.riesgo.charAt(0).toUpperCase() + wave.riesgo.slice(1)}`)}
</div> </div>
</div> </div>
</motion.div> </motion.div>

View File

@@ -686,9 +686,13 @@
"legendRisk": "= Risk" "legendRisk": "= Risk"
}, },
"comparison": { "comparison": {
"title": "Investment Scenarios",
"subtitle": "Comparison of options by commitment level",
"tooltip": "ROI based on industry benchmarks. Adjusted ROI considers implementation risk factors.",
"investment": "Investment", "investment": "Investment",
"recurring": "Recurring", "recurring": "Recurring",
"savings": "Savings", "savings": "Savings",
"adjusted": "adjusted",
"margin": "Margin", "margin": "Margin",
"payback": "Payback", "payback": "Payback",
"roi3y": "3y ROI", "roi3y": "3y ROI",
@@ -697,7 +701,18 @@
"recommendation": "Recommendation", "recommendation": "Recommendation",
"recommendationEnabler": "Recommendation (Enabler)", "recommendationEnabler": "Recommendation (Enabler)",
"enabler": "Enabler", "enabler": "Enabler",
"recommended": "Recommended" "recommended": "Recommended",
"savingsPerYear": "Savings/year",
"marginPerYear": "Margin/year",
"savingsLabel": "Savings:",
"conditional": "Conditional",
"riskLow": "Low",
"riskMedium": "Medium",
"riskHigh": "High",
"enablerWaveTooltip": "Enabler wave - its value is in unlocking subsequent waves",
"negativeMarginTooltip": "Negative annual margin",
"projectedRoiTooltip": "Projected ROI. Validate with pilot.",
"adjustedRoiTooltip": "ROI adjusted for implementation risk"
}, },
"entryCriteria": { "entryCriteria": {
"wave1TierFrom": "HUMAN-ONLY (4), AUGMENT (3)", "wave1TierFrom": "HUMAN-ONLY (4), AUGMENT (3)",
@@ -1186,6 +1201,53 @@
"notRecommended": "Not recommended for automation at this time", "notRecommended": "Not recommended for automation at this time",
"bronzeAnalysis": "Bronze analysis does not include Agentic Readiness Score" "bronzeAnalysis": "Bronze analysis does not include Agentic Readiness Score"
} }
},
"table": {
"queueId": "Queue (original_queue_id)",
"volume": "Volume",
"aht": "AHT",
"cv": "CV",
"transfer": "Transfer",
"fcr": "FCR",
"score": "Score",
"tier": "Tier",
"redFlags": "Red Flags",
"savingsPerMonth": "Savings/mo",
"total": "TOTAL",
"skill": "Skill",
"queues": "Queues",
"avgAht": "Avg AHT",
"avgCv": "Avg CV",
"potentialSavings": "Potential Savings",
"dominantTier": "Dominant Tier",
"perYear": "/year"
},
"summary": {
"queuesAnalyzed": "queues analyzed",
"volumeInIndividualQueues": "of volume is in individual queues",
"balancedDistribution": "Balanced distribution across tiers. Review individual queues for prioritization.",
"clickToExpand": "Click on a skill to see individual queue details"
},
"emptyStates": {
"noQueuesClassifiedAs": "No queues classified as {{tier}}",
"noQueuesMatchFilters": "No queues match the selected filters"
},
"sections": {
"classificationBySkill": "CLASSIFICATION BY SKILL",
"classificationByTier": "CLASSIFICATION BY AUTOMATION TIER",
"queuesAutomate": "Queues AUTOMATE",
"readyForFullAutomation": "Ready for full automation with virtual agent (Score ≥7.5)",
"queuesAssist": "Queues ASSIST",
"candidatesForCopilot": "Candidates for Copilot - AI assists human agent (Score 5.5-7.5)",
"queuesAugment": "Queues AUGMENT",
"requireOptimization": "Require prior optimization: standardize processes, reduce variability (Score 3.5-5.5)",
"queuesHumanOnly": "Queues HUMAN-ONLY",
"notSuitableForAutomation": "Not suitable for automation: insufficient volume, low data quality, or extreme complexity",
"queuesIn": "queues in {{count}} skills",
"costPerYear": "/year",
"volumeColon": "Volume:",
"costColon": "Cost:",
"potentialSavingsColon": "Potential savings:"
} }
}, },
"economicModel": { "economicModel": {

View File

@@ -686,9 +686,13 @@
"legendRisk": "= Riesgo" "legendRisk": "= Riesgo"
}, },
"comparison": { "comparison": {
"title": "Escenarios de Inversión",
"subtitle": "Comparación de opciones según nivel de compromiso",
"tooltip": "ROI basado en benchmarks de industria. El ROI ajustado considera factores de riesgo de implementación.",
"investment": "Inversión", "investment": "Inversión",
"recurring": "Recurrente", "recurring": "Recurrente",
"savings": "Ahorro", "savings": "Ahorro",
"adjusted": "ajustado",
"margin": "Margen", "margin": "Margen",
"payback": "Payback", "payback": "Payback",
"roi3y": "ROI 3a", "roi3y": "ROI 3a",
@@ -697,7 +701,18 @@
"recommendation": "Recomendación", "recommendation": "Recomendación",
"recommendationEnabler": "Recomendación (Habilitador)", "recommendationEnabler": "Recomendación (Habilitador)",
"enabler": "Habilitador", "enabler": "Habilitador",
"recommended": "Recomendado" "recommended": "Recomendado",
"savingsPerYear": "Ahorro/año",
"marginPerYear": "Margen/año",
"savingsLabel": "Ahorro:",
"conditional": "Condicional",
"riskLow": "Bajo",
"riskMedium": "Medio",
"riskHigh": "Alto",
"enablerWaveTooltip": "Wave habilitadora - su valor está en desbloquear waves posteriores",
"negativeMarginTooltip": "Margen anual negativo",
"projectedRoiTooltip": "ROI proyectado. Validar con piloto.",
"adjustedRoiTooltip": "ROI ajustado por riesgo de implementación"
}, },
"entryCriteria": { "entryCriteria": {
"wave1TierFrom": "HUMAN-ONLY (4), AUGMENT (3)", "wave1TierFrom": "HUMAN-ONLY (4), AUGMENT (3)",
@@ -945,10 +960,17 @@
"strategicSkill": "Queue Skill (Estratégico)", "strategicSkill": "Queue Skill (Estratégico)",
"volume": "Volumen", "volume": "Volumen",
"volumePerMonth": "int/mes", "volumePerMonth": "int/mes",
"aht": "AHT",
"cv": "CV",
"fcr": "FCR",
"ahtAvg": "AHT Prom.", "ahtAvg": "AHT Prom.",
"cvAvg": "CV Prom.", "cvAvg": "CV Prom.",
"avgAht": "AHT Prom.",
"avgCv": "CV Prom.",
"savingsPotential": "Ahorro Potencial", "savingsPotential": "Ahorro Potencial",
"potentialSavings": "Ahorro Potencial",
"dominantTier": "Tier Dom.", "dominantTier": "Tier Dom.",
"tier": "Tier",
"transfer": "Transfer", "transfer": "Transfer",
"redFlags": "Red Flags", "redFlags": "Red Flags",
"savingsPerMonth": "Ahorro/mes", "savingsPerMonth": "Ahorro/mes",
@@ -970,6 +992,9 @@
"tierAutoAssist": "(Tier AUTOMATE + ASSIST)", "tierAutoAssist": "(Tier AUTOMATE + ASSIST)",
"interactions": "interacciones", "interactions": "interacciones",
"queuesAnalyzed": "colas analizadas", "queuesAnalyzed": "colas analizadas",
"volumeInIndividualQueues": "del volumen está en colas individuales",
"balancedDistribution": "Distribución equilibrada entre tiers. Revisar colas individuales para priorización.",
"clickToExpand": "Click en un skill para ver el detalle de colas individuales",
"interpretation": "Interpretación:", "interpretation": "Interpretación:",
"interpretationText": "El {{pct}}% representa el volumen de interacciones automatizables (AUTOMATE + ASSIST). Solo el {{queuePct}}% de las colas ({{count}} de {{total}}) son AUTOMATE, pero concentran {{volumePct}}% del volumen total. Esto indica pocas colas de alto volumen automatizables - oportunidad concentrada en Quick Wins de alto impacto.", "interpretationText": "El {{pct}}% representa el volumen de interacciones automatizables (AUTOMATE + ASSIST). Solo el {{queuePct}}% de las colas ({{count}} de {{total}}) son AUTOMATE, pero concentran {{volumePct}}% del volumen total. Esto indica pocas colas de alto volumen automatizables - oportunidad concentrada en Quick Wins de alto impacto.",
"inSkills": "en {{count}} skills", "inSkills": "en {{count}} skills",
@@ -984,6 +1009,27 @@
"activeFilters": "Filtros activos:", "activeFilters": "Filtros activos:",
"of": "de" "of": "de"
}, },
"emptyStates": {
"noQueuesClassifiedAs": "No hay colas clasificadas como {{tier}}",
"noQueuesMatchFilters": "No hay colas que cumplan los filtros seleccionados"
},
"sections": {
"classificationBySkill": "CLASIFICACIÓN POR SKILL",
"classificationByTier": "CLASIFICACIÓN POR TIER DE AUTOMATIZACIÓN",
"queuesAutomate": "Colas AUTOMATE",
"readyForFullAutomation": "Listas para automatización completa con agente virtual (Score ≥7.5)",
"queuesAssist": "Colas ASSIST",
"candidatesForCopilot": "Candidatas a Copilot - IA asiste al agente humano (Score 5.5-7.5)",
"queuesAugment": "Colas AUGMENT",
"requireOptimization": "Requieren optimización previa: estandarizar procesos, reducir variabilidad (Score 3.5-5.5)",
"queuesHumanOnly": "Colas HUMAN-ONLY",
"notSuitableForAutomation": "No aptas para automatización: volumen insuficiente, calidad de datos baja o complejidad extrema",
"queuesIn": "colas en {{count}} skills",
"costPerYear": "/año",
"volumeColon": "Volumen:",
"costColon": "Coste:",
"potentialSavingsColon": "Ahorro potencial:"
},
"opportunityMap": { "opportunityMap": {
"title": "Mapa de Oportunidades", "title": "Mapa de Oportunidades",
"subtitle": "Tamaño = Volumen · Color = Tier · Posición = Score vs Ahorro TCO", "subtitle": "Tamaño = Volumen · Color = Tier · Posición = Score vs Ahorro TCO",