2025-07-03 11:44:10 -03:00
|
|
|
import { Box, CircularProgress, Alert, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Button } from '@mui/material';
|
|
|
|
|
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
2025-07-15 15:20:36 -03:00
|
|
|
|
|
|
|
|
// Importaciones de nuestro proyecto
|
2025-07-03 11:44:10 -03:00
|
|
|
import { useApiData } from '../../hooks/useApiData';
|
2025-07-15 15:20:36 -03:00
|
|
|
import { useIsHoliday } from '../../hooks/useIsHoliday';
|
2025-07-03 11:44:10 -03:00
|
|
|
import type { CotizacionBolsa } from '../../models/mercadoModels';
|
|
|
|
|
import { formatCurrency, formatFullDateTime } from '../../utils/formatters';
|
|
|
|
|
import { copyToClipboard } from '../../utils/clipboardUtils';
|
2025-07-15 15:20:36 -03:00
|
|
|
import { HolidayAlert } from '../common/HolidayAlert';
|
2025-07-03 11:44:10 -03:00
|
|
|
|
2025-07-15 15:20:36 -03:00
|
|
|
/**
|
|
|
|
|
* Función para convertir los datos de la tabla a formato CSV.
|
|
|
|
|
*/
|
2025-07-03 11:44:10 -03:00
|
|
|
const toCSV = (headers: string[], data: CotizacionBolsa[]) => {
|
|
|
|
|
const headerRow = headers.join(';');
|
|
|
|
|
const dataRows = data.map(row =>
|
|
|
|
|
[
|
|
|
|
|
row.ticker,
|
|
|
|
|
row.nombreEmpresa,
|
|
|
|
|
formatCurrency(row.precioActual),
|
|
|
|
|
formatCurrency(row.cierreAnterior),
|
2025-07-15 15:20:36 -03:00
|
|
|
`${row.porcentajeCambio.toFixed(2)}%`,
|
|
|
|
|
formatFullDateTime(row.fechaRegistro)
|
2025-07-03 11:44:10 -03:00
|
|
|
].join(';')
|
|
|
|
|
);
|
|
|
|
|
return [headerRow, ...dataRows].join('\n');
|
|
|
|
|
};
|
|
|
|
|
|
2025-07-15 15:20:36 -03:00
|
|
|
/**
|
|
|
|
|
* Componente de tabla de datos crudos para la Bolsa Local (MERVAL y acciones),
|
|
|
|
|
* diseñado para la página de redacción.
|
|
|
|
|
*/
|
2025-07-03 11:44:10 -03:00
|
|
|
export const RawBolsaLocalTable = () => {
|
2025-07-15 15:20:36 -03:00
|
|
|
// Hooks para obtener los datos y el estado de feriado.
|
|
|
|
|
const { data, loading: dataLoading, error: dataError } = useApiData<CotizacionBolsa[]>('/mercados/bolsa/local');
|
|
|
|
|
const isHoliday = useIsHoliday('BA');
|
2025-07-03 11:44:10 -03:00
|
|
|
|
|
|
|
|
const handleCopy = () => {
|
|
|
|
|
if (!data) return;
|
2025-07-15 15:20:36 -03:00
|
|
|
const headers = ["Ticker", "Nombre", "Último Precio", "Cierre Anterior", "Variación %", "Fecha de Registro"];
|
2025-07-03 11:44:10 -03:00
|
|
|
const csvData = toCSV(headers, data);
|
|
|
|
|
|
|
|
|
|
copyToClipboard(csvData)
|
2025-07-15 15:20:36 -03:00
|
|
|
.then(() => alert('¡Tabla copiada al portapapeles!'))
|
2025-07-03 11:44:10 -03:00
|
|
|
.catch(err => {
|
|
|
|
|
console.error('Error al copiar:', err);
|
|
|
|
|
alert('Error: No se pudo copiar la tabla.');
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2025-07-15 15:20:36 -03:00
|
|
|
// Estado de carga unificado.
|
|
|
|
|
const isLoading = dataLoading || isHoliday === null;
|
|
|
|
|
|
|
|
|
|
if (isLoading) return <CircularProgress />;
|
|
|
|
|
if (dataError) return <Alert severity="error">{dataError}</Alert>;
|
|
|
|
|
|
|
|
|
|
if (!data || data.length === 0) {
|
|
|
|
|
if (isHoliday) {
|
|
|
|
|
return <HolidayAlert />;
|
|
|
|
|
}
|
|
|
|
|
return <Alert severity="info">No hay datos disponibles para el mercado local.</Alert>;
|
|
|
|
|
}
|
2025-07-03 11:44:10 -03:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Box>
|
2025-07-15 15:20:36 -03:00
|
|
|
{/* Si es feriado, mostramos una alerta informativa encima de la tabla. */}
|
|
|
|
|
{isHoliday && (
|
|
|
|
|
<Box sx={{ mb: 2 }}>
|
|
|
|
|
<HolidayAlert />
|
|
|
|
|
</Box>
|
|
|
|
|
)}
|
|
|
|
|
|
2025-07-03 11:44:10 -03:00
|
|
|
<Button startIcon={<ContentCopyIcon />} onClick={handleCopy} sx={{ mb: 1 }}>
|
|
|
|
|
Copiar como CSV
|
|
|
|
|
</Button>
|
|
|
|
|
<TableContainer component={Paper}>
|
|
|
|
|
<Table size="small">
|
|
|
|
|
<TableHead>
|
|
|
|
|
<TableRow>
|
|
|
|
|
<TableCell>Ticker</TableCell>
|
|
|
|
|
<TableCell>Nombre</TableCell>
|
|
|
|
|
<TableCell align="right">Último Precio</TableCell>
|
|
|
|
|
<TableCell align="right">Cierre Anterior</TableCell>
|
|
|
|
|
<TableCell align="right">Variación %</TableCell>
|
|
|
|
|
<TableCell>Última Act.</TableCell>
|
|
|
|
|
</TableRow>
|
|
|
|
|
</TableHead>
|
|
|
|
|
<TableBody>
|
|
|
|
|
{data.map(row => (
|
|
|
|
|
<TableRow key={row.id}>
|
|
|
|
|
<TableCell>{row.ticker}</TableCell>
|
|
|
|
|
<TableCell>{row.nombreEmpresa}</TableCell>
|
|
|
|
|
<TableCell align="right">${formatCurrency(row.precioActual)}</TableCell>
|
|
|
|
|
<TableCell align="right">${formatCurrency(row.cierreAnterior)}</TableCell>
|
|
|
|
|
<TableCell align="right">{row.porcentajeCambio.toFixed(2)}%</TableCell>
|
|
|
|
|
<TableCell>{formatFullDateTime(row.fechaRegistro)}</TableCell>
|
|
|
|
|
</TableRow>
|
|
|
|
|
))}
|
|
|
|
|
</TableBody>
|
|
|
|
|
</Table>
|
|
|
|
|
</TableContainer>
|
|
|
|
|
</Box>
|
|
|
|
|
);
|
|
|
|
|
};
|