feat: Refactor carousel component and add new event card
- Updated ClientCarousel to accept props for dynamic image rendering. - Changed CarouselProps interface to export for better type usage. - Enhanced Carousel component to handle default images and improved styling. - Introduced EventoCard component for displaying event details with dynamic data. - Added MarkdownRenderer for rendering markdown content in EventoCard. - Removed old Formulario component and replaced it with FormularioRegistro for better structure. - Implemented prefetching logic in FormularioRegistro to auto-fill user data based on account info. - Created PrefetchAbiertaCorta component for handling short answer questions with pre-filled data. - Added useGetApi hook for simplified API data fetching. - Updated plantillas data to include validation types for new form fields. - Introduced new types for event and questionnaire handling in TypeScript. - Enhanced styles for better UI/UX, including carousel controls and required field indicators.
This commit is contained in:
+13
-13
@@ -1,7 +1,7 @@
|
||||
import Image from 'next/image';
|
||||
import React from 'react';
|
||||
|
||||
interface CarouselProps {
|
||||
export interface CarouselProps {
|
||||
id?: string;
|
||||
images?: {
|
||||
src: string;
|
||||
@@ -9,15 +9,9 @@ interface CarouselProps {
|
||||
}[];
|
||||
}
|
||||
|
||||
export default function Carousel({
|
||||
id = 'carouselExample',
|
||||
images = [
|
||||
{
|
||||
src: '/feriasex.png',
|
||||
alt: 'Imagen de ejemplo',
|
||||
},
|
||||
],
|
||||
}: CarouselProps) {
|
||||
export default function Carousel({ id, images }: CarouselProps) {
|
||||
console.log('Carousel images:', images);
|
||||
|
||||
if (!images || images.length === 0) {
|
||||
return <div>No hay imágenes para mostrar</div>;
|
||||
}
|
||||
@@ -31,11 +25,17 @@ export default function Carousel({
|
||||
className={`carousel-item ${index === 0 ? 'active' : ''}`}
|
||||
>
|
||||
<Image
|
||||
src={img.src}
|
||||
width={1600}
|
||||
height={535}
|
||||
src={img.src ? img.src : '/default-banner.png'}
|
||||
width={1200}
|
||||
height={400}
|
||||
alt="Ejemplo de banner"
|
||||
className="d-block w-100 rounded-3 img-fluid"
|
||||
style={{
|
||||
height: '400px',
|
||||
objectFit: 'cover',
|
||||
objectPosition: 'center',
|
||||
maxHeight: '400px',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { GetEventoWithCuestionarios } from '@/types/evento';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import React, { useState } from 'react';
|
||||
import MarkdownRenderer from './markdown-render';
|
||||
|
||||
export default function EventoCard({
|
||||
evento,
|
||||
}: {
|
||||
evento: GetEventoWithCuestionarios;
|
||||
}) {
|
||||
const [verMas, setVerMas] = useState(false);
|
||||
const descripcion = evento.descripcion_evento;
|
||||
const limite = 100;
|
||||
|
||||
const descripcionRecortada =
|
||||
descripcion.length > limite && !verMas
|
||||
? `${descripcion.slice(0, limite)}...`
|
||||
: descripcion;
|
||||
|
||||
return (
|
||||
<div className="card card-blog d-flex flex-column justify-content-between">
|
||||
<div>
|
||||
<div className="card-image scale-hover-1">
|
||||
<Link href={`/evento/${evento.id_evento}`}>
|
||||
<Image
|
||||
width={400}
|
||||
height={300}
|
||||
className="img-fluid"
|
||||
src={`${process.env.NEXT_PUBLIC_API_URL}/banners/${evento.banner}`}
|
||||
alt="Banner formulario"
|
||||
/>
|
||||
<div className="card-caption">{evento.nombre_evento}</div>
|
||||
</Link>
|
||||
<div className="ripple-cont"></div>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="card-description mb-0">
|
||||
<MarkdownRenderer markdown={descripcionRecortada} />
|
||||
{descripcion.length > limite && (
|
||||
<button
|
||||
onClick={() => setVerMas(!verMas)}
|
||||
className="btn btn-link btn-sm p-0 ms-1 align-baseline"
|
||||
style={{ fontSize: '0.875rem' }}
|
||||
>
|
||||
{verMas ? 'Ver menos' : 'Ver más'}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{evento.cuestionarios.length > 0 &&
|
||||
evento.cuestionarios.map((cuestionario) => (
|
||||
<div key={cuestionario.id_cuestionario} className="">
|
||||
<Link
|
||||
href={`/evento/${evento.nombre_evento.split(' ').join('_')}/${evento.id_evento}/${cuestionario.id_cuestionario}`}
|
||||
className="btn mt-2 w-100 btn-outline-primary"
|
||||
>
|
||||
{cuestionario.nombre_form}
|
||||
</Link>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
|
||||
type MarkdownRendererProps = {
|
||||
markdown: string;
|
||||
};
|
||||
|
||||
const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ markdown }) => (
|
||||
<ReactMarkdown
|
||||
components={{
|
||||
p: ({ ...props }) => <p style={{ margin: 0 }} {...props} />,
|
||||
}}
|
||||
>
|
||||
{markdown}
|
||||
</ReactMarkdown>
|
||||
);
|
||||
|
||||
export default MarkdownRenderer;
|
||||
Reference in New Issue
Block a user