feat: Rediseño dashboard con 4 pestañas estilo McKinsey

- Nueva estructura de tabs: Resumen, Dimensiones, Agentic Readiness, Roadmap
- Componentes de visualización McKinsey:
  - BulletChart: actual vs benchmark con rangos de color
  - WaterfallChart: impacto económico con costes y ahorros
  - OpportunityTreemap: priorización por volumen y readiness
- 5 dimensiones actualizadas (sin satisfaction ni economy)
- Header sticky con navegación animada
- Integración completa con datos existentes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Susana
2026-01-12 08:41:20 +00:00
parent fdfb520710
commit 7e24f4eb31
17 changed files with 2282 additions and 389 deletions

View File

@@ -4,7 +4,7 @@
import type { AnalysisData, Kpi, DimensionAnalysis, HeatmapDataPoint, Opportunity, RoadmapInitiative, EconomicModelData, BenchmarkDataPoint, Finding, Recommendation, TierKey, CustomerSegment, RawInteraction, AgenticReadinessResult, SubFactor, SkillMetrics } from '../types';
import { RoadmapPhase } from '../types';
import { BarChartHorizontal, Zap, Smile, DollarSign, Target, Globe } from 'lucide-react';
import { BarChartHorizontal, Zap, Target, Brain, Bot } from 'lucide-react';
import { calculateAgenticReadinessScore, type AgenticReadinessInput } from './agenticReadinessV2';
import { classifyQueue } from './segmentClassifier';
@@ -287,7 +287,7 @@ function calculateHealthScore(heatmapData: HeatmapDataPoint[]): number {
}
/**
* Generar dimensiones desde datos reales
* v3.0: Generar 5 dimensiones viables desde datos reales
*/
function generateDimensionsFromRealData(
interactions: RawInteraction[],
@@ -298,69 +298,72 @@ function generateDimensionsFromRealData(
const totalVolume = interactions.length;
const avgCV = metrics.reduce((sum, m) => sum + m.cv_aht, 0) / metrics.length;
const avgTransferRate = metrics.reduce((sum, m) => sum + m.transfer_rate, 0) / metrics.length;
const avgHoldTime = metrics.reduce((sum, m) => sum + m.hold_time_mean, 0) / metrics.length;
// Calcular ratio P90/P50 aproximado desde CV
const avgRatio = 1 + avgCV * 1.5; // Aproximación: ratio ≈ 1 + 1.5*CV
// Calcular Agentic Score
const predictability = Math.max(0, Math.min(10, 10 - ((avgCV - 0.3) / 1.2 * 10)));
const complexityInverse = Math.max(0, Math.min(10, 10 - (avgTransferRate / 10)));
const repetitivity = Math.min(10, totalVolume / 500);
const agenticScore = predictability * 0.30 + complexityInverse * 0.30 + repetitivity * 0.25 + 2.5;
return [
// 1. VOLUMETRÍA & DISTRIBUCIÓN
{
id: 'volumetry_distribution',
name: 'volumetry_distribution',
title: 'Análisis de la Demanda',
score: Math.min(100, Math.round((totalVolume / 200))), // Score basado en volumen
title: 'Volumetría & Distribución',
score: Math.min(100, Math.round((totalVolume / 200))),
percentile: 65,
summary: `Se procesaron ${totalVolume.toLocaleString('es-ES')} interacciones distribuidas en ${metrics.length} skills diferentes.`,
summary: `${totalVolume.toLocaleString('es-ES')} interacciones en ${metrics.length} colas. Distribución por skill disponible en el heatmap.`,
kpi: { label: 'Volumen Total', value: totalVolume.toLocaleString('es-ES') },
icon: BarChartHorizontal
},
// 2. EFICIENCIA OPERATIVA
{
id: 'performance',
name: 'performance',
title: 'Rendimiento Operativo',
score: Math.round(100 - (avgCV * 100)),
id: 'operational_efficiency',
name: 'operational_efficiency',
title: 'Eficiencia Operativa',
score: Math.max(0, Math.min(100, Math.round(100 - (avgRatio - 1) * 50))),
percentile: 70,
summary: avgCV < 0.4
? 'El AHT muestra baja variabilidad, indicando procesos estandarizados.'
: 'La variabilidad del AHT es alta, sugiriendo inconsistencia en procesos.',
kpi: { label: 'AHT Promedio', value: `${avgAHT}s` },
summary: `AHT P50: ${avgAHT}s. Ratio P90/P50 estimado: ${avgRatio.toFixed(2)}. Hold time promedio: ${Math.round(avgHoldTime)}s.`,
kpi: { label: 'Ratio P90/P50', value: avgRatio.toFixed(2) },
icon: Zap
},
// 3. EFECTIVIDAD & RESOLUCIÓN
{
id: 'satisfaction',
name: 'satisfaction',
title: 'Voz del Cliente',
score: avgCsat,
percentile: 60,
summary: `CSAT promedio de ${(avgCsat / 20).toFixed(1)}/5.`,
kpi: { label: 'CSAT', value: `${(avgCsat / 20).toFixed(1)}/5` },
icon: Smile
},
{
id: 'economy',
name: 'economy',
title: 'Rentabilidad del Servicio',
score: Math.round(100 - avgTransferRate),
percentile: 55,
summary: `Tasa de transferencia del ${avgTransferRate.toFixed(1)}%.`,
kpi: { label: 'Transfer Rate', value: `${avgTransferRate.toFixed(1)}%` },
icon: DollarSign
},
{
id: 'efficiency',
name: 'efficiency',
title: 'Resolución y Calidad',
id: 'effectiveness_resolution',
name: 'effectiveness_resolution',
title: 'Efectividad & Resolución',
score: Math.round(100 - avgTransferRate),
percentile: 68,
summary: `FCR estimado del ${(100 - avgTransferRate).toFixed(1)}%.`,
kpi: { label: 'FCR', value: `${(100 - avgTransferRate).toFixed(1)}%` },
summary: `FCR proxy: ${(100 - avgTransferRate).toFixed(1)}%. Tasa de transferencias: ${avgTransferRate.toFixed(1)}%.`,
kpi: { label: 'FCR Proxy', value: `${(100 - avgTransferRate).toFixed(1)}%` },
icon: Target
},
// 4. COMPLEJIDAD & PREDICTIBILIDAD
{
id: 'benchmark',
name: 'benchmark',
title: 'Contexto Competitivo',
score: 75,
id: 'complexity_predictability',
name: 'complexity_predictability',
title: 'Complejidad & Predictibilidad',
score: Math.round(100 - (avgCV * 100)),
percentile: 60,
summary: `CV AHT: ${(avgCV * 100).toFixed(1)}%. % transferencias: ${avgTransferRate.toFixed(1)}%. ${avgCV < 0.4 ? 'Proceso predecible.' : 'Alta variabilidad, considerar estandarización.'}`,
kpi: { label: 'CV AHT', value: `${(avgCV * 100).toFixed(1)}%` },
icon: Brain
},
// 5. AGENTIC READINESS
{
id: 'agentic_readiness',
name: 'agentic_readiness',
title: 'Agentic Readiness',
score: Math.round(agenticScore * 10),
percentile: 65,
summary: 'Métricas alineadas con benchmarks de la industria.',
kpi: { label: 'Benchmark', value: 'P65' },
icon: Globe
summary: `Score: ${agenticScore.toFixed(1)}/10. ${agenticScore >= 8 ? 'Excelente para automatización.' : agenticScore >= 5 ? 'Candidato para asistencia IA.' : 'Requiere optimización previa.'}`,
kpi: { label: 'Score', value: `${agenticScore.toFixed(1)}/10` },
icon: Bot
}
];
}