feat: Implement event and questionnaire management features
- Added event creation page with form handling and validation. - Introduced layout for event management with context provider. - Created event listing page with active and recent events display. - Developed questionnaire creation page linked to events. - Implemented breadcrumb navigation for better user experience. - Added reusable components for event and questionnaire cards. - Integrated API calls for fetching and managing event data. - Enhanced slugify utility for better URL handling. - Established context for managing event state across components.
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
'use client';
|
||||
import { CuestionarioWithCupo, GetEvento } from '@/types/evento';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import React, { useState } from 'react';
|
||||
import MarkdownRenderer from '../markdown-render';
|
||||
import { toParam } from '@/utils/slugify';
|
||||
|
||||
export default function FormularioCardUser({
|
||||
evento,
|
||||
formulario,
|
||||
}: {
|
||||
evento: GetEvento;
|
||||
formulario: CuestionarioWithCupo;
|
||||
}) {
|
||||
const [verMas, setVerMas] = useState(false);
|
||||
const descripcion = formulario.descripcion ?? '';
|
||||
const limite = 100;
|
||||
|
||||
const descripcionRecortada =
|
||||
descripcion.length > limite && !verMas
|
||||
? `${descripcion.slice(0, limite)}...`
|
||||
: descripcion;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="card shadow-sm border-0"
|
||||
style={{ borderRadius: '12px', overflow: 'hidden' }}
|
||||
>
|
||||
<div className="position-relative">
|
||||
<Link
|
||||
href={`/evento/${toParam(
|
||||
evento.nombre_evento,
|
||||
evento.id_evento
|
||||
)}/${toParam(formulario.nombre_form, formulario.id_cuestionario)}`}
|
||||
>
|
||||
<Image
|
||||
width={400}
|
||||
height={250}
|
||||
className="img-fluid w-100"
|
||||
src={`${process.env.NEXT_PUBLIC_API_URL}/banners/${formulario.banner}`}
|
||||
alt="Banner formulario"
|
||||
style={{ objectFit: 'cover', height: '200px' }}
|
||||
/>
|
||||
</Link>
|
||||
|
||||
{/* Badge de cupos en la esquina superior derecha */}
|
||||
<div className="position-absolute top-0 end-0 m-2">
|
||||
{formulario.cupo_maximo === null ? (
|
||||
<span className="badge bg-success">Sin límite</span>
|
||||
) : (
|
||||
<span className="badge bg-primary">
|
||||
{formulario.cupos_disponibles} cupos
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="card-body p-3 d-flex flex-column">
|
||||
{/* Fecha del evento */}
|
||||
<div className="d-flex align-items-center mb-2">
|
||||
<div className="me-3">
|
||||
<div className="text-muted text-center small">
|
||||
{new Date(formulario.fecha_inicio)
|
||||
.toLocaleDateString('es-ES', { month: 'short' })
|
||||
.toUpperCase()}
|
||||
</div>
|
||||
<div
|
||||
className="fw-bold h4 mb-0"
|
||||
style={{ lineHeight: 1, whiteSpace: 'nowrap' }}
|
||||
>
|
||||
{(() => {
|
||||
const fechaInicio = new Date(formulario.fecha_inicio);
|
||||
const fechaFin = new Date(formulario.fecha_fin);
|
||||
const diaInicio = fechaInicio.getDate();
|
||||
const diaFin = fechaFin.getDate();
|
||||
const esElMismoDia =
|
||||
fechaInicio.toDateString() === fechaFin.toDateString();
|
||||
|
||||
return esElMismoDia ? diaInicio : `${diaInicio} - ${diaFin}`;
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="small text-muted fw-bold">
|
||||
{evento.nombre_evento}
|
||||
</span>
|
||||
<h5 className="card-title mb-1 fw-bold">
|
||||
{formulario.nombre_form}
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Descripción */}
|
||||
<div className="card-description flex-grow-1 mb-3">
|
||||
<MarkdownRenderer markdown={descripcionRecortada} />
|
||||
{descripcion.length > limite && (
|
||||
<button
|
||||
onClick={() => setVerMas(!verMas)}
|
||||
className="btn btn-link btn-sm p-0 ms-1 align-baseline text-decoration-none"
|
||||
style={{ fontSize: '0.875rem' }}
|
||||
>
|
||||
{verMas ? 'Ver menos' : 'Ver más'}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Botón de registro */}
|
||||
<Link
|
||||
href={`/evento/${toParam(
|
||||
evento.nombre_evento,
|
||||
evento.id_evento
|
||||
)}/${toParam(formulario.nombre_form, formulario.id_cuestionario)}`}
|
||||
className="btn btn-primary w-100 rounded-pill"
|
||||
>
|
||||
Registro
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user