feat: Implement event creation and management features for administrators

- Added page for creating forms associated with events, including template selection and validation of form dates against event dates.
- Created layout component to provide context for event-related pages.
- Developed event detail page with editing capabilities and form management.
- Introduced event creation page with banner upload functionality and preview.
- Implemented event listing page displaying active and recent events with associated forms.
- Added layout for user section including header, navbar, and footer.
- Created page for uploading teacher data from Excel files.
- Developed QR code scanning page for attendance registration with modal confirmation.
- Implemented login functionality with fake user data for testing purposes.
- Added event card preview component to display event details and banner.
This commit is contained in:
miguel
2025-08-14 20:27:25 -06:00
parent be8f207ecd
commit 7f2ab5b359
25 changed files with 1905 additions and 367 deletions
+75 -96
View File
@@ -26,107 +26,86 @@ export default function CreateEvento({
}: CreateEventoProps) {
return (
<div className="mt-2">
<div className="p-4 border rounded bg-light">
<h2 className="mb-2">Creación del Evento</h2>
<p className="mb-0 text-muted">
Completa la siguiente información para describir los detalles
generales del evento.
</p>
<p className="mb-0 text-muted">
Presiona siguiente para continuar con la creacion del formulario.
<h4 className="mb-3">Detalles del Evento</h4>
<div className="mb-2">
<ImageUploader
label="Banner del evento"
onChange={handleBannerChange}
showPreview={false}
/>
<p className="text-muted mt-2 mb-0 small">
<strong>
<i className="bi bi-info-circle-fill me-2"></i>
Esta es la imagen que se verá en el carrusel del evento.
</strong>
<br />
<strong>
<i className="bi bi-image me-2"></i>
Dimensiones recomendadas: 1200x600 píxeles.
</strong>
<br />
<strong>
<i className="bi bi-file-earmark-image me-2"></i>
Formatos soportados: PNG, JPG, JPEG.
</strong>
</p>
</div>
<div className="row mt-3">
{/* Columna Izquierda - Banner */}
<div className="col-lg-6">
<div className="pe-lg-3">
<ImageUploader
label="Banner del evento"
onChange={handleBannerChange}
/>
<p className="text-muted mt-2 small">
<strong>
<i className="bi bi-info-circle-fill me-2"></i>
Esta es la imagen que se verá en el carrusel del evento.
</strong>
<br />
<strong>
<i className="bi bi-image me-2"></i>
Dimensiones recomendadas: 1200x600 píxeles.
</strong>
<br />
<strong>
<i className="bi bi-file-earmark-image me-2"></i>
Formatos soportados: PNG, JPG, JPEG.
</strong>
</p>
</div>
<Input
label="Nombre del evento"
required
value={evento.nombre_evento}
onChange={(e) => handleChange('nombre_evento', e.target.value)}
/>
<div className="mb-4">
<label className="form-label">Descripción del evento</label>
<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={200}
commands={[commands.bold, commands.italic, commands.hr]}
/>
</div>
</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={tipoEventos}
/>
<div className="row">
<div className="col-md-6">
<Input
label="Fecha de inicio"
type="datetime-local"
className={{ container: 'mb-3' }}
value={formatDateLocal(evento.fecha_inicio)}
onChange={(e) =>
handleChange('fecha_inicio', new Date(e.target.value))
}
/>
</div>
{/* Columna Derecha - Detalles del Evento */}
<div className="col-lg-6">
<div className="ps-lg-3">
<h4 className="mb-3">Detalles del Evento</h4>
<Input
label="Nombre del evento"
required
value={evento.nombre_evento}
onChange={(e) => handleChange('nombre_evento', e.target.value)}
/>
<div className="mb-4">
<label className="form-label">Descripción del evento</label>
<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={200}
commands={[commands.bold, commands.italic, commands.hr]}
/>
</div>
</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={tipoEventos}
/>
<div className="row">
<div className="col-md-6">
<Input
label="Fecha de inicio"
type="datetime-local"
className={{ container: 'mb-3' }}
value={formatDateLocal(evento.fecha_inicio)}
onChange={(e) =>
handleChange('fecha_inicio', new Date(e.target.value))
}
/>
</div>
<div className="col-md-6">
<Input
label="Fecha de fin"
type="datetime-local"
className={{ container: 'mb-3' }}
value={formatDateLocal(evento.fecha_fin)}
onChange={(e) =>
handleChange('fecha_fin', new Date(e.target.value))
}
/>
</div>
</div>
</div>
<div className="col-md-6">
<Input
label="Fecha de fin"
type="datetime-local"
className={{ container: 'mb-3' }}
value={formatDateLocal(evento.fecha_fin)}
onChange={(e) =>
handleChange('fecha_fin', new Date(e.target.value))
}
/>
</div>
</div>
</div>