feat(UI): Implement holiday awareness across all data widgets
- All data widgets (tables and cards) now use the useIsHoliday hook. - An informational alert is displayed on holidays, without hiding the last available data. - Unifies loading state logic to wait for both data and holiday status, preventing race conditions. - Ensures a consistent and robust user experience across all components."
This commit is contained in:
		| @@ -1,11 +1,17 @@ | ||||
| import { Box, CircularProgress, Alert, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Button } from '@mui/material'; | ||||
| import ContentCopyIcon from '@mui/icons-material/ContentCopy'; | ||||
|  | ||||
| // Importaciones de nuestro proyecto | ||||
| import { useApiData } from '../../hooks/useApiData'; | ||||
| import { useIsHoliday } from '../../hooks/useIsHoliday'; | ||||
| import type { CotizacionBolsa } from '../../models/mercadoModels'; | ||||
| import { formatCurrency, formatFullDateTime } from '../../utils/formatters'; | ||||
| import { copyToClipboard } from '../../utils/clipboardUtils'; | ||||
| import { HolidayAlert } from '../common/HolidayAlert'; | ||||
|  | ||||
| // Función para convertir datos a formato CSV | ||||
| /** | ||||
|  * Función para convertir los datos de la tabla a formato CSV. | ||||
|  */ | ||||
| const toCSV = (headers: string[], data: CotizacionBolsa[]) => { | ||||
|     const headerRow = headers.join(';'); | ||||
|     const dataRows = data.map(row =>  | ||||
| @@ -14,36 +20,57 @@ const toCSV = (headers: string[], data: CotizacionBolsa[]) => { | ||||
|             row.nombreEmpresa, | ||||
|             formatCurrency(row.precioActual), | ||||
|             formatCurrency(row.cierreAnterior), | ||||
|             `${row.porcentajeCambio.toFixed(2)}%` | ||||
|             `${row.porcentajeCambio.toFixed(2)}%`, | ||||
|             formatFullDateTime(row.fechaRegistro) | ||||
|         ].join(';') | ||||
|     ); | ||||
|     return [headerRow, ...dataRows].join('\n'); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Componente de tabla de datos crudos para la Bolsa Local (MERVAL y acciones), | ||||
|  * diseñado para la página de redacción. | ||||
|  */ | ||||
| export const RawBolsaLocalTable = () => { | ||||
|     const { data, loading, error } = useApiData<CotizacionBolsa[]>('/mercados/bolsa/local'); | ||||
|     // 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'); | ||||
|  | ||||
|     const handleCopy = () => { | ||||
|         if (!data) return; | ||||
|         const headers = ["Ticker", "Nombre", "Último Precio", "Cierre Anterior", "Variación %"]; | ||||
|         const headers = ["Ticker", "Nombre", "Último Precio", "Cierre Anterior", "Variación %", "Fecha de Registro"]; | ||||
|         const csvData = toCSV(headers, data); | ||||
|          | ||||
|         copyToClipboard(csvData) | ||||
|             .then(() => { | ||||
|                 alert('¡Tabla copiada al portapapeles!'); | ||||
|             }) | ||||
|             .then(() => alert('¡Tabla copiada al portapapeles!')) | ||||
|             .catch(err => { | ||||
|                 console.error('Error al copiar:', err); | ||||
|                 alert('Error: No se pudo copiar la tabla.'); | ||||
|             }); | ||||
|     }; | ||||
|  | ||||
|     if (loading) return <CircularProgress />; | ||||
|     if (error) return <Alert severity="error">{error}</Alert>; | ||||
|     if (!data) return null; | ||||
|     // 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>; | ||||
|     } | ||||
|  | ||||
|     return ( | ||||
|         <Box> | ||||
|             {/* Si es feriado, mostramos una alerta informativa encima de la tabla. */} | ||||
|             {isHoliday && ( | ||||
|                 <Box sx={{ mb: 2 }}> | ||||
|                     <HolidayAlert /> | ||||
|                 </Box> | ||||
|             )} | ||||
|  | ||||
|             <Button startIcon={<ContentCopyIcon />} onClick={handleCopy} sx={{ mb: 1 }}> | ||||
|                 Copiar como CSV | ||||
|             </Button> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user