Feat: Currency 2 Decimal Format - Fix: Charts Scale
This commit is contained in:
		| @@ -2,7 +2,7 @@ import { Box, CircularProgress, Alert } from '@mui/material'; | ||||
| import type { CotizacionBolsa } from '../models/mercadoModels'; | ||||
| import { useApiData } from '../hooks/useApiData'; | ||||
| import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'; | ||||
| import { formatFullDateTime } from '../utils/formatters'; | ||||
| import { formatFullDateTime, formatCurrency2Decimal } from '../utils/formatters'; | ||||
|  | ||||
| interface HistoricalChartWidgetProps { | ||||
|     ticker: string; | ||||
| @@ -10,6 +10,11 @@ interface HistoricalChartWidgetProps { | ||||
|     dias: number; | ||||
| } | ||||
|  | ||||
| // Formateador para el eje X que solo muestra día/mes | ||||
| const formatXAxis = (tickItem: string) => { | ||||
|     return new Date(tickItem).toLocaleDateString('es-AR', { day: '2-digit', month: '2-digit' }); | ||||
| }; | ||||
|  | ||||
| const formatTooltipLabel = (label: string) => { | ||||
|     return formatFullDateTime(label); | ||||
| }; | ||||
| @@ -23,16 +28,25 @@ export const HistoricalChartWidget = ({ ticker, mercado, dias }: HistoricalChart | ||||
|     } | ||||
|  | ||||
|     if (error) { | ||||
|         return <Alert severity="error" sx={{height: 300}}>{error}</Alert>; | ||||
|         return <Alert severity="error" sx={{ height: 300 }}>{error}</Alert>; | ||||
|     } | ||||
|  | ||||
|     if (!data || data.length < 2) { | ||||
|         return <Alert severity="info" sx={{height: 300}}>No hay suficientes datos históricos para graficar.</Alert>; | ||||
|         return <Alert severity="info" sx={{ height: 300 }}>No hay suficientes datos históricos para graficar.</Alert>; | ||||
|     } | ||||
|  | ||||
|     // Formateador para el eje X que solo muestra día/mes | ||||
|     const formatXAxis = (tickItem: string) => { | ||||
|         return new Date(tickItem).toLocaleDateString('es-AR', { day: '2-digit', month: '2-digit' }); | ||||
|     // 1. Calcular el dominio del eje Y con un margen | ||||
|     const prices = data.map(p => p.precioActual); | ||||
|     const dataMin = Math.min(...prices); | ||||
|     const dataMax = Math.max(...prices); | ||||
|     const padding = (dataMax - dataMin) * 0.05; // 5% de padding | ||||
|     const domainMin = Math.floor(dataMin - padding); | ||||
|     const domainMax = Math.ceil(dataMax + padding); | ||||
|  | ||||
|     // 2. Formateador de ticks para el eje Y más robusto | ||||
|     const yAxisTickFormatter = (tick: number) => { | ||||
|         // Usamos el formateador de moneda | ||||
|         return `$${formatCurrency2Decimal(tick)}`; | ||||
|     }; | ||||
|  | ||||
|     return ( | ||||
| @@ -40,13 +54,17 @@ export const HistoricalChartWidget = ({ ticker, mercado, dias }: HistoricalChart | ||||
|             <LineChart data={data} margin={{ top: 5, right: 30, left: 20, bottom: 5 }}> | ||||
|                 <CartesianGrid strokeDasharray="3 3" /> | ||||
|                 <XAxis dataKey="fechaRegistro" tickFormatter={formatXAxis} /> | ||||
|                 <YAxis domain={['dataMin - dataMin * 0.02', 'dataMax + dataMax * 0.02']} tickFormatter={(tick) => `$${tick.toLocaleString('es-AR')}`} /> | ||||
|                 <Tooltip  | ||||
|                     formatter={(value: number) => [`$${value.toFixed(2)}`, 'Precio']}  | ||||
|                     labelFormatter={formatTooltipLabel}  | ||||
|                 <YAxis | ||||
|                     domain={[domainMin, domainMax]} | ||||
|                     tickFormatter={yAxisTickFormatter} | ||||
|                     width={80} // Damos un poco más de espacio para números grandes | ||||
|                 /> | ||||
|                 <Tooltip | ||||
|                     formatter={(value: number) => [`$${formatCurrency2Decimal(value)}`, 'Precio']} | ||||
|                     labelFormatter={formatTooltipLabel} | ||||
|                 /> | ||||
|                 <Legend /> | ||||
|                 <Line type="monotone" dataKey="precioActual" name="Precio de Cierre" stroke="#028fbe" strokeWidth={2} dot={false} /> | ||||
|                 <Line type="monotone" dataKey="precioActual" name="Precio de Cierre" stroke="#8884d8" strokeWidth={2} dot={false} /> | ||||
|             </LineChart> | ||||
|         </ResponsiveContainer> | ||||
|     ); | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'; | ||||
| import RemoveIcon from '@mui/icons-material/Remove'; | ||||
|  | ||||
| import type { CotizacionBolsa } from '../models/mercadoModels'; | ||||
| import { formatInteger, formatCurrency } from '../utils/formatters'; | ||||
| import { formatInteger, formatCurrency, formatCurrency2Decimal } from '../utils/formatters'; | ||||
| import { HistoricalChartWidget } from './HistoricalChartWidget'; | ||||
| import { useApiData } from '../hooks/useApiData'; | ||||
|  | ||||
| @@ -53,7 +53,7 @@ export const MervalHeroCard = () => { | ||||
|             <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', mb: 2 }}> | ||||
|                 <Box> | ||||
|                     <Typography variant="h5" component="h2" sx={{ fontWeight: 'bold' }}>Índice S&P MERVAL</Typography> | ||||
|                     <Typography variant="h3" component="p" sx={{ fontWeight: 'bold', mt:1 }}>{formatInteger(mervalData.precioActual)}</Typography> | ||||
|                     <Typography variant="h3" component="p" sx={{ fontWeight: 'bold', mt:1 }}>{formatCurrency2Decimal(mervalData.precioActual)}</Typography> | ||||
|                 </Box> | ||||
|                 <Box sx={{ pt: 2 }}> | ||||
|                     <VariacionMerval actual={mervalData.precioActual} anterior={mervalData.cierreAnterior} /> | ||||
|   | ||||
| @@ -11,6 +11,18 @@ export const formatCurrency = (num: number, currency = 'ARS') => { | ||||
|   }).format(num); | ||||
| }; | ||||
|  | ||||
| export const formatCurrency2Decimal = (num: number, currency = 'ARS') => { | ||||
|   const style = currency === 'USD' ? 'currency' : 'decimal'; | ||||
|   const locale = currency === 'USD' ? 'en-US' : 'es-AR'; | ||||
|    | ||||
|   return new Intl.NumberFormat(locale, { | ||||
|     style: style, | ||||
|     currency: currency, | ||||
|     minimumFractionDigits: 2, | ||||
|     maximumFractionDigits: 2, | ||||
|   }).format(num); | ||||
| }; | ||||
|  | ||||
| export const formatInteger = (num: number) => { | ||||
|   return new Intl.NumberFormat('es-AR').format(num); | ||||
| }; | ||||
| @@ -23,7 +35,7 @@ export const formatFullDateTime = (dateString: string) => { | ||||
|     year: 'numeric', | ||||
|     hour: '2-digit', | ||||
|     minute: '2-digit', | ||||
|     hourCycle: 'h23', // <--- LA CLAVE PARA EL FORMATO 24HS | ||||
|     hourCycle: 'h23', | ||||
|     timeZone: 'America/Argentina/Buenos_Aires', | ||||
|   }); | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user