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
View File
@@ -193,3 +193,78 @@ export function formatearRangoFechas(
// Si tanto el año como el mes son diferentes
return `del ${diaInicio} de ${mesInicio} del ${añoInicio} al ${diaFin} de ${mesFin} del ${añoFin}`;
}
/**
* Formatea fechas para mostrar en las cartas de eventos, optimizando el espacio disponible.
* Retorna un objeto con el texto del mes y el texto del día para mostrar en la interfaz.
*
* @param {Date | string} fechaInicio - Fecha de inicio del evento.
* @param {Date | string} fechaFin - Fecha de fin del evento.
* @returns {{ mesTexto: string, diaTexto: string }} Objeto con texto del mes y día formateados.
* @throws {Error} Lanza un error si alguna de las fechas proporcionadas no es válida.
*
* @example
* formatearFechaCard(new Date('2025-08-15'), new Date('2025-08-15'));
* // Retorna: { mesTexto: 'AGO', diaTexto: '15' }
*
* @example
* formatearFechaCard(new Date('2025-08-15'), new Date('2025-08-20'));
* // Retorna: { mesTexto: 'AGO', diaTexto: '15 - 20' }
*
* @example
* formatearFechaCard(new Date('2025-08-28'), new Date('2025-09-05'));
* // Retorna: { mesTexto: 'AGO - SEP', diaTexto: '28 - 5' }
*/
export function formatearFechaCard(
fechaInicio: Date | string,
fechaFin: Date | string
): { mesTexto: string; diaTexto: string } {
// Convertir a Date si son strings
const inicio =
typeof fechaInicio === 'string' ? new Date(fechaInicio) : fechaInicio;
const fin = typeof fechaFin === 'string' ? new Date(fechaFin) : fechaFin;
if (isNaN(inicio.getTime())) {
throw new Error(`Fecha de inicio inválida: ${fechaInicio}`);
}
if (isNaN(fin.getTime())) {
throw new Error(`Fecha de fin inválida: ${fechaFin}`);
}
const mesInicioCorto = inicio
.toLocaleDateString('es-ES', { month: 'short' })
.toUpperCase();
const mesFinCorto = fin
.toLocaleDateString('es-ES', { month: 'short' })
.toUpperCase();
const diaInicio = inicio.getDate();
const diaFin = fin.getDate();
// Si es el mismo día
const esElMismoDia = inicio.toDateString() === fin.toDateString();
// Si es el mismo mes pero diferentes días
const esElMismoMes =
inicio.getMonth() === fin.getMonth() &&
inicio.getFullYear() === fin.getFullYear();
if (esElMismoDia) {
return {
mesTexto: mesInicioCorto,
diaTexto: diaInicio.toString(),
};
} else if (esElMismoMes) {
return {
mesTexto: mesInicioCorto,
diaTexto: `${diaInicio} - ${diaFin}`,
};
} else {
// Diferentes meses
return {
mesTexto: `${mesInicioCorto} - ${mesFinCorto}`,
diaTexto: `${diaInicio} - ${diaFin}`,
};
}
}