feat: add markdown editor for event description and update event forms
- Added @uiw/react-md-editor dependency for rich text editing. - Implemented dynamic loading of the markdown editor in create and edit event forms. - Updated event forms to include new fields for 'apellidos', 'genero', and 'rfc'. - Refactored event and questionnaire pages to improve data fetching and rendering. - Removed unnecessary Excel files from the public directory. - Enhanced error handling and logging in event creation and form submission processes. - Updated carousel component to handle empty image arrays gracefully. - Created a new FormularioPage component to streamline questionnaire rendering.
This commit is contained in:
@@ -1,9 +1,16 @@
|
||||
'use client';
|
||||
import ImageUploader from '@/components/banner-uploader';
|
||||
import Input from '@/components/input';
|
||||
import Select from '@/components/select';
|
||||
import { CreateEventoType } from '@/types/create-evento';
|
||||
import { commands } from '@uiw/react-md-editor';
|
||||
import dynamic from 'next/dynamic';
|
||||
import React from 'react';
|
||||
|
||||
// Carga dinámica para evitar problemas con SSR
|
||||
const MDEditor = dynamic(() => import('@uiw/react-md-editor'), { ssr: false });
|
||||
const MAX_LENGTH = 500;
|
||||
|
||||
interface CreateEventoProps {
|
||||
evento: CreateEventoType;
|
||||
handleChange: (field: keyof CreateEventoType, value: string | Date) => void;
|
||||
@@ -17,13 +24,14 @@ export default function CreateEvento({
|
||||
}: CreateEventoProps) {
|
||||
return (
|
||||
<div className="row border p-3 rounded my-4">
|
||||
<h2>
|
||||
Informacion del Evento
|
||||
</h2>
|
||||
<h2>Información del Evento</h2>
|
||||
<p>
|
||||
Completa la siguiente informacion para describir la informacion general del evento
|
||||
Completa la siguiente información para describir los detalles generales
|
||||
del evento.
|
||||
</p>
|
||||
|
||||
<ImageUploader label="Banner del evento" onChange={handleBannerChange} />
|
||||
|
||||
<Input
|
||||
label="Nombre del evento"
|
||||
required
|
||||
@@ -31,15 +39,21 @@ export default function CreateEvento({
|
||||
onChange={(e) => handleChange('nombre_evento', e.target.value)}
|
||||
/>
|
||||
|
||||
<div className="mb-3">
|
||||
<div className="mb-4">
|
||||
<label className="form-label">Descripción del evento</label>
|
||||
<textarea
|
||||
className="form-control bg-white"
|
||||
rows={3}
|
||||
placeholder="Describe el evento..."
|
||||
value={evento.descripcion_evento}
|
||||
onChange={(e) => handleChange('descripcion_evento', e.target.value)}
|
||||
/>
|
||||
<div data-color-mode="light">
|
||||
<MDEditor
|
||||
value={evento.descripcion_evento}
|
||||
onChange={(value) => {
|
||||
const texto = value || '';
|
||||
if (texto.length <= MAX_LENGTH) {
|
||||
handleChange('descripcion_evento', texto);
|
||||
}
|
||||
}}
|
||||
height={300}
|
||||
commands={[commands.bold, commands.italic, commands.hr]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Select
|
||||
@@ -66,6 +80,7 @@ export default function CreateEvento({
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-md-6">
|
||||
<Input
|
||||
label="Fecha de fin"
|
||||
|
||||
@@ -25,12 +25,15 @@ const tiposValidacion: TiposValidacion[] = [
|
||||
'correo_institucional',
|
||||
'telefono',
|
||||
'nombre',
|
||||
'apellidos',
|
||||
'genero',
|
||||
'entero',
|
||||
'decimal',
|
||||
'comunidad_alumno',
|
||||
'cuenta_alumno',
|
||||
'comunidad_trabajador',
|
||||
'cuenta_trabajador',
|
||||
'rfc'
|
||||
];
|
||||
|
||||
type CampoPreguntaSimple =
|
||||
|
||||
@@ -7,8 +7,11 @@ import { CreateEventoType } from '@/types/create-evento';
|
||||
import { GetEventoWithCuestionario } from '@/types/evento';
|
||||
import axiosInstance from '@/utils/api-config';
|
||||
import { getAxiosError } from '@/utils/errors-utils';
|
||||
import { commands } from '@uiw/react-md-editor';
|
||||
import dynamic from 'next/dynamic';
|
||||
import React, { useState } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
const MDEditor = dynamic(() => import('@uiw/react-md-editor'), { ssr: false });
|
||||
|
||||
interface EditEventoProps {
|
||||
evento: GetEventoWithCuestionario;
|
||||
@@ -88,15 +91,21 @@ export default function EditEvento({
|
||||
onChange={(e) => handleChange('nombre_evento', e.target.value)}
|
||||
/>
|
||||
|
||||
<div className="mb-3">
|
||||
<div className="mb-4">
|
||||
<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 data-color-mode="light">
|
||||
<MDEditor
|
||||
value={evento.descripcion_evento}
|
||||
onChange={(value) => {
|
||||
const texto = value || '';
|
||||
if (texto.length <= 500) {
|
||||
handleChange('descripcion_evento', texto);
|
||||
}
|
||||
}}
|
||||
height={250}
|
||||
commands={[commands.bold, commands.italic, commands.hr]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Select
|
||||
|
||||
@@ -12,11 +12,12 @@ import { useRouter } from 'next/navigation';
|
||||
import { getAxiosError } from '@/utils/errors-utils';
|
||||
|
||||
type UsuarioData = {
|
||||
nombre: string;
|
||||
apellidos: string;
|
||||
correo: string;
|
||||
genero: 'M' | 'F';
|
||||
carrera: string;
|
||||
nombre: string; // alumno o trabajador
|
||||
apellidos: string; // alumno o trabajador
|
||||
correo: string; // alumno o trabajador (en los alumnos se usa el id_ncuenta en trabajadores ellos deben escribirlo)
|
||||
genero: 'M' | 'F'; // alumno o trabajador
|
||||
carrera: string; // solo para alumnos
|
||||
rfc?: string; // solo para trabajadores se usa para buscar información de cuenta
|
||||
};
|
||||
|
||||
const confirmativeOption = ['Sí', 'Si', 'Si, claro', 'Claro que sí'];
|
||||
@@ -60,7 +61,8 @@ export default function FormularioRegistro({
|
||||
const preguntaCuenta = preguntas?.find(
|
||||
(pregunta) =>
|
||||
pregunta.validacion === 'cuenta_alumno' ||
|
||||
pregunta.validacion === 'cuenta_trabajador'
|
||||
pregunta.validacion === 'cuenta_trabajador' ||
|
||||
pregunta.validacion === 'rfc'
|
||||
);
|
||||
|
||||
// ------------------------
|
||||
@@ -71,12 +73,13 @@ export default function FormularioRegistro({
|
||||
|
||||
const esCuentaAlumno = preguntaCuenta?.validacion === 'cuenta_alumno';
|
||||
const esCuentaTrabajador =
|
||||
preguntaCuenta?.validacion === 'cuenta_trabajador';
|
||||
preguntaCuenta?.validacion === 'cuenta_trabajador' ||
|
||||
preguntaCuenta?.validacion === 'rfc';
|
||||
|
||||
const puedeBuscar =
|
||||
cuenta &&
|
||||
typeof cuenta === 'string' &&
|
||||
((esCuentaAlumno && cuenta.length === 9) || esCuentaTrabajador);
|
||||
((esCuentaAlumno && cuenta.length === 9) || (esCuentaTrabajador && cuenta.length === 5));
|
||||
|
||||
const fetchCuentaInfo = async () => {
|
||||
try {
|
||||
@@ -85,17 +88,22 @@ export default function FormularioRegistro({
|
||||
: `/trabajadores/${cuenta}`;
|
||||
|
||||
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: res.data.nombre,
|
||||
apellidos: res.data.apellidos,
|
||||
correo: '',
|
||||
genero: res.data.genero,
|
||||
carrera: res.data.carrera ? res.data.carrera : '',
|
||||
});
|
||||
// Usar datos fake para pruebas
|
||||
/* setCuentaInfo({
|
||||
nombre: 'Juan',
|
||||
apellidos: 'Pérez',
|
||||
correo: 'juan.perez@pcpuma.acatlan.unam.mx',
|
||||
genero: 'M',
|
||||
carrera: 'Ingeniería en Computación',
|
||||
});
|
||||
}); */
|
||||
} catch (error) {
|
||||
console.error('Error al obtener datos de cuenta:', error);
|
||||
setCuentaInfo(null);
|
||||
@@ -358,6 +366,7 @@ export default function FormularioRegistro({
|
||||
cuentaInfo={cuentaInfo}
|
||||
isComunidad={isComunidad?.label}
|
||||
onChange={actualizarRespuesta}
|
||||
preguntaComunidad={preguntaComunidad?.validacion ?? ''}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ type Props = {
|
||||
} | null;
|
||||
isComunidad: string | undefined;
|
||||
onChange: (id: string, valor: string) => void;
|
||||
preguntaComunidad: string;
|
||||
};
|
||||
|
||||
const confirmativeOption = ['Sí', 'Si', 'Si, claro', 'Claro que sí'];
|
||||
@@ -30,28 +31,32 @@ export default function PrefetchAbiertaCorta({
|
||||
isComunidad,
|
||||
obligatorio,
|
||||
onChange,
|
||||
preguntaComunidad,
|
||||
}: Props) {
|
||||
console.log(preguntaComunidad);
|
||||
let defaultValue = '';
|
||||
let disabled = false;
|
||||
|
||||
if (confirmativeOption.includes(isComunidad ?? '') && cuentaInfo) {
|
||||
if (validacion === 'nombre') {
|
||||
if (validacion === 'nombre' && cuentaInfo.nombre) {
|
||||
defaultValue = cuentaInfo.nombre;
|
||||
disabled = true;
|
||||
}
|
||||
if (validacion === 'apellidos') {
|
||||
if (validacion === 'apellidos' && cuentaInfo.apellidos) {
|
||||
defaultValue = cuentaInfo.apellidos;
|
||||
disabled = true;
|
||||
}
|
||||
if (validacion === 'correo') {
|
||||
if (validacion === 'correo' && cuentaInfo.correo) {
|
||||
defaultValue = cuentaInfo.correo;
|
||||
disabled = true;
|
||||
if (preguntaComunidad !== 'comunidad_trabajador') {
|
||||
disabled = true;
|
||||
}
|
||||
}
|
||||
if (validacion === 'institucion') {
|
||||
defaultValue = 'FES Acatlán';
|
||||
disabled = true;
|
||||
}
|
||||
if (validacion === 'carrera') {
|
||||
if (validacion === 'carrera' && cuentaInfo.carrera) {
|
||||
defaultValue = cuentaInfo.carrera;
|
||||
disabled = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
'use client'
|
||||
import MarkdownRenderer from '@/components/markdown-render';
|
||||
import { useGetApi } from '@/hooks/use-get-api';
|
||||
import Image from 'next/image';
|
||||
import React from 'react';
|
||||
import FormularioRegistro from '../formulario/formulario-registro';
|
||||
import { GetEventoWithCuestionario } from '@/types/evento';
|
||||
|
||||
export default function FormularioPage({
|
||||
id_evento,
|
||||
id_cuestionario,
|
||||
}: {
|
||||
id_evento: string;
|
||||
id_cuestionario: string;
|
||||
}) {
|
||||
const { data, error } = useGetApi<GetEventoWithCuestionario>(
|
||||
`/evento/${id_evento}/cuestionario/${id_cuestionario}`
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return <div>Error al cargar el cuestionario: {error.message}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container my-5">
|
||||
<div className="text-center mb-4">
|
||||
{data?.banner && (
|
||||
<Image
|
||||
src={`${process.env.NEXT_PUBLIC_API_URL}/banners/${data.banner}`}
|
||||
alt={data?.nombre_evento || ''}
|
||||
width={800}
|
||||
height={400}
|
||||
className="img-fluid rounded"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<h1>{data?.nombre_evento}</h1>
|
||||
{data?.descripcion_evento && (
|
||||
<MarkdownRenderer markdown={data?.descripcion_evento} />
|
||||
)}
|
||||
{data && (
|
||||
<FormularioRegistro
|
||||
id_cuestionario={data?.cuestionario.id_cuestionario}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user