Skip to content

DS-6096 integation form flow#34

Merged
MatiasRoy-Rodriguez merged 6 commits into
mainfrom
feature/DS-6096-integation-form-flow
May 15, 2026
Merged

DS-6096 integation form flow#34
MatiasRoy-Rodriguez merged 6 commits into
mainfrom
feature/DS-6096-integation-form-flow

Conversation

@MatiasRoy-Rodriguez
Copy link
Copy Markdown
Contributor

PR: conectar el form email-first del hero con el endpoint de estado de registro

TL;DR

Se conecta el form de dos pasos del hero (ya está en el DOM con data-registration-flow="email-first") contra el endpoint de estado de registro que se shipeó en #32. El paso 1 recibe el email y le pregunta al endpoint si el usuario ya está registrado para el evento actual. Si lo está → redirect a la experiencia registrada. Si no (o el endpoint falla) → revela el paso 2 (nombre / WhatsApp / política / promociones) y submitea a través del pipeline de registro existente. No hay pantallas intermedias, no hay barra de progreso — redirect directo en ambos estados terminales.

  • El check está acotado al evento: un usuario registrado en ECOMMERCE NO va a ser tratado como registrado en una landing de DIGITALTRENDS. El evento lo resuelve server-side checkRegistrationStatus.php vía getCurrentEvent(); el cliente solo manda {email}. Esto es a propósito — el cliente no puede consultar por un evento distinto al de la landing donde está parado.
  • El flow está gateado: el módulo nuevo se inicializa solo cuando el form tiene data-registration-flow="email-first". Todos los paths legacy (modal de extra data, los CTAs .alreadyRegisterForm, sponsors quick-submit, alreadyAccountForm) quedan byte por byte intactos.
  • El flow falla abierto (fail-open): si el endpoint de estado tira 500 o se cae la red, igual se revela el paso 2. services/register.php es la fuente de verdad y deduplica server-side. Que el check esté caído un rato no puede dejar a los usuarios afuera del registro.

Cambios por archivo

src/1.0.0/js/heroRegistrationFlow.js — módulo nuevo

Export único: initHeroRegistrationFlow(form). Internamente:

  • Cachea stepOneEl, stepTwoEl, stepOneButton, stepTwoButton al momento del init. El botón del paso 2 NO se busca con form.querySelector("button") al momento del handler (ese selector devuelve el botón del paso 1 oculto — ver más abajo el gotcha del loading).
  • handleEmailStep: valida el email, postea a checkRegistrationStatus, redirige si true, revela paso 2 si false o null (fail-open).
  • handleSubmitStep: rutea el submit del paso 2 al submitFormFetch existente, redirige cuando fetchResp.ok. El único call site de customError está en el catch — las ramas internas hacen throw para no reportar errores dos veces.
  • setButtonLoading(button, isLoading): helper local que togglea button--loading Y button.disabled sobre la referencia cacheada. Ambos handlers también hacen early-return cuando button.disabled === true (defensa contra double-tap de iOS y otros casos de doble-fire en mobile).
  • Listener form-level de submit que llama preventDefault() — defense in depth contra un Enter en el input de email. Los botones son type="button", así que en la práctica no debería dispararse, pero el listener es barato y elimina ambigüedad.
  • goToStepTwo: togglea [hidden], mirrorea form.dataset.step = "2", mueve el foco al input de nombre. Honra prefers-reduced-motion — cuando está activado, el swap es sincrónico (sin animación, sin setTimeout). Si no, corre un cross-fade de 280ms (ver CSS abajo).
  • En la rama "ya está registrado", escribe dplrid + events en localStorage vía el helper existente setEventInLocalStorage ANTES de redirigir. Eso mantiene paridad de storage con el path post-submit, así la landing registrada lee las mismas keys sin importar cómo llegó el usuario.

src/1.0.0/js/common/submitForm.js

  • Nuevo checkRegistrationStatus(email) que devuelve Promise<boolean | null>. POST {"email": "..."} only (sin campo de evento) a /services/checkRegistrationStatus.php. Devuelve true si registrado, false si no, null ante fallo de transporte / HTTP no-OK / JSON inválido. Loguea errores de red con console.warn.
  • redirectToRegisteredPage() mudado acá desde commonForm.js (el caso especial del slug de sponsors se preservó textual). Esto evita el ciclo de imports que se formaría si no entre commonForm.js y heroRegistrationFlow.js.
  • Se agregó un JSDoc sobre submitFormFetch documentando su contrato tri-state (undefined si falla validación cliente, null si falla red, objeto en éxito). El contrato ya existía; el JSDoc solo lo explicita para que un futuro caller no destructure un null/undefined y crashee.
  • El path del endpoint es absoluto (/services/checkRegistrationStatus.php), no relativo — protege contra landings en sub-rutas (ej. /sponsors).

src/1.0.0/js/common/formsValidators.js

  • Nuevo validateEmailStep(form): compone validateEmptyField y validateEmailField sobre el input[name="email"] del form. Devuelve un boolean plano. El rendering de errores reusa el path existente (setErrorField) a través de esos dos helpers — no se introduce ningún helper de error nuevo.

src/1.0.0/js/commonForm.js

  • El redirectToRegisteredPage local se eliminó; ahora se importa desde ./common/submitForm.js.
  • Import nuevo: initHeroRegistrationFlow desde ./heroRegistrationFlow.js.
  • El bloque if (form) { ... } ahora despacha: si form.dataset.registrationFlow === "email-first"initHeroRegistrationFlow(form); si no → el wiring legacy (listener de submitFormHandler + swichFormListener) corre intacto.
  • Las otras ramas (modalForm, extraData, alreadyRegisterButtons, alreadyAccountForm) quedan sin tocar.

src/1.0.0/css/components/form.css

  • Cross-fade entre steps: 280ms ease sobre opacity y transform, con un translateY chico de ±8px para dar pista direccional (el paso 1 sale hacia arriba, el paso 2 entra desde abajo).
  • .is-leaving y .is-entering son clases de estado scopeadas bajo .emms__form--two-step .emms__form__step. Sin modifier BEM porque son estados transitorios de UI, no una variante del componente.
  • prefers-reduced-motion: reduce clampea transition-duration a 1ms y saca el translateY. Defense in depth arriba del guard de JS.

Resumen del flujo

[paso 1]
   │  usuario tipea email, clickea botón
   ▼
validateEmailStep ── falla ──► error inline, stop
   │
   │  pasa
   ▼
POST /services/checkRegistrationStatus.php  { email }
   │
   ├── registered: true  ─► setEventInLocalStorage → redirectToRegisteredPage
   │
   └── registered: false  O  null (5xx / red)
           │
           ▼
       [se revela paso 2 con cross-fade, foco al input "name"]
           │
           │  usuario completa, clickea botón
           ▼
       submitFormFetch (pipeline existente) ─► redirectToRegisteredPage

Related to: Ticket

@mcappato
Copy link
Copy Markdown
Collaborator

Mati, revisaría validateEmailStep: hoy usa validateEmptyField + validateEmailField, pero no queda enganchado el listener para limpiar el error cuando el usuario vuelve a escribir. No lo veo bloqueante, pero puede dejar el error visual visible hasta el siguiente intento.

Fuera de eso, lo veo bien.

@MatiasRoy-Rodriguez MatiasRoy-Rodriguez merged commit 5859a31 into main May 15, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants