diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 8d7547d..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ee55cb3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# Scripts locales de arranque (Windows), no se versionan +*.bat + +# Sistema operativo +.DS_Store +Thumbs.db + +# Dependencias y variables de entorno (cada subproyecto ya las ignora, +# se cubre también aquí por si se generan en la raíz) +node_modules/ +.env +.env.* +!.env.example + +# Editores +.vscode/ +.idea/ + +# Configuración local de Claude Code (no necesaria para producción) +.claude/ diff --git a/backend/src/bootstrapEasyFestPermissions.js b/backend/src/bootstrapEasyFestPermissions.js index 7ff6152..7ed54b0 100644 --- a/backend/src/bootstrapEasyFestPermissions.js +++ b/backend/src/bootstrapEasyFestPermissions.js @@ -1,306 +1,299 @@ +// Este bootstrap se ejecuta en cada arranque de Strapi (ver `src/index.js`), incluido +// cada despliegue. `roleService.updateRole` REEMPLAZA el árbol de permisos completo del +// rol al que se llama: cualquier permiso activado a mano desde el panel de admin que no +// esté aquí listado se desactiva en el siguiente arranque. Por eso este archivo debe ser +// la fuente de verdad de TODO lo que necesita el rol Public y el rol Authenticated: si +// falta algo aquí, "se borra solo" al desplegar. + +// Permisos de solo lectura que necesitan tanto Public como Authenticated (un usuario +// logueado sigue viendo el mismo contenido público de la web). +const readOnlyApiPermissions = { + 'api::about-us': { + controllers: { + 'about-us': { + find: { enabled: true, policy: '' } + } + } + }, + 'api::accommodation-info': { + controllers: { + 'accommodation-info': { + find: { enabled: true, policy: '' } + } + } + }, + 'api::agenda': { + controllers: { + agenda: { + find: { enabled: true, policy: '' } + } + } + }, + 'api::code-of-conduct': { + controllers: { + 'code-of-conduct': { + find: { enabled: true, policy: '' } + } + } + }, + 'api::contact-info': { + controllers: { + 'contact-info': { + find: { enabled: true, policy: '' } + } + } + }, + 'api::contact-type': { + controllers: { + 'contact-type': { + find: { enabled: true, policy: '' }, + findOne: { enabled: true, policy: '' } + } + } + }, + 'api::cookie-policy': { + controllers: { + 'cookie-policy': { + find: { enabled: true, policy: '' } + } + } + }, + 'api::enrollment': { + controllers: { + enrollment: { + find: { enabled: true, policy: '' } + } + } + }, + 'api::faq': { + controllers: { + faq: { + find: { enabled: true, policy: '' }, + findOne: { enabled: true, policy: '' } + } + } + }, + 'api::homepage': { + controllers: { + homepage: { + find: { enabled: true, policy: '' } + } + } + }, + 'api::news-item': { + controllers: { + 'news-item': { + find: { enabled: true, policy: '' }, + findOne: { enabled: true, policy: '' } + } + } + }, + 'api::newsletter-subscription': { + controllers: { + 'newsletter-subscription': { + find: { enabled: true, policy: '' }, + findOne: { enabled: true, policy: '' } + } + } + }, + 'api::org-team': { + controllers: { + 'org-team': { + find: { enabled: true, policy: '' } + } + } + }, + 'api::press-kit': { + controllers: { + 'press-kit': { + find: { enabled: true, policy: '' } + } + } + }, + 'api::privacy-policy': { + controllers: { + 'privacy-policy': { + find: { enabled: true, policy: '' } + } + } + }, + 'api::profile-contact': { + controllers: { + 'profile-contact': { + find: { enabled: true, policy: '' }, + findOne: { enabled: true, policy: '' } + } + } + }, + 'api::public-profile': { + controllers: { + 'public-profile': { + find: { enabled: true, policy: '' }, + findOne: { enabled: true, policy: '' } + } + } + }, + 'api::registration-info': { + controllers: { + 'registration-info': { + find: { enabled: true, policy: '' } + } + } + }, + 'api::seo': { + controllers: { + seo: { + find: { enabled: true, policy: '' } + } + } + }, + 'api::setting': { + controllers: { + setting: { + find: { enabled: true, policy: '' } + } + } + }, + 'api::simple-page': { + controllers: { + 'simple-page': { + find: { enabled: true, policy: '' } + } + } + }, + 'api::site': { + controllers: { + site: { + find: { enabled: true, policy: '' } + } + } + }, + 'api::speakers': { + controllers: { + speakers: { + find: { enabled: true, policy: '' } + } + } + }, + 'api::sponsor': { + controllers: { + sponsor: { + find: { enabled: true, policy: '' }, + findOne: { enabled: true, policy: '' } + } + } + }, + 'api::sponsors-info': { + controllers: { + 'sponsors-info': { + find: { enabled: true, policy: '' } + } + } + }, + 'api::streaming': { + controllers: { + streaming: { + find: { enabled: true, policy: '' } + } + } + }, + 'api::track': { + controllers: { + track: { + find: { enabled: true, policy: '' }, + findOne: { enabled: true, policy: '' } + } + } + }, + 'api::venue-info': { + controllers: { + 'venue-info': { + find: { enabled: true, policy: '' } + } + } + } +}; + +// `activity` necesita distinto alcance según el rol: cualquier visitante puede leer la +// agenda, pero solo un usuario logueado puede apuntarse/desapuntarse (update, usado por +// `/me` para conectar/desconectar `registered_users`/`queued_users`). +const activityPermissions = (withUpdate) => ({ + 'api::activity': { + controllers: { + activity: { + find: { enabled: true, policy: '' }, + findOne: { enabled: true, policy: '' }, + ...(withUpdate ? { update: { enabled: true, policy: '' } } : {}) + } + } + } +}); + +const publicOnlyPermissions = { + // Formulario de inscripción (create-only, sin lectura pública de inscripciones). + 'api::registration': { + controllers: { + registration: { + find: { enabled: false, policy: '' }, + findOne: { enabled: false, policy: '' }, + create: { enabled: true, policy: '' } + } + } + }, + // Login, "olvidé mi contraseña" y "restablecer contraseña" del plugin de usuarios: + // sin esto, esas pantallas devuelven 403 tras cada despliegue. + 'plugin::users-permissions': { + controllers: { + auth: { + callback: { enabled: true, policy: '' }, + forgotPassword: { enabled: true, policy: '' }, + resetPassword: { enabled: true, policy: '' } + } + } + }, + // Necesario para la búsqueda de ficheros subidos que usa la home (`/api/upload/files`). + 'plugin::upload': { + controllers: { + 'content-api': { + find: { enabled: true, policy: '' } + } + } + } +}; + +const authenticatedOnlyPermissions = { + // `/me` usa esta acción para leer los datos y actividades del usuario logueado. + 'plugin::users-permissions': { + controllers: { + user: { + me: { enabled: true, policy: '' } + } + } + } +}; + const grantEasyFestPublicApiPermissions = (strapi) => async () => { + const roleService = strapi.plugin('users-permissions').service('role'); + const publicRole = await strapi .query('plugin::users-permissions.role') .findOne({ where: { type: 'public' } }); - const publicRoleId = publicRole.id; + await roleService.updateRole(publicRole.id, { + permissions: { + ...readOnlyApiPermissions, + ...activityPermissions(false), + ...publicOnlyPermissions + } + }); - const roleService = strapi.plugin('users-permissions').service('role'); - await roleService.updateRole(publicRoleId, { + const authenticatedRole = await strapi + .query('plugin::users-permissions.role') + .findOne({ where: { type: 'authenticated' } }); + await roleService.updateRole(authenticatedRole.id, { permissions: { - 'api::about-us': { - controllers: { - 'about-us': { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::accommodation-info': { - controllers: { - 'accommodation-info': { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::activity': { - controllers: { - activity: { - find: { enabled: true, policy: '' }, - findOne: { enabled: true, policy: '' } - // create: { enabled: false, policy: '' }, - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::agenda': { - controllers: { - agenda: { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::code-of-conduct': { - controllers: { - 'code-of-conduct': { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::contact-info': { - controllers: { - 'contact-info': { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::contact-type': { - controllers: { - 'contact-type': { - find: { enabled: true, policy: '' }, - findOne: { enabled: true, policy: '' } - // create: { enabled: false, policy: '' }, - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' } - } - } - }, - 'api::cookie-policy': { - controllers: { - 'cookie-policy': { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::faq': { - controllers: { - faq: { - find: { enabled: true, policy: '' }, - findOne: { enabled: true, policy: '' } - // create: { enabled: false, policy: '' }, - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::homepage': { - controllers: { - homepage: { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' } - } - } - }, - 'api::news-item': { - controllers: { - 'news-item': { - find: { enabled: true, policy: '' }, - findOne: { enabled: true, policy: '' } - // create: { enabled: false, policy: '' }, - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::newsletter-subscription': { - controllers: { - 'newsletter-subscription': { - find: { enabled: true, policy: '' }, - findOne: { enabled: true, policy: '' } - // create: { enabled: false, policy: '' }, - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' } - } - } - }, - 'api::org-team': { - controllers: { - 'org-team': { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::press-kit': { - controllers: { - 'press-kit': { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::privacy-policy': { - controllers: { - 'privacy-policy': { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::profile-contact': { - controllers: { - 'profile-contact': { - find: { enabled: true, policy: '' }, - findOne: { enabled: true, policy: '' } - // create: { enabled: false, policy: '' }, - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' } - } - } - }, - 'api::public-profile': { - controllers: { - 'public-profile': { - find: { enabled: true, policy: '' }, - findOne: { enabled: true, policy: '' } - // create: { enabled: false, policy: '' }, - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::registration': { - controllers: { - registration: { - find: { enabled: false, policy: '' }, - findOne: { enabled: false, policy: '' }, - create: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' } - } - } - }, - 'api::registration-info': { - controllers: { - 'registration-info': { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::seo': { - controllers: { - seo: { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::setting': { - controllers: { - setting: { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::site': { - controllers: { - site: { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' } - } - } - }, - 'api::speakers': { - controllers: { - speakers: { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::sponsor': { - controllers: { - sponsor: { - find: { enabled: true, policy: '' }, - findOne: { enabled: true, policy: '' } - // create: { enabled: false, policy: '' }, - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::sponsors-info': { - controllers: { - 'sponsors-info': { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::streaming': { - controllers: { - streaming: { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::track': { - controllers: { - track: { - find: { enabled: true, policy: '' }, - findOne: { enabled: true, policy: '' } - // create: { enabled: false, policy: '' }, - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - }, - 'api::venue-info': { - controllers: { - 'venue-info': { - find: { enabled: true, policy: '' } - // update: { enabled: false, policy: '' }, - // delete: { enabled: false, policy: '' }, - // createLocalization: { enabled: false, policy: '' } - } - } - } + ...readOnlyApiPermissions, + ...activityPermissions(true), + ...authenticatedOnlyPermissions } }); }; diff --git a/backend/src/index.js b/backend/src/index.js index 519e389..17ef69c 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -1,7 +1,6 @@ 'use strict'; const saveAndPublishEasyFestDefaultEntities = require('./bootstrapEasyFestDefaultEntities.js') -const grantEasyFestPublicApiPermissions = require('./bootstrapEasyFestPermissions.js'); module.exports = { /** @@ -22,6 +21,10 @@ module.exports = { async bootstrap({ strapi }) { await saveAndPublishEasyFestDefaultEntities(strapi)() - await grantEasyFestPublicApiPermissions(strapi)() + // Los permisos de Public/Authenticated ya NO se reescriben en cada arranque: + // lo que esté configurado en Strapi (Settings > Users & Permissions > Roles) + // se respeta tal cual, no se sobrescribe ni se borra en el despliegue. + // `bootstrapEasyFestPermissions.js` se deja en el repo sin usar por si hace + // falta consultarlo o reactivarlo más adelante. }, }; diff --git a/frontend/messages/es.json b/frontend/messages/es.json index 391a1ae..741ed6c 100644 --- a/frontend/messages/es.json +++ b/frontend/messages/es.json @@ -56,7 +56,7 @@ "privacy_policy": "Política de privacidad", "register": "Registro", "registration": "Inscripción", - "reset_password_sent": "Si tu correo está registrado, hemos enviado un mensaje con un enlace para establecer una contraseña nueva.", + "reset_password_sent": "Si tu correo está registrado, se enviará un mensaje con un enlace para establecer una contraseña nueva.", "send": "Enviar", "speakers": "Invitadas", "sponsors": "EstelTienda", diff --git a/frontend/src/app.scss b/frontend/src/app.scss index da12dc6..26dfdfc 100644 --- a/frontend/src/app.scss +++ b/frontend/src/app.scss @@ -82,6 +82,52 @@ $control-border-width: 0.125rem; // 2px font-family: $font-family; } +// Controles de formulario (input/textarea/select): texto y placeholder con +// la tipografia secundaria (Lora) del cuerpo. Los navegadores no hacen que +// estos elementos hereden la fuente del body por defecto, así que hay que +// fijarlo explícitamente; se hace aquí una sola vez para toda la web en vez +// de repetirlo formulario a formulario. +.input, +.textarea, +.select select { + font-family: $font-family-secondary; +} + +.input::placeholder, +.textarea::placeholder { + font-family: $font-family-secondary; +} + +// Frases-enlace bajo los campos de un formulario (p.ej. "¿Olvidaste tu +// contraseña? Pulsa aquí."): tipografia secundaria, centradas como bloque y +// adaptadas al ancho del contenedor para que el texto pase a otra linea si +// no cabe en una sola, en vez del inline-flex sin ajustar de Bulma. +.button.is-text { + display: block; + width: 100%; + height: auto; + min-height: 2.5em; + white-space: normal; + text-align: center; + line-height: 1.3; + font-family: $font-family-secondary; +} + +// Botones: texto con la tipografia primaria (Cinzel) en vez de heredar la +// secundaria (Lora) del body. Se usa la custom property que expone Bulma +// (--bulma-family-primary) en vez de fijar el valor a fuego, siguiendo el +// mismo patron ya usado en varios botones sueltos del sitio. +.button { + font-family: var(--bulma-family-primary, #{$font-family-primary}); +} + +// Ayudas de formulario (.help): las de error de validacion (is-danger) +// mantienen el rojo de Bulma; el resto (mensajes informativos/de exito) +// usan el color secundario del sistema de diseno. +.help:not(.is-danger) { + color: $color-secondary; +} + .header--large { @include ec-typography(1.2, 3em, $font-family-secondary); @include mixins.tablet { diff --git a/frontend/src/lib/ActivityModal.svelte b/frontend/src/lib/ActivityModal.svelte index fead85b..cd1d8cf 100644 --- a/frontend/src/lib/ActivityModal.svelte +++ b/frontend/src/lib/ActivityModal.svelte @@ -1,17 +1,13 @@ @@ -32,30 +36,30 @@ {activityHour(activity)} · {activity.title}

- {#if activity.short_description || (activity.public_faces && activity.public_faces.length > 0)} + {#if activity.short_description || hasPublicFaces(activity)}
- {#if activity.short_description} -

{activity.short_description}

- {/if} - - {#each activity.public_faces as pf} - {#if activity.public_faces} - - handleProfileClick(pf)}> -
-
- -
-
-
- {pf.fullname} + {#if hasPublicFaces(activity)} + {#each activity.public_faces as pf} +
-
- {/if} - {/each} + {/if} + + + {/each} + {:else if activity.short_description} +

{activity.short_description}

+ {/if} {#if activity.tag2}

@@ -138,22 +142,49 @@ word-break: break-word; } - .card .media { - margin-bottom: 0; + /* Botón de ponente: se distingue claramente de la tarjeta (fondo, borde y + cursor propios) para que quede claro que es un control aparte, con su + propio clic, y no parte del texto de la actividad. */ + .public-face { + display: flex; + align-items: center; + gap: 0.5rem; + width: 100%; + margin: 0.5rem 0 0; + padding: 0.35rem 0.6rem; + background: rgba(67, 178, 220, 0.12); + border: 1px solid rgba(13, 59, 68, 0.18); + border-radius: 999px; + font: inherit; + text-align: left; + cursor: pointer; + transition: + background 0.18s ease, + border-color 0.18s ease; + } + + .public-face:first-child { + margin-top: 0; + } + + .public-face:hover, + .public-face:focus-visible { + background: rgba(67, 178, 220, 0.24); + border-color: rgba(13, 59, 68, 0.32); } - .media + .media { - margin-top: 0.25rem; - padding-top: 0.25rem; + .public-face:focus-visible { + outline: 2px solid #43b2dc; + outline-offset: 1px; } - .public-face .content { + .public-face .image { + flex-shrink: 0; + } + + .public-face__name { font-size: 0.96rem; /* 20% menos que el tamaño heredado (1.2rem) */ - text-align: left; - /* Sin límite de líneas: que use el espacio que haya. .media es flex, así - que también necesita min-width:0 para poder envolver en vez de - desbordar (mismo motivo que .card-header-title). El único límite real - es el overflow:hidden de .card/.card-content si de verdad no cabe. */ + color: #0d3b44; min-width: 0; overflow-wrap: break-word; word-break: break-word; diff --git a/frontend/src/routes/forgot-password/+page.svelte b/frontend/src/routes/forgot-password/+page.svelte index 12f9c05..6dbaf24 100644 --- a/frontend/src/routes/forgot-password/+page.svelte +++ b/frontend/src/routes/forgot-password/+page.svelte @@ -60,20 +60,3 @@

- \ No newline at end of file diff --git a/frontend/src/routes/login/+page.svelte b/frontend/src/routes/login/+page.svelte index 9b4e872..93d1732 100644 --- a/frontend/src/routes/login/+page.svelte +++ b/frontend/src/routes/login/+page.svelte @@ -78,31 +78,3 @@ - - diff --git a/frontend/src/routes/me/+page.server.js b/frontend/src/routes/me/+page.server.js index f431aa6..5dda553 100644 --- a/frontend/src/routes/me/+page.server.js +++ b/frontend/src/routes/me/+page.server.js @@ -1,7 +1,13 @@ import { redirect } from '@sveltejs/kit'; +import { dev } from '$app/environment'; import { fetchCMSData, fetchCollection, fetchSingle, fetchBasic } from '../../services/api'; import { isAuthorizedUser } from '../../services/users'; +// En local (`npm run dev`) forzamos la inscripción a actividades activa para poder +// probarla sin tener que tocar el flag en Strapi. En producción no tiene efecto. +const withActivityRegistrationOverride = (settings) => + dev ? { ...settings, show_activity_registration: true } : settings; + /** @type {import('./$types').PageLoad} */ export async function load({ cookies, url }) { @@ -9,34 +15,42 @@ export async function load({ cookies, url }) { redirect(302, "/login"); } - const activeTab = url.searchParams.get("tab") || "datos"; + const activeTab = url.searchParams.get("tab") || "datos"; - const [settings, user, allActivities] = await Promise.all([ + const [rawSettings, user, allActivities] = await Promise.all([ fetchSingle("/setting"), fetchBasic("/users/me?populate[activities_registered][filters][publishedAt][$notNull]=true&populate[activities_registered][populate][track]=true&populate[activities_queued][filters][publishedAt][$notNull]=true&populate[activities_queued][populate][track]=true&populate[activities_staff][filters][publishedAt][$notNull]=true&populate[activities_staff][populate][track]=true", cookies), fetchCollection("/activities?filters[needs_registration][$eq]=true&sort=title:asc", cookies), ]); + const settings = withActivityRegistrationOverride(rawSettings); if (!user) { redirect(302, "/login"); } - // Filter out activities already registered by this user. + // Filter out activities already registered by this user, and (for minors) + // activities marked as not allowed for them (`format`, ver ActivityCard.svelte). const registeredIds = new Set((user.activities_registered ?? []).map(activity => activity.id)); const queuedIds = new Set((user.activities_queued ?? []).map(activity => activity.id)); - const activities = allActivities.filter(activity => !registeredIds.has(activity.id) && (!queuedIds.has(activity.id))); + const isMinor = user.age === 'Menor'; + const activities = allActivities.filter(activity => + !registeredIds.has(activity.id) && + !queuedIds.has(activity.id) && + !(isMinor && activity.format) + ); return { settings, user, activities, activeTab }; - + } export const actions = { signIn: async ({ url, cookies }) => { - const activityId = url.searchParams.get("activityId"); - const [settings, user, activity] = await Promise.all([ + const activityId = url.searchParams.get("activityId"); + const [rawSettings, user, activity] = await Promise.all([ fetchSingle("/setting"), fetchBasic("/users/me", cookies), fetchSingle(`/activities/${activityId}?populate[registered_users][count]=true`, cookies), ]); + const settings = withActivityRegistrationOverride(rawSettings); if (!settings.show_activity_registration) { return { success: false, message: "La inscripción a actividades no está activada." }; } @@ -90,12 +104,13 @@ export const actions = { }, signOut: async ({ url, cookies }) => { - const activityId = url.searchParams.get("activityId"); - const [settings, user, activity] = await Promise.all([ + const activityId = url.searchParams.get("activityId"); + const [rawSettings, user, activity] = await Promise.all([ fetchSingle("/setting"), fetchBasic("/users/me", cookies), fetchSingle(`/activities/${activityId}`, cookies), ]); + const settings = withActivityRegistrationOverride(rawSettings); if (!settings.show_activity_registration) { return { success: false, message: "La inscripción a actividades no está activada." }; } @@ -126,12 +141,13 @@ export const actions = { }, signOutQueued: async ({ url, cookies }) => { - const activityId = url.searchParams.get("activityId"); - const [settings, user, activity] = await Promise.all([ + const activityId = url.searchParams.get("activityId"); + const [rawSettings, user, activity] = await Promise.all([ fetchSingle("/setting"), fetchBasic("/users/me", cookies), fetchSingle(`/activities/${activityId}`, cookies), ]); + const settings = withActivityRegistrationOverride(rawSettings); if (!settings.show_activity_registration) { return { success: false, message: "La inscripción a actividades no está activada." }; } @@ -160,4 +176,4 @@ export const actions = { return { success: false, message: error.message }; } } -}; \ No newline at end of file +}; diff --git a/frontend/src/routes/register/+page.server.js b/frontend/src/routes/register/+page.server.js index b64dbb5..df7809e 100644 --- a/frontend/src/routes/register/+page.server.js +++ b/frontend/src/routes/register/+page.server.js @@ -38,4 +38,4 @@ export const actions = { const result = (response ? "éxito" : error?.message); return message(form, result); } - }; \ No newline at end of file + }; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index bf7077f..0000000 --- a/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "e2026-main", - "lockfileVersion": 3, - "requires": true, - "packages": {} -}