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 type { CotizacionBolsa } from '../models/mercadoModels';
|
||||||
import { useApiData } from '../hooks/useApiData';
|
import { useApiData } from '../hooks/useApiData';
|
||||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
|
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
|
||||||
import { formatFullDateTime } from '../utils/formatters';
|
import { formatFullDateTime, formatCurrency2Decimal } from '../utils/formatters';
|
||||||
|
|
||||||
interface HistoricalChartWidgetProps {
|
interface HistoricalChartWidgetProps {
|
||||||
ticker: string;
|
ticker: string;
|
||||||
@@ -10,6 +10,11 @@ interface HistoricalChartWidgetProps {
|
|||||||
dias: number;
|
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) => {
|
const formatTooltipLabel = (label: string) => {
|
||||||
return formatFullDateTime(label);
|
return formatFullDateTime(label);
|
||||||
};
|
};
|
||||||
@@ -23,16 +28,25 @@ export const HistoricalChartWidget = ({ ticker, mercado, dias }: HistoricalChart
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
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) {
|
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
|
// 1. Calcular el dominio del eje Y con un margen
|
||||||
const formatXAxis = (tickItem: string) => {
|
const prices = data.map(p => p.precioActual);
|
||||||
return new Date(tickItem).toLocaleDateString('es-AR', { day: '2-digit', month: '2-digit' });
|
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 (
|
return (
|
||||||
@@ -40,13 +54,17 @@ export const HistoricalChartWidget = ({ ticker, mercado, dias }: HistoricalChart
|
|||||||
<LineChart data={data} margin={{ top: 5, right: 30, left: 20, bottom: 5 }}>
|
<LineChart data={data} margin={{ top: 5, right: 30, left: 20, bottom: 5 }}>
|
||||||
<CartesianGrid strokeDasharray="3 3" />
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
<XAxis dataKey="fechaRegistro" tickFormatter={formatXAxis} />
|
<XAxis dataKey="fechaRegistro" tickFormatter={formatXAxis} />
|
||||||
<YAxis domain={['dataMin - dataMin * 0.02', 'dataMax + dataMax * 0.02']} tickFormatter={(tick) => `$${tick.toLocaleString('es-AR')}`} />
|
<YAxis
|
||||||
<Tooltip
|
domain={[domainMin, domainMax]}
|
||||||
formatter={(value: number) => [`$${value.toFixed(2)}`, 'Precio']}
|
tickFormatter={yAxisTickFormatter}
|
||||||
labelFormatter={formatTooltipLabel}
|
width={80} // Damos un poco más de espacio para números grandes
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
formatter={(value: number) => [`$${formatCurrency2Decimal(value)}`, 'Precio']}
|
||||||
|
labelFormatter={formatTooltipLabel}
|
||||||
/>
|
/>
|
||||||
<Legend />
|
<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>
|
</LineChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
|
|||||||
import RemoveIcon from '@mui/icons-material/Remove';
|
import RemoveIcon from '@mui/icons-material/Remove';
|
||||||
|
|
||||||
import type { CotizacionBolsa } from '../models/mercadoModels';
|
import type { CotizacionBolsa } from '../models/mercadoModels';
|
||||||
import { formatInteger, formatCurrency } from '../utils/formatters';
|
import { formatInteger, formatCurrency, formatCurrency2Decimal } from '../utils/formatters';
|
||||||
import { HistoricalChartWidget } from './HistoricalChartWidget';
|
import { HistoricalChartWidget } from './HistoricalChartWidget';
|
||||||
import { useApiData } from '../hooks/useApiData';
|
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 sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', mb: 2 }}>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="h5" component="h2" sx={{ fontWeight: 'bold' }}>Índice S&P MERVAL</Typography>
|
<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>
|
||||||
<Box sx={{ pt: 2 }}>
|
<Box sx={{ pt: 2 }}>
|
||||||
<VariacionMerval actual={mervalData.precioActual} anterior={mervalData.cierreAnterior} />
|
<VariacionMerval actual={mervalData.precioActual} anterior={mervalData.cierreAnterior} />
|
||||||
|
|||||||
@@ -11,6 +11,18 @@ export const formatCurrency = (num: number, currency = 'ARS') => {
|
|||||||
}).format(num);
|
}).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) => {
|
export const formatInteger = (num: number) => {
|
||||||
return new Intl.NumberFormat('es-AR').format(num);
|
return new Intl.NumberFormat('es-AR').format(num);
|
||||||
};
|
};
|
||||||
@@ -23,7 +35,7 @@ export const formatFullDateTime = (dateString: string) => {
|
|||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
hourCycle: 'h23', // <--- LA CLAVE PARA EL FORMATO 24HS
|
hourCycle: 'h23',
|
||||||
timeZone: 'America/Argentina/Buenos_Aires',
|
timeZone: 'America/Argentina/Buenos_Aires',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user