feat: Add event management features, including event editing and participant tracking; refactor layout and API integration

This commit is contained in:
miguel
2025-06-18 12:37:47 -06:00
parent f00bd8ac5e
commit b110109cb3
14 changed files with 316 additions and 198 deletions
+142
View File
@@ -0,0 +1,142 @@
'use client';
import ImageUploader from '@/components/banner-uploader';
import Button from '@/components/button';
import Input from '@/components/input';
import Select from '@/components/select';
import { CreateEventoType } from '@/types/create-evento';
import { GetEventoWithCuestionario } from '@/types/evento';
import axiosInstance from '@/utils/api-config';
import { getAxiosError } from '@/utils/errors-utils';
import React, { useState } from 'react';
import toast from 'react-hot-toast';
interface EditEventoProps {
evento: GetEventoWithCuestionario;
handleChange: (field: keyof CreateEventoType, value: string | Date) => void;
handleOnChange: (eventoActualizado: GetEventoWithCuestionario) => void;
}
export default function EditEvento({
evento,
handleChange,
handleOnChange,
}: EditEventoProps) {
const toDateInputValue = (isoString: string) => isoString.slice(0, 10);
const [loading, setLoading] = useState(false);
const [nuevoBanner, setNuevoBanner] = useState<File | null>(null);
const handleOnSave = async () => {
setLoading(true);
try {
// 1. Subir nuevo banner si fue cambiado
if (nuevoBanner) {
const formData = new FormData();
formData.append('banner', nuevoBanner);
await axiosInstance.post(
`/evento/${evento.id_evento}/banner`,
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
}
);
}
// 2. Actualizar el evento (sin incluir 'banner')
const res = await axiosInstance.patch(`/evento/${evento.id_evento}`, {
nombre_evento: evento.nombre_evento,
descripcion_evento: evento.descripcion_evento,
tipo_evento: evento.tipo_evento,
fecha_inicio: evento.fecha_inicio,
fecha_fin: evento.fecha_fin,
});
toast.success('Evento actualizado correctamente');
handleOnChange(res.data); // Actualiza en el padre
} catch (error) {
const msg = getAxiosError(error);
toast.error(`Error al actualizar el evento: ${msg.message}`);
} finally {
setLoading(false);
}
};
return (
<div className="row border p-3 rounded my-4">
<h2>Editar Información del Evento</h2>
<p>Modifica los datos del evento que desees actualizar.</p>
<ImageUploader
label="Banner del evento"
defaultBanner={
evento.banner
? `${process.env.NEXT_PUBLIC_API_URL}/banners/${evento.banner}`
: undefined
}
onChange={(file) => {
setNuevoBanner(file);
}}
/>
<Input
label="Nombre del evento"
required
value={evento.nombre_evento}
onChange={(e) => handleChange('nombre_evento', e.target.value)}
/>
<div className="mb-3">
<label className="form-label">Descripción del evento</label>
<textarea
className="form-control bg-white"
rows={5}
placeholder="Describe el evento..."
value={evento.descripcion_evento}
onChange={(e) => handleChange('descripcion_evento', e.target.value)}
/>
</div>
<Select
label="Tipo de evento"
value={evento.tipo_evento}
placeholder="Selecciona un tipo de evento"
onChange={(e) => handleChange('tipo_evento', e.target.value)}
options={[
{ label: 'Conferencia', value: 'conferencia' },
{ label: 'Taller', value: 'taller' },
{ label: 'Seminario', value: 'seminario' },
{ label: 'Otro', value: 'otro' },
]}
/>
<div className="col-md-6">
<Input
label="Fecha de inicio"
type="date"
className={{ container: 'mb-3' }}
value={toDateInputValue(evento.fecha_inicio)}
onChange={(e) => handleChange('fecha_inicio', e.target.value)}
/>
</div>
<div className="col-md-6">
<Input
label="Fecha de fin"
type="date"
className={{ container: 'mb-3' }}
value={toDateInputValue(evento.fecha_fin)}
onChange={(e) => handleChange('fecha_fin', e.target.value)}
/>
</div>
<div>
<Button icon="save" disabled={loading} onClick={handleOnSave}>
{loading ? 'Guardando...' : 'Guardar Cambios'}
</Button>
</div>
</div>
);
}
@@ -84,15 +84,17 @@ export default function FormularioRegistro({
? `/alumnos/${cuenta}`
: `/trabajadores/${cuenta}`;
console.log('Buscando información de cuenta:', endpoint);
const res = await axiosInstance.get(endpoint);
console.log('Datos de cuenta obtenidos:', res.data);
// Usar datos fake para pruebas
// Usar datos fake para pruebas
setCuentaInfo({
nombre: 'Juan',
apellidos: 'Pérez',
correo: '421010301@pcpuma.acatlan.unam.mx',
correo: 'juan.perez@pcpuma.acatlan.unam.mx',
genero: 'M',
carrera: 'Ingeniería',
carrera: 'Ingeniería en Computación',
});
} catch (error) {
console.error('Error al obtener datos de cuenta:', error);
@@ -267,7 +269,7 @@ export default function FormularioRegistro({
}
return (
<div>
<div className="preguntas">
<hr />
<h2 className="text-xl font-bold">{data?.cuestionario.nombre_form}</h2>
{data?.cuestionario.descripcion && (