first commit

This commit is contained in:
Urtzi Alfaro
2025-07-17 13:54:51 +02:00
parent 347ff51bd7
commit 5bb3e93da4
41 changed files with 10084 additions and 94 deletions

View File

@@ -0,0 +1,166 @@
// ForecastChart.tsx (Modified)
import React from 'react';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
Filler,
} from 'chart.js';
import { Line } from 'react-chartjs-2';
import { format } from 'date-fns';
import { es } from 'date-fns/locale';
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
Filler
);
interface ForecastData {
date: string;
predicted_quantity: number;
confidence_lower: number;
confidence_upper: number;
actual_quantity?: number;
}
interface ForecastChartProps {
data: ForecastData[];
productName: string;
// height?: number; // Removed fixed height prop
}
const ForecastChart: React.FC<ForecastChartProps> = ({ data, productName /*, height = 400*/ }) => { // Removed height from props
const chartData = {
labels: data.map(d => format(new Date(d.date), 'dd MMM', { locale: es })),
datasets: [
{
label: 'Predicción',
data: data.map(d => d.predicted_quantity),
borderColor: 'rgb(59, 130, 246)',
backgroundColor: 'rgba(59, 130, 246, 0.1)',
borderWidth: 2,
tension: 0.1,
pointRadius: 4,
pointHoverRadius: 6,
fill: true,
},
{
label: 'Intervalo Inferior',
data: data.map(d => d.confidence_lower),
borderColor: 'rgba(59, 130, 246, 0.3)',
backgroundColor: 'transparent',
borderDash: [5, 5],
pointRadius: 0,
tension: 0.1,
},
{
label: 'Intervalo Superior',
data: data.map(d => d.confidence_upper),
borderColor: 'rgba(59, 130, 246, 0.3)',
backgroundColor: 'transparent',
borderDash: [5, 5],
pointRadius: 0,
tension: 0.1,
},
// Optional: Actual quantity if available
...(data[0]?.actual_quantity !== undefined && data.some(d => d.actual_quantity !== undefined) ? [{
label: 'Real',
data: data.map(d => d.actual_quantity),
borderColor: 'rgb(255, 99, 132)',
backgroundColor: 'rgba(255, 99, 132, 0.1)',
borderWidth: 2,
tension: 0.1,
pointRadius: 4,
pointHoverRadius: 6,
hidden: true, // Initially hidden, can be toggled
}] : []),
],
};
const chartOptions = {
responsive: true,
maintainAspectRatio: false, // Ensures the chart fills its parent container's dimensions
plugins: {
legend: {
position: 'top' as const,
labels: {
font: {
size: 12,
},
},
},
title: {
display: true,
text: `Predicción de Demanda - ${productName}`,
font: {
size: 16,
weight: 'bold' as const,
},
padding: {
bottom: 20,
},
},
tooltip: {
mode: 'index' as const,
intersect: false,
callbacks: {
label: function(context: any) {
const label = context.dataset.label || '';
const value = context.parsed.y;
if (value !== null && value !== undefined) {
return `${label}: ${Math.round(value)} unidades`;
}
return '';
},
},
},
},
scales: {
x: {
grid: {
display: false,
},
title: {
display: true,
text: 'Fecha',
font: {
size: 14,
},
},
},
y: {
beginAtZero: true,
grid: {
color: 'rgba(0, 0, 0, 0.05)',
},
title: {
display: true,
text: 'Cantidad (unidades)',
font: {
size: 14,
},
},
},
},
interaction: {
mode: 'nearest' as const,
axis: 'x' as const,
intersect: false,
},
};
return <Line data={chartData} options={chartOptions} />;
};
export default ForecastChart;