feat: Add event management features, including event editing and participant tracking; refactor layout and API integration
This commit is contained in:
@@ -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 && (
|
||||
|
||||
Reference in New Issue
Block a user