Files
BeyondCXAnalytics_AE/frontend/components/EconomicModelEnhanced.tsx
2025-12-29 18:12:32 +01:00

233 lines
9.3 KiB
TypeScript

import React from 'react';
import { motion } from 'framer-motion';
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell } from 'recharts';
import { EconomicModelData } from '../types';
import { DollarSign, TrendingDown, Calendar, TrendingUp } from 'lucide-react';
import CountUp from 'react-countup';
import MethodologyFooter from './MethodologyFooter';
interface EconomicModelEnhancedProps {
data: EconomicModelData;
}
const EconomicModelEnhanced: React.FC<EconomicModelEnhancedProps> = ({ data }) => {
const {
currentAnnualCost,
futureAnnualCost,
annualSavings,
initialInvestment,
paybackMonths,
roi3yr,
} = data;
// Data for comparison chart
const comparisonData = [
{
name: 'Coste Actual',
value: currentAnnualCost,
color: '#ef4444',
},
{
name: 'Coste Futuro',
value: futureAnnualCost,
color: '#10b981',
},
];
// Data for savings breakdown (example)
const savingsBreakdown = [
{ category: 'Automatización', amount: annualSavings * 0.45, percentage: 45 },
{ category: 'Eficiencia', amount: annualSavings * 0.30, percentage: 30 },
{ category: 'Reducción AHT', amount: annualSavings * 0.15, percentage: 15 },
{ category: 'Otros', amount: annualSavings * 0.10, percentage: 10 },
];
const CustomTooltip = ({ active, payload }: any) => {
if (active && payload && payload.length) {
return (
<div className="bg-slate-900 text-white px-3 py-2 rounded-lg shadow-lg text-sm">
<p className="font-semibold">{payload[0].payload.name}</p>
<p className="text-green-400">{payload[0].value.toLocaleString('es-ES')}</p>
</div>
);
}
return null;
};
return (
<div id="economics" className="bg-white p-6 rounded-xl border border-slate-200 shadow-sm">
<h3 className="font-bold text-xl text-slate-800 mb-6">Modelo Económico</h3>
{/* Key Metrics Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
{/* Annual Savings */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 }}
className="bg-gradient-to-br from-green-50 to-emerald-50 p-6 rounded-xl border-2 border-green-200"
>
<div className="flex items-center gap-2 mb-2">
<TrendingDown size={20} className="text-green-600" />
<span className="text-sm font-medium text-green-900">Ahorro Anual</span>
</div>
<div className="text-3xl font-bold text-green-600">
<CountUp end={annualSavings} duration={2} separator="," />
</div>
<div className="text-xs text-green-700 mt-2">
{((annualSavings / currentAnnualCost) * 100).toFixed(1)}% reducción de costes
</div>
</motion.div>
{/* ROI 3 Years */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
className="bg-gradient-to-br from-blue-50 to-indigo-50 p-6 rounded-xl border-2 border-blue-200"
>
<div className="flex items-center gap-2 mb-2">
<TrendingUp size={20} className="text-blue-600" />
<span className="text-sm font-medium text-blue-900">ROI (3 años)</span>
</div>
<div className="text-3xl font-bold text-blue-600">
<CountUp end={roi3yr} duration={2} suffix="x" decimals={1} />
</div>
<div className="text-xs text-blue-700 mt-2">
Retorno sobre inversión
</div>
</motion.div>
{/* Payback Period */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3 }}
className="bg-gradient-to-br from-amber-50 to-orange-50 p-6 rounded-xl border-2 border-amber-200"
>
<div className="flex items-center gap-2 mb-2">
<Calendar size={20} className="text-amber-600" />
<span className="text-sm font-medium text-amber-900">Payback</span>
</div>
<div className="text-3xl font-bold text-amber-600">
<CountUp end={paybackMonths} duration={2} /> m
</div>
<div className="text-xs text-amber-700 mt-2">
Recuperación de inversión
</div>
</motion.div>
{/* Initial Investment */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.4 }}
className="bg-gradient-to-br from-slate-50 to-slate-100 p-6 rounded-xl border-2 border-slate-200"
>
<div className="flex items-center gap-2 mb-2">
<DollarSign size={20} className="text-slate-600" />
<span className="text-sm font-medium text-slate-900">Inversión Inicial</span>
</div>
<div className="text-3xl font-bold text-slate-700">
<CountUp end={initialInvestment} duration={2} separator="," />
</div>
<div className="text-xs text-slate-600 mt-2">
One-time investment
</div>
</motion.div>
</div>
{/* Comparison Chart */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5 }}
className="mb-8"
>
<h4 className="font-semibold text-slate-800 mb-4">Comparación AS-IS vs TO-BE</h4>
<div className="bg-slate-50 p-4 rounded-lg">
<ResponsiveContainer width="100%" height={250}>
<BarChart data={comparisonData}>
<CartesianGrid strokeDasharray="3 3" stroke="#e2e8f0" />
<XAxis dataKey="name" stroke="#64748b" />
<YAxis stroke="#64748b" />
<Tooltip content={<CustomTooltip />} />
<Bar dataKey="value" radius={[8, 8, 0, 0]}>
{comparisonData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Bar>
</BarChart>
</ResponsiveContainer>
</div>
</motion.div>
{/* Savings Breakdown */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.6 }}
>
<h4 className="font-semibold text-slate-800 mb-4">Desglose de Ahorros</h4>
<div className="space-y-3">
{savingsBreakdown.map((item, index) => (
<motion.div
key={item.category}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.7 + index * 0.1 }}
className="bg-slate-50 p-4 rounded-lg"
>
<div className="flex items-center justify-between mb-2">
<span className="font-medium text-slate-700">{item.category}</span>
<span className="font-bold text-slate-900">
{item.amount.toLocaleString('es-ES', { maximumFractionDigits: 0 })}
</span>
</div>
<div className="flex items-center gap-3">
<div className="flex-1 bg-slate-200 rounded-full h-2">
<motion.div
className="bg-green-500 h-2 rounded-full"
initial={{ width: 0 }}
animate={{ width: `${item.percentage}%` }}
transition={{ delay: 0.8 + index * 0.1, duration: 0.8 }}
/>
</div>
<span className="text-sm font-semibold text-slate-600 w-12 text-right">
{item.percentage}%
</span>
</div>
</motion.div>
))}
</div>
</motion.div>
{/* Summary Box */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 1 }}
className="mt-8 bg-gradient-to-r from-blue-600 to-blue-700 p-6 rounded-xl text-white"
>
<h4 className="font-bold text-lg mb-3">Resumen Ejecutivo</h4>
<p className="text-blue-100 text-sm leading-relaxed">
Con una inversión inicial de <span className="font-bold text-white">{initialInvestment.toLocaleString('es-ES')}</span>,
se proyecta un ahorro anual de <span className="font-bold text-white">{annualSavings.toLocaleString('es-ES')}</span>,
recuperando la inversión en <span className="font-bold text-white">{paybackMonths} meses</span> y
generando un ROI de <span className="font-bold text-white">{roi3yr}x</span> en 3 años.
</p>
</motion.div>
{/* Methodology Footer */}
<MethodologyFooter
sources="Datos operacionales internos (2024) | Benchmarks: Gartner, Forrester Research | Costes de software: RFP vendors (Q4 2024)"
methodology="DCF (Discounted Cash Flow) con tasa de descuento 10% | Fully-loaded cost incluye salario, beneficios, overhead | Assumptions conservadoras: 80% adoption rate, 30% automatización"
notes="Desglose de ahorros: Automatización (45%), Eficiencia operativa (30%), Mejora FCR (15%), Reducción attrition (7.5%), Otros (2.5%) | Payback calculado sobre flujo de caja acumulado"
lastUpdated="Enero 2025"
/>
</div>
);
};
export default EconomicModelEnhanced;