Fix Widgets Carousel
This commit is contained in:
@@ -77,6 +77,18 @@ export const DevAppLegislativas = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style={sectionStyle}>
|
||||||
|
<h2>Widget: Carrusel de Resultados Nación (Home)</h2>
|
||||||
|
<p style={descriptionStyle}>
|
||||||
|
Uso: <code style={codeStyle}><HomeCarouselNacionalWidget eleccionId={2} categoriaId={2} titulo="Senadores - Argentina" /></code>
|
||||||
|
</p>
|
||||||
|
<HomeCarouselNacionalWidget
|
||||||
|
eleccionId={2}
|
||||||
|
categoriaId={2} // 3 para Diputados, 2 para Senadores
|
||||||
|
titulo="Senadores - Total País"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* --- SECCIÓN PARA EL WIDGET DE TARJETAS CON EJEMPLOS --- */}
|
{/* --- SECCIÓN PARA EL WIDGET DE TARJETAS CON EJEMPLOS --- */}
|
||||||
<div style={sectionStyle}>
|
<div style={sectionStyle}>
|
||||||
<h2>Widget: Resultados por Provincia (Tarjetas)</h2>
|
<h2>Widget: Resultados por Provincia (Tarjetas)</h2>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// src/features/legislativas/nacionales/HomeCarouselNacionalWidget.tsx
|
// src/features/legislativas/nacionales/HomeCarouselNacionalWidget.tsx
|
||||||
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { getHomeResumenNacional } from '../../../apiService';
|
import { getHomeResumenNacional } from '../../../apiService';
|
||||||
import { ImageWithFallback } from '../../../components/common/ImageWithFallback';
|
import { ImageWithFallback } from '../../../components/common/ImageWithFallback';
|
||||||
@@ -12,9 +13,14 @@ import 'swiper/css';
|
|||||||
import 'swiper/css/navigation';
|
import 'swiper/css/navigation';
|
||||||
import styles from './HomeCarouselWidget.module.css';
|
import styles from './HomeCarouselWidget.module.css';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
eleccionId: number;
|
||||||
|
categoriaId: number;
|
||||||
|
titulo: string;
|
||||||
|
}
|
||||||
|
|
||||||
const formatPercent = (num: number | null | undefined) => `${(num || 0).toFixed(2).replace('.', ',')}%`;
|
const formatPercent = (num: number | null | undefined) => `${(num || 0).toFixed(2).replace('.', ',')}%`;
|
||||||
const formatNumber = (num: number) => num.toLocaleString('es-AR');
|
const formatNumber = (num: number) => num.toLocaleString('es-AR');
|
||||||
|
|
||||||
const formatDateTime = (dateString: string | undefined | null) => {
|
const formatDateTime = (dateString: string | undefined | null) => {
|
||||||
if (!dateString) return '...';
|
if (!dateString) return '...';
|
||||||
try {
|
try {
|
||||||
@@ -33,20 +39,16 @@ const formatDateTime = (dateString: string | undefined | null) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Las props ya no incluyen distritoId
|
|
||||||
interface Props {
|
|
||||||
eleccionId: number;
|
|
||||||
categoriaId: number;
|
|
||||||
titulo: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const HomeCarouselNacionalWidget = ({ eleccionId, categoriaId, titulo }: Props) => {
|
export const HomeCarouselNacionalWidget = ({ eleccionId, categoriaId, titulo }: Props) => {
|
||||||
|
const uniqueId = `swiper-${Math.random().toString(36).substring(2, 9)}`;
|
||||||
|
const prevButtonClass = `prev-${uniqueId}`;
|
||||||
|
const nextButtonClass = `next-${uniqueId}`;
|
||||||
|
|
||||||
const { data, isLoading, error } = useQuery({
|
const { data, isLoading, error } = useQuery({
|
||||||
// La queryKey ahora no necesita distritoId
|
|
||||||
queryKey: ['homeResumenNacional', eleccionId, categoriaId],
|
queryKey: ['homeResumenNacional', eleccionId, categoriaId],
|
||||||
// Llama a la nueva función de la API
|
|
||||||
queryFn: () => getHomeResumenNacional(eleccionId, categoriaId),
|
queryFn: () => getHomeResumenNacional(eleccionId, categoriaId),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isLoading) return <div>Cargando widget...</div>;
|
if (isLoading) return <div>Cargando widget...</div>;
|
||||||
if (error || !data) return <div>No se pudieron cargar los datos.</div>;
|
if (error || !data) return <div>No se pudieron cargar los datos.</div>;
|
||||||
|
|
||||||
@@ -82,8 +84,8 @@ export const HomeCarouselNacionalWidget = ({ eleccionId, categoriaId, titulo }:
|
|||||||
spaceBetween={16}
|
spaceBetween={16}
|
||||||
slidesPerView={1.3}
|
slidesPerView={1.3}
|
||||||
navigation={{
|
navigation={{
|
||||||
prevEl: `.${styles.navButtonPrev}`,
|
prevEl: `.${prevButtonClass}`,
|
||||||
nextEl: `.${styles.navButtonNext}`,
|
nextEl: `.${nextButtonClass}`,
|
||||||
}}
|
}}
|
||||||
breakpoints={{
|
breakpoints={{
|
||||||
320: { slidesPerView: 1.25, spaceBetween: 10 },
|
320: { slidesPerView: 1.25, spaceBetween: 10 },
|
||||||
@@ -96,7 +98,6 @@ export const HomeCarouselNacionalWidget = ({ eleccionId, categoriaId, titulo }:
|
|||||||
{data.resultados.map(candidato => (
|
{data.resultados.map(candidato => (
|
||||||
<SwiperSlide key={candidato.agrupacionId}>
|
<SwiperSlide key={candidato.agrupacionId}>
|
||||||
<div className={styles.candidateCard} style={{ '--candidate-color': candidato.color || '#ccc' } as React.CSSProperties}>
|
<div className={styles.candidateCard} style={{ '--candidate-color': candidato.color || '#ccc' } as React.CSSProperties}>
|
||||||
|
|
||||||
<div className={styles.candidatePhotoWrapper}>
|
<div className={styles.candidatePhotoWrapper}>
|
||||||
<ImageWithFallback
|
<ImageWithFallback
|
||||||
src={candidato.fotoUrl ?? undefined}
|
src={candidato.fotoUrl ?? undefined}
|
||||||
@@ -105,22 +106,15 @@ export const HomeCarouselNacionalWidget = ({ eleccionId, categoriaId, titulo }:
|
|||||||
className={styles.candidatePhoto}
|
className={styles.candidatePhoto}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.candidateDetails}>
|
<div className={styles.candidateDetails}>
|
||||||
<div className={styles.candidateInfo}>
|
<div className={styles.candidateInfo}>
|
||||||
{candidato.nombreCandidato ? (
|
{candidato.nombreCandidato ? (
|
||||||
<>
|
<>
|
||||||
<span className={styles.candidateName}>
|
<span className={styles.candidateName}>{candidato.nombreCandidato}</span>
|
||||||
{candidato.nombreCandidato}
|
<span className={styles.partyName}>{candidato.nombreCortoAgrupacion || candidato.nombreAgrupacion}</span>
|
||||||
</span>
|
|
||||||
<span className={styles.partyName}>
|
|
||||||
{candidato.nombreCortoAgrupacion || candidato.nombreAgrupacion}
|
|
||||||
</span>
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<span className={styles.candidateName}>
|
<span className={styles.candidateName}>{candidato.nombreCortoAgrupacion || candidato.nombreAgrupacion}</span>
|
||||||
{candidato.nombreCortoAgrupacion || candidato.nombreAgrupacion}
|
|
||||||
</span>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.candidateResults}>
|
<div className={styles.candidateResults}>
|
||||||
@@ -128,14 +122,13 @@ export const HomeCarouselNacionalWidget = ({ eleccionId, categoriaId, titulo }:
|
|||||||
<span className={styles.votes}>{formatNumber(candidato.votos)} votos</span>
|
<span className={styles.votes}>{formatNumber(candidato.votos)} votos</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
|
|
||||||
<div className={`${styles.navButton} ${styles.navButtonPrev}`}></div>
|
<div className={`${styles.navButton} ${styles.navButtonPrev} ${prevButtonClass}`}></div>
|
||||||
<div className={`${styles.navButton} ${styles.navButtonNext}`}></div>
|
<div className={`${styles.navButton} ${styles.navButtonNext} ${nextButtonClass}`}></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.widgetFooter}>
|
<div className={styles.widgetFooter}>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// src/features/legislativas/nacionales/HomeCarouselWidget.tsx
|
// src/features/legislativas/nacionales/HomeCarouselWidget.tsx
|
||||||
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { getHomeResumen } from '../../../apiService';
|
import { getHomeResumen } from '../../../apiService';
|
||||||
import { ImageWithFallback } from '../../../components/common/ImageWithFallback';
|
import { ImageWithFallback } from '../../../components/common/ImageWithFallback';
|
||||||
@@ -21,7 +22,6 @@ interface Props {
|
|||||||
|
|
||||||
const formatPercent = (num: number | null | undefined) => `${(num || 0).toFixed(2).replace('.', ',')}%`;
|
const formatPercent = (num: number | null | undefined) => `${(num || 0).toFixed(2).replace('.', ',')}%`;
|
||||||
const formatNumber = (num: number) => num.toLocaleString('es-AR');
|
const formatNumber = (num: number) => num.toLocaleString('es-AR');
|
||||||
|
|
||||||
const formatDateTime = (dateString: string | undefined | null) => {
|
const formatDateTime = (dateString: string | undefined | null) => {
|
||||||
if (!dateString) return '...';
|
if (!dateString) return '...';
|
||||||
try {
|
try {
|
||||||
@@ -41,6 +41,10 @@ const formatDateTime = (dateString: string | undefined | null) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const HomeCarouselWidget = ({ eleccionId, distritoId, categoriaId, titulo }: 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}`;
|
||||||
|
|
||||||
const { data, isLoading, error } = useQuery({
|
const { data, isLoading, error } = useQuery({
|
||||||
queryKey: ['homeResumen', eleccionId, distritoId, categoriaId],
|
queryKey: ['homeResumen', eleccionId, distritoId, categoriaId],
|
||||||
queryFn: () => getHomeResumen(eleccionId, distritoId, categoriaId),
|
queryFn: () => getHomeResumen(eleccionId, distritoId, categoriaId),
|
||||||
@@ -81,8 +85,8 @@ export const HomeCarouselWidget = ({ eleccionId, distritoId, categoriaId, titulo
|
|||||||
spaceBetween={16}
|
spaceBetween={16}
|
||||||
slidesPerView={1.3}
|
slidesPerView={1.3}
|
||||||
navigation={{
|
navigation={{
|
||||||
prevEl: `.${styles.navButtonPrev}`,
|
prevEl: `.${prevButtonClass}`,
|
||||||
nextEl: `.${styles.navButtonNext}`,
|
nextEl: `.${nextButtonClass}`,
|
||||||
}}
|
}}
|
||||||
breakpoints={{
|
breakpoints={{
|
||||||
320: { slidesPerView: 1.25, spaceBetween: 10 },
|
320: { slidesPerView: 1.25, spaceBetween: 10 },
|
||||||
@@ -95,7 +99,6 @@ export const HomeCarouselWidget = ({ eleccionId, distritoId, categoriaId, titulo
|
|||||||
{data.resultados.map(candidato => (
|
{data.resultados.map(candidato => (
|
||||||
<SwiperSlide key={candidato.agrupacionId}>
|
<SwiperSlide key={candidato.agrupacionId}>
|
||||||
<div className={styles.candidateCard} style={{ '--candidate-color': candidato.color || '#ccc' } as React.CSSProperties}>
|
<div className={styles.candidateCard} style={{ '--candidate-color': candidato.color || '#ccc' } as React.CSSProperties}>
|
||||||
|
|
||||||
<div className={styles.candidatePhotoWrapper}>
|
<div className={styles.candidatePhotoWrapper}>
|
||||||
<ImageWithFallback
|
<ImageWithFallback
|
||||||
src={candidato.fotoUrl ?? undefined}
|
src={candidato.fotoUrl ?? undefined}
|
||||||
@@ -104,22 +107,15 @@ export const HomeCarouselWidget = ({ eleccionId, distritoId, categoriaId, titulo
|
|||||||
className={styles.candidatePhoto}
|
className={styles.candidatePhoto}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.candidateDetails}>
|
<div className={styles.candidateDetails}>
|
||||||
<div className={styles.candidateInfo}>
|
<div className={styles.candidateInfo}>
|
||||||
{candidato.nombreCandidato ? (
|
{candidato.nombreCandidato ? (
|
||||||
<>
|
<>
|
||||||
<span className={styles.candidateName}>
|
<span className={styles.candidateName}>{candidato.nombreCandidato}</span>
|
||||||
{candidato.nombreCandidato}
|
<span className={styles.partyName}>{candidato.nombreCortoAgrupacion || candidato.nombreAgrupacion}</span>
|
||||||
</span>
|
|
||||||
<span className={styles.partyName}>
|
|
||||||
{candidato.nombreCortoAgrupacion || candidato.nombreAgrupacion}
|
|
||||||
</span>
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<span className={styles.candidateName}>
|
<span className={styles.candidateName}>{candidato.nombreCortoAgrupacion || candidato.nombreAgrupacion}</span>
|
||||||
{candidato.nombreCortoAgrupacion || candidato.nombreAgrupacion}
|
|
||||||
</span>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.candidateResults}>
|
<div className={styles.candidateResults}>
|
||||||
@@ -127,14 +123,13 @@ export const HomeCarouselWidget = ({ eleccionId, distritoId, categoriaId, titulo
|
|||||||
<span className={styles.votes}>{formatNumber(candidato.votos)} votos</span>
|
<span className={styles.votes}>{formatNumber(candidato.votos)} votos</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
|
|
||||||
<div className={`${styles.navButton} ${styles.navButtonPrev}`}></div>
|
<div className={`${styles.navButton} ${styles.navButtonPrev} ${prevButtonClass}`}></div>
|
||||||
<div className={`${styles.navButton} ${styles.navButtonNext}`}></div>
|
<div className={`${styles.navButton} ${styles.navButtonNext} ${nextButtonClass}`}></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.widgetFooter}>
|
<div className={styles.widgetFooter}>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+4bc257df43f5813ec432b89b47fa078c1cfa1fc8")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+ae846f2d4834f3cd03079e91a8225e9f74cd073b")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
|
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|||||||
Reference in New Issue
Block a user