feat: Implement event and questionnaire management features
- Added event creation page with form handling and validation. - Introduced layout for event management with context provider. - Created event listing page with active and recent events display. - Developed questionnaire creation page linked to events. - Implemented breadcrumb navigation for better user experience. - Added reusable components for event and questionnaire cards. - Integrated API calls for fetching and managing event data. - Enhanced slugify utility for better URL handling. - Established context for managing event state across components.
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
export const tipoEventos = [
|
||||
{ label: 'Conferencia', value: 'conferencia' },
|
||||
{ label: 'Taller', value: 'taller' },
|
||||
{ label: 'Seminario', value: 'seminario' },
|
||||
{ label: 'Curso', value: 'curso' },
|
||||
{ label: 'Webinar', value: 'webinar' },
|
||||
{ label: 'Reunión', value: 'reunion' },
|
||||
{ label: 'Feria', value: 'feria' },
|
||||
{ label: 'Concierto', value: 'concierto' },
|
||||
{ label: 'Exposición', value: 'exposicion' },
|
||||
{ label: 'Deportivo', value: 'deportivo' },
|
||||
{ label: 'Cultural', value: 'cultural' },
|
||||
{ label: 'Otro', value: 'otro' },
|
||||
];
|
||||
+90
-1
@@ -28,7 +28,6 @@
|
||||
export function formatFecha(
|
||||
fechaStr: string,
|
||||
config: { horas?: boolean; minutos?: boolean; diaSemana?: boolean } = {
|
||||
|
||||
horas: false,
|
||||
minutos: false,
|
||||
diaSemana: false,
|
||||
@@ -104,3 +103,93 @@ export function formatDateLocal(date: Date): string {
|
||||
|
||||
return `${yyyy}-${MM}-${dd}T${hh}:${mm}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatea un rango de fechas en español, optimizando la salida según si coinciden año, mes y día.
|
||||
*
|
||||
* @param {string} fechaInicio - Fecha de inicio en formato ISO 8601 (ej: '2025-08-13T18:44:00.000Z').
|
||||
* @param {string} fechaFin - Fecha de fin en formato ISO 8601 (ej: '2025-08-15T18:44:00.000Z').
|
||||
* @returns {string} Rango de fechas formateado en español.
|
||||
* @throws {Error} Lanza un error si alguna de las fechas proporcionadas no es válida.
|
||||
*
|
||||
* @example
|
||||
* formatearRangoFechas('2025-08-13T12:00:00.000Z', '2025-08-13T18:00:00.000Z');
|
||||
* // Retorna: "el 13 de agosto del 2025 de 12:00 a 18:00"
|
||||
*
|
||||
* @example
|
||||
* formatearRangoFechas('2025-08-13T18:44:00.000Z', '2025-08-15T18:44:00.000Z');
|
||||
* // Retorna: "del 13 al 15 de agosto del 2025"
|
||||
*
|
||||
* @example
|
||||
* formatearRangoFechas('2025-08-13T18:44:00.000Z', '2025-09-13T18:44:00.000Z');
|
||||
* // Retorna: "del 13 de agosto al 13 de septiembre del 2025"
|
||||
*
|
||||
* @example
|
||||
* formatearRangoFechas('2025-08-13T18:44:00.000Z', '2026-01-13T18:44:00.000Z');
|
||||
* // Retorna: "del 13 de agosto del 2025 al 13 de enero del 2026"
|
||||
*/
|
||||
export function formatearRangoFechas(
|
||||
fechaInicio: string,
|
||||
fechaFin: string
|
||||
): string {
|
||||
const inicio = new Date(fechaInicio);
|
||||
const fin = new Date(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 meses = [
|
||||
'enero',
|
||||
'febrero',
|
||||
'marzo',
|
||||
'abril',
|
||||
'mayo',
|
||||
'junio',
|
||||
'julio',
|
||||
'agosto',
|
||||
'septiembre',
|
||||
'octubre',
|
||||
'noviembre',
|
||||
'diciembre',
|
||||
];
|
||||
|
||||
const diaInicio = inicio.getUTCDate();
|
||||
const mesInicio = meses[inicio.getUTCMonth()];
|
||||
const añoInicio = inicio.getUTCFullYear();
|
||||
|
||||
const diaFin = fin.getUTCDate();
|
||||
const mesFin = meses[fin.getUTCMonth()];
|
||||
const añoFin = fin.getUTCFullYear();
|
||||
|
||||
// Si es el mismo día (año, mes y día iguales)
|
||||
if (
|
||||
añoInicio === añoFin &&
|
||||
inicio.getUTCMonth() === fin.getUTCMonth() &&
|
||||
diaInicio === diaFin
|
||||
) {
|
||||
const horaInicio = (inicio.getUTCHours() - 6 + 24) % 24;
|
||||
const minutosInicio = inicio.getUTCMinutes().toString().padStart(2, '0');
|
||||
const horaFin = (fin.getUTCHours() - 6 + 24) % 24;
|
||||
const minutosFin = fin.getUTCMinutes().toString().padStart(2, '0');
|
||||
|
||||
return `el ${diaInicio} de ${mesInicio} del ${añoInicio} de ${horaInicio}:${minutosInicio} a ${horaFin}:${minutosFin}`;
|
||||
}
|
||||
|
||||
// Si el año y mes son iguales pero días diferentes
|
||||
if (añoInicio === añoFin && inicio.getUTCMonth() === fin.getUTCMonth()) {
|
||||
return `del ${diaInicio} al ${diaFin} de ${mesInicio} del ${añoInicio}`;
|
||||
}
|
||||
|
||||
// Si el año es igual pero el mes es diferente
|
||||
if (añoInicio === añoFin) {
|
||||
return `del ${diaInicio} de ${mesInicio} al ${diaFin} de ${mesFin} del ${añoInicio}`;
|
||||
}
|
||||
|
||||
// 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}`;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// slugify.ts
|
||||
export function slugify(input: string, maxLen = 60) {
|
||||
return input
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '')
|
||||
.slice(0, maxLen);
|
||||
}
|
||||
|
||||
// Combina slug + id (id al final facilita parsear con "último -")
|
||||
export function toParam(name: string, id: string | number) {
|
||||
return `${slugify(name)}-${id}`;
|
||||
}
|
||||
|
||||
// Extrae { id, slug } de un param con formato "slug-123"
|
||||
export function fromParam(param: string) {
|
||||
const lastDash = param.lastIndexOf('-');
|
||||
if (lastDash === -1) return { slug: param, id: null };
|
||||
const slug = param.slice(0, lastDash);
|
||||
const idStr = param.slice(lastDash + 1);
|
||||
const id = /^\d+$/.test(idStr) ? Number(idStr) : null;
|
||||
return { slug, id };
|
||||
}
|
||||
Reference in New Issue
Block a user