Feat Tabla de Datos Redaccion
- Tabla de Top 2 Conurbano - Tabla de Top 2 Por Secciones Electorales Bs. As.
This commit is contained in:
@@ -5,7 +5,7 @@ import type {
|
||||
ApiResponseTablaDetallada, ProyeccionBancas, MunicipioSimple,
|
||||
TelegramaData, CatalogoItem, CategoriaResumen, ResultadoTicker,
|
||||
ApiResponseResultadosPorSeccion, PanelElectoralDto, ResumenProvincia,
|
||||
CategoriaResumenHome
|
||||
CategoriaResumenHome, ResultadoFila, ResultadoSeccion
|
||||
} from './types/types';
|
||||
|
||||
/**
|
||||
@@ -337,4 +337,14 @@ export const getHomeResumenNacional = async (eleccionId: number, categoriaId: nu
|
||||
const url = `/elecciones/home-resumen-nacional?${queryParams.toString()}`;
|
||||
const { data } = await apiClient.get(url);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getTablaConurbano = async (eleccionId: number): Promise<ResultadoFila[]> => {
|
||||
const { data } = await apiClient.get(`/elecciones/${eleccionId}/tabla-conurbano`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getTablaSecciones = async (eleccionId: number): Promise<ResultadoSeccion[]> => {
|
||||
const { data } = await apiClient.get(`/elecciones/${eleccionId}/tabla-secciones`);
|
||||
return data;
|
||||
};
|
||||
@@ -6,6 +6,8 @@ import { PanelNacionalWidget } from './nacionales/PanelNacionalWidget';
|
||||
import { HomeCarouselWidget } from './nacionales/HomeCarouselWidget';
|
||||
import './DevAppStyle.css'
|
||||
import { HomeCarouselNacionalWidget } from './nacionales/HomeCarouselNacionalWidget';
|
||||
import { TablaConurbanoWidget } from './nacionales/TablaConurbanoWidget';
|
||||
import { TablaSeccionesWidget } from './nacionales/TablaSeccionesWidget';
|
||||
|
||||
// --- NUEVO COMPONENTE REUTILIZABLE PARA CONTENIDO COLAPSABLE ---
|
||||
const CollapsibleWidgetWrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
@@ -163,7 +165,15 @@ export const DevAppLegislativas = () => {
|
||||
Uso: <code style={codeStyle}><ResultadosNacionalesCardsWidget eleccionId={2} focoDistritoId="16" focoCategoriaId={2} cantidadResultados={1} /></code>
|
||||
</p>
|
||||
<ResultadosNacionalesCardsWidget eleccionId={2} focoDistritoId="16" focoCategoriaId={2} cantidadResultados={1} />
|
||||
<div style={sectionStyle}>
|
||||
<h2>Widget: Tabla de Resultados del Conurbano</h2>
|
||||
<TablaConurbanoWidget />
|
||||
</div>
|
||||
|
||||
<div style={sectionStyle}>
|
||||
<h2>Widget: Tabla de Resultados por Sección Electoral</h2>
|
||||
<TablaSeccionesWidget />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// src/features/legislativas/nacionales/TablaConurbanoWidget.tsx
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getTablaConurbano } from '../../../apiService';
|
||||
import styles from './TablaResultadosWidget.module.css';
|
||||
|
||||
export const TablaConurbanoWidget = () => {
|
||||
// CORRECCIÓN: Se elimina el estado y el selector de categoría.
|
||||
const ELECCION_ID = 2; // Exclusivo para elecciones nacionales
|
||||
|
||||
const { data, isLoading, error } = useQuery({
|
||||
// La queryKey ya no necesita la categoría
|
||||
queryKey: ['tablaConurbano', ELECCION_ID],
|
||||
// La llamada a la API ya no necesita la categoría
|
||||
queryFn: () => getTablaConurbano(ELECCION_ID),
|
||||
refetchInterval: 60000,
|
||||
});
|
||||
|
||||
const formatPercent = (num: number) => `${num.toFixed(2)}%`;
|
||||
|
||||
return (
|
||||
<div className={styles.widgetContainer}>
|
||||
<div className={styles.header}>
|
||||
<h3>Resultados Conurbano - Diputados Nacionales</h3>
|
||||
</div>
|
||||
{isLoading && <p>Cargando resultados...</p>}
|
||||
{error && <p>Error al cargar los datos.</p>}
|
||||
{data && (
|
||||
<table className={styles.resultsTable}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Distrito</th>
|
||||
<th>1ra Fuerza</th>
|
||||
<th>%</th>
|
||||
<th>2da Fuerza</th>
|
||||
<th>%</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.map((fila, index) => (
|
||||
<tr key={fila.ambitoId}>
|
||||
<td className={styles.distritoCell}><span className={styles.distritoIndex}>{index + 1}.</span>{fila.nombre}</td>
|
||||
<td className={styles.fuerzaCell}>{fila.fuerza1Display}</td>
|
||||
<td className={styles.porcentajeCell}>{formatPercent(fila.fuerza1Porcentaje)}</td>
|
||||
<td className={styles.fuerzaCell}>{fila.fuerza2Display}</td>
|
||||
<td className={styles.porcentajeCell}>{formatPercent(fila.fuerza2Porcentaje)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
/* src/features/legislativas/nacionales/TablaResultadosWidget.module.css */
|
||||
.widgetContainer {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
max-width: 900px;
|
||||
margin: 2rem auto;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.header h3 {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.categoriaSelector {
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
.resultsTable {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.resultsTable th,
|
||||
.resultsTable td {
|
||||
padding: 0.75rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.resultsTable th {
|
||||
font-weight: 700;
|
||||
font-size: 0.8rem;
|
||||
text-transform: uppercase;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.distritoCell {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.fuerzaCell {
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.porcentajeCell {
|
||||
font-weight: 700;
|
||||
text-align: right;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.seccionHeader td {
|
||||
background-color: #f8f9fa;
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
color: #007bff;
|
||||
border-top: 2px solid #007bff;
|
||||
border-bottom: 2px solid #007bff;
|
||||
}
|
||||
|
||||
.distritoIndex {
|
||||
font-weight: 400;
|
||||
color: #6c757d;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// src/features/legislativas/nacionales/TablaSeccionesWidget.tsx
|
||||
import React from 'react'; // Importar React para React.Fragment
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getTablaSecciones } from '../../../apiService';
|
||||
import styles from './TablaResultadosWidget.module.css';
|
||||
|
||||
export const TablaSeccionesWidget = () => {
|
||||
const ELECCION_ID = 2;
|
||||
|
||||
const { data, isLoading, error } = useQuery({
|
||||
queryKey: ['tablaSecciones', ELECCION_ID],
|
||||
queryFn: () => getTablaSecciones(ELECCION_ID),
|
||||
refetchInterval: 60000,
|
||||
});
|
||||
|
||||
const formatPercent = (num: number) => `${num.toFixed(2)}%`;
|
||||
|
||||
return (
|
||||
<div className={styles.widgetContainer}>
|
||||
<div className={styles.header}>
|
||||
<h3>Resultados por Sección - Diputados Nacionales</h3>
|
||||
</div>
|
||||
{isLoading && <p>Cargando resultados...</p>}
|
||||
{error && <p>Error al cargar los datos.</p>}
|
||||
{data && (
|
||||
<table className={styles.resultsTable}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Municipio</th>
|
||||
<th>1ra Fuerza</th>
|
||||
<th>%</th>
|
||||
<th>2da Fuerza</th>
|
||||
<th>%</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.map((seccion) => (
|
||||
<React.Fragment key={seccion.seccionId}>
|
||||
<tr className={styles.seccionHeader}>
|
||||
<td colSpan={5}>{seccion.nombre}</td>
|
||||
</tr>
|
||||
{seccion.municipios.map((fila, index) => (
|
||||
<tr key={fila.ambitoId}>
|
||||
<td className={styles.distritoCell}><span className={styles.distritoIndex}>{index + 1}.</span>{fila.nombre}</td>
|
||||
<td className={styles.fuerzaCell}>{fila.fuerza1Display}</td>
|
||||
<td className={styles.porcentajeCell}>{formatPercent(fila.fuerza1Porcentaje)}</td>
|
||||
<td className={styles.fuerzaCell}>{fila.fuerza2Display}</td>
|
||||
<td className={styles.porcentajeCell}>{formatPercent(fila.fuerza2Porcentaje)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -152,7 +152,7 @@ export interface ResultadoCandidato {
|
||||
color: string | null;
|
||||
porcentaje: number;
|
||||
votos: number;
|
||||
bancasObtenidas?: number;
|
||||
bancasObtenidas?: number;
|
||||
}
|
||||
|
||||
// Definición para una categoría.
|
||||
@@ -171,12 +171,29 @@ export interface ResumenProvincia {
|
||||
}
|
||||
|
||||
export interface CategoriaResumenHome {
|
||||
categoriaId: number;
|
||||
categoriaNombre: string;
|
||||
estadoRecuento: EstadoRecuentoDto | null;
|
||||
resultados: ResultadoCandidato[];
|
||||
votosEnBlanco: number;
|
||||
votosEnBlancoPorcentaje: number;
|
||||
votosTotales: number;
|
||||
ultimaActualizacion: string;
|
||||
categoriaId: number;
|
||||
categoriaNombre: string;
|
||||
estadoRecuento: EstadoRecuentoDto | null;
|
||||
resultados: ResultadoCandidato[];
|
||||
votosEnBlanco: number;
|
||||
votosEnBlancoPorcentaje: number;
|
||||
votosTotales: number;
|
||||
ultimaActualizacion: string;
|
||||
}
|
||||
|
||||
// --- TIPOS PARA WIDGETS DE TABLAS ---
|
||||
export interface ResultadoFila {
|
||||
ambitoId: number;
|
||||
nombre: string;
|
||||
orden: number;
|
||||
fuerza1Display: string;
|
||||
fuerza1Porcentaje: number;
|
||||
fuerza2Display: string;
|
||||
fuerza2Porcentaje: number;
|
||||
}
|
||||
|
||||
export interface ResultadoSeccion {
|
||||
seccionId: string;
|
||||
nombre: string;
|
||||
municipios: ResultadoFila[];
|
||||
}
|
||||
Reference in New Issue
Block a user