diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.tsx b/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.tsx
index 84a64e0..7a56b38 100644
--- a/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.tsx
+++ b/Elecciones-Web/frontend/src/features/legislativas/nacionales/HomeCarouselWidget.tsx
@@ -19,7 +19,6 @@ interface Props {
distritoId: string;
categoriaId: number;
titulo: string;
- mapLinkUrl: string;
}
const formatPercent = (num: number | null | undefined) => `${(num || 0).toFixed(2).replace('.', ',')}%`;
@@ -42,7 +41,7 @@ const formatDateTime = (dateString: string | undefined | null) => {
}
};
-export const HomeCarouselWidget = ({ eleccionId, distritoId, categoriaId, titulo, mapLinkUrl }: Props) => {
+export const HomeCarouselWidget = ({ eleccionId, distritoId, categoriaId, titulo }: Props) => {
const uniqueId = `swiper-${Math.random().toString(36).substring(2, 9)}`;
const prevButtonClass = `prev-${uniqueId}`;
const nextButtonClass = `next-${uniqueId}`;
@@ -56,14 +55,24 @@ export const HomeCarouselWidget = ({ eleccionId, distritoId, categoriaId, titulo
if (isLoading) return
Cargando widget...
;
if (error || !data) return
No se pudieron cargar los datos.
;
+ const handleOpenMap = () => {
+ (window as any).EleccionesWidgets.openModal('panel-nacional', {
+ eleccionId: eleccionId.toString(),
+ // Pasamos un ámbito inicial para que el mapa sepa qué mostrar
+ ambitoId: `distrito:${distritoId}`,
+ categoriaId: categoriaId.toString(),
+ nivel: 'provincia'
+ });
+ };
+
return (
diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacional.module.css b/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacional.module.css
index 5f300b4..276a143 100644
--- a/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacional.module.css
+++ b/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacional.module.css
@@ -576,4 +576,34 @@
.mobileResultsHeader .headerInfo h4 { font-size: 0.75rem; text-transform: uppercase; }
.mobileResultsHeader .headerInfo .headerActionText { font-size: 0.7rem; }
.mobileCardViewToggle .toggleBtn { padding: 6px 10px; font-size: 0.8rem; }
+}
+
+/* Estilos que se aplican al contenedor principal del widget cuando está en un modal */
+.panelNacionalContainer.isModal {
+ width: 100%;
+ height: 100%;
+ max-width: 900px;
+ align-self: center;
+ margin: 0;
+ border: none;
+ border-radius: 0;
+ box-shadow: none;
+ display: flex;
+ flex-direction: column;
+}
+
+/* Hacemos que el contenido principal (mapa + resultados) crezca para llenar el espacio */
+.panelNacionalContainer.isModal .panelMainContent {
+ flex-grow: 1;
+ height: auto; /* Quitamos la altura fija */
+ min-height: 0; /* Permitimos que se encoja si es necesario */
+}
+
+/* Aseguramos que la columna de resultados también sea flexible en el modal */
+.panelNacionalContainer.isModal .resultadosColumn {
+ display: flex;
+ flex-direction: column;
+}
+.panelNacionalContainer.isModal .panelPartidosContainer {
+ flex-grow: 1;
}
\ No newline at end of file
diff --git a/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacionalWidget.tsx b/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacionalWidget.tsx
index c5b77f1..98e9289 100644
--- a/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacionalWidget.tsx
+++ b/Elecciones-Web/frontend/src/features/legislativas/nacionales/PanelNacionalWidget.tsx
@@ -124,6 +124,7 @@ const MobileResultsCard = ({
// --- WIDGET PRINCIPAL ---
interface PanelNacionalWidgetProps {
eleccionId: number;
+ isModal?: boolean; // Aceptamos la nueva prop opcional
}
type AmbitoState = {
@@ -159,7 +160,7 @@ const PanelContenido = ({ eleccionId, ambitoActual, categoriaId }: { eleccionId:
return
;
};
-export const PanelNacionalWidget = ({ eleccionId }: PanelNacionalWidgetProps) => {
+export const PanelNacionalWidget = ({ eleccionId, isModal = false }: PanelNacionalWidgetProps) => {
const queryClient = useQueryClient();
const [ambitoActual, setAmbitoActual] = useState
({ id: null, nivel: 'pais', nombre: 'Argentina', provinciaDistritoId: null });
const [categoriaId, setCategoriaId] = useState(3);
@@ -215,8 +216,13 @@ export const PanelNacionalWidget = ({ eleccionId }: PanelNacionalWidgetProps) =>
isMobile ? styles[`mobile-view-${mobileView}`] : ''
].join(' ');
+ const containerClasses = [
+ styles.panelNacionalContainer,
+ isModal ? styles.isModal : ''
+ ].join(' ');
+
return (
-
+
= {
'concejales-por-seccion': ConcejalesPorSeccionWidget,
'resultados-tabla-detallada-por-seccion' : ResultadosTablaDetalladaWidget,
'resultados-tabla-detallada-por-municipio' : ResultadosRankingMunicipioWidget,*/
-
+
// Widgets Legislativas Nacionales 2025
'home-carousel': HomeCarouselWidget,
'home-carousel-nacional': HomeCarouselNacionalWidget,
@@ -72,42 +73,89 @@ const WIDGET_MAP: Record = {
'home-carousel-provincial': HomeCarouselProvincialWidget,
};
-// Vite establece `import.meta.env.DEV` a `true` cuando ejecutamos 'npm run dev'
+// --- LÓGICA DEL MODAL (AHORA GLOBAL) ---
+
+// 1. Crear un contenedor persistente para el modal en el DOM.
+let modalHost = document.getElementById('elecciones-modal-root');
+if (!modalHost) {
+ modalHost = document.createElement('div');
+ modalHost.id = 'elecciones-modal-root';
+ document.body.appendChild(modalHost);
+}
+let modalRoot: ReactDOM.Root | null = null;
+
+const renderWidgets = (container: HTMLElement, props: DOMStringMap) => {
+ const widgetName = props.eleccionesWidget;
+
+ if (widgetName && WIDGET_MAP[widgetName]) {
+ const WidgetComponent = WIDGET_MAP[widgetName];
+ const root = ReactDOM.createRoot(container);
+
+ root.render(
+
+
+
+
+
+ );
+ } else {
+ console.error(`React: ERROR - No se encontró un componente para el nombre de widget: "${widgetName}"`);
+ }
+};
+
+const openModal = (widgetName: string, props: DOMStringMap) => {
+ const WidgetComponent = WIDGET_MAP[widgetName];
+ if (WidgetComponent && modalHost) {
+ if (!modalRoot) {
+ modalRoot = ReactDOM.createRoot(modalHost);
+ }
+ modalRoot.render(
+
+
+
+
+
+
+
+ );
+ } else {
+ console.error(`Error: Se intentó abrir un widget en modal no encontrado: "${widgetName}"`);
+ }
+};
+
+const closeModal = () => {
+ if (modalRoot) {
+ modalRoot.unmount();
+ modalRoot = null;
+ }
+};
+
+// 2. Definir la API pública y asignarla al objeto window.
+const publicApi = {
+ render: renderWidgets,
+ openModal: openModal,
+ closeModal: closeModal,
+};
+(window as any).EleccionesWidgets = publicApi;
+
+
+// --- LÓGICA DE INICIALIZACIÓN ---
+
if (import.meta.env.DEV) {
// --- MODO DESARROLLO ---
- // Renderizamos nuestra página de showcase en el div#root
+ // Simplemente renderizamos la app de showcase. El modal ya está disponible globalmente.
ReactDOM.createRoot(document.getElementById('root')!).render(
- {/* */}
);
} else {
// --- MODO PRODUCCIÓN ---
- // Exponemos la función de renderizado para el bootstrap.js
- // La función de renderizado acepta el contenedor y las props
- const renderWidgets = (container: HTMLElement, props: DOMStringMap) => {
- const widgetName = props.eleccionesWidget;
-
- if (widgetName && WIDGET_MAP[widgetName]) {
- const WidgetComponent = WIDGET_MAP[widgetName];
- const root = ReactDOM.createRoot(container);
- root.render(
-
-
-
-
-
- );
- } else {
- console.error(`React: ERROR - No se encontró un componente para el nombre de widget: "${widgetName}"`);
- }
- };
-
- // La función expuesta ahora se llamará por cada widget, no una sola vez.
- (window as any).EleccionesWidgets = {
- render: renderWidgets
- };
+ // Procesamos la cola de renderizado si existe (para el script asíncrono)
+ const renderQueue = (window as any).EleccionesWidgets?.q || [];
+ renderQueue.forEach((request: { container: HTMLElement, props: DOMStringMap }) => {
+ publicApi.render(request.container, request.props);
+ });
}
\ No newline at end of file