Purpose#
The Invitation component completes a user registration flow that is initiated by an invitation link (tokenized URL).It renders a registration form that:shows the invited email (readonly/disabled)
collects first name and last name
collects password + confirm password
validates required fields, password strength, and password match
submits registration via the theme services layer using the invitation token
shows toast feedback and redirects to /login on success
Model shape (storefront example)#
{
"name": "Invitation",
"view": "Default",
"section": "SectionA",
"settings": {
"id": "Component Id",
"section": "SectionA",
"type": "NoirInvitation",
"name": "Invitation",
"configuredInContentApi": true,
"view": "Default",
"displayName": "",
"cssClass": ""
},
"translations": {
"invitation": "Sample text",
"firstNamePlaceholder": "Sample text",
"lastNamePlaceholder": "Sample text",
"...": "..."
}
}
Required fields#
settings.id
Used for wrapper id: comp-{{ id }} and for deterministic DOM ids (inputs are suffixed with -{{ id }}).
Optional fields#
settings.cssClass
Applied only when non-empty and not (UNDEFINED).
model.Settings.email
The template expects an invited email (rendered in a disabled input):value="{{ model.Settings.email }}"
Even though it’s not shown in the provided model snippet, the Liquid template reads it.
translations.*
Used for placeholders, validation messages, password strength checklist, and toast messages.
JavaScript#
Global object#
The component exposes an Alpine-ready object:
State fields#
fields: []
Cached list of form fields ([name]), excluding disabled and submit inputs.
errors: {}
Field-name → error-code mapping:required, invalidEmail, weak, unmatched, or empty string
isSending: false
Disables the submit button and prevents double submits.
errorUpLowCase, errorLength, errorSymbolNum
Password strength breakdown flags used by the checklist UI.
init()#
Collects all fields with [name] under the form scope (this.$el).
Filters out disabled fields (the email field is disabled, so it is excluded from validation).
Email is validated neither client-side nor included in fields because it’s disabled. That’s OK for invitation flows since email is pre-populated and controlled.
validateField(field)#
What it does
Validates a single field and updates:.icon-state warning/check icon classes (where present)
password strength checklist flags
empty required → required
2.
Email format (if email fields existed as enabled inputs):
invalid email → invalidEmail
3.
Password strength (for password fields):
uppercase + lowercase (unicode-aware)
errorUpLowCase, errorLength, errorSymbolNum
sets errorType = "weak" if full regex fails
if confirm != password → unmatched
if the user changes the main password and confirm already has a value, it re-validates confirm.
Regex symbol set is ASCII-based; adjust if you want broader symbol support.
Confirm/password inputs are found using selectors that match the template naming pattern:input[name^="invitation-password-"]
input[name^="invitation-confirm-password-"]
toggleVisibility(event)#
Uses the toggle checkbox id convention:checkbox id: toggle-<inputId>
Switches password input type: This depends on strict id naming. If ids change in Liquid, update the toggle- convention accordingly.
updateFormValidity()#
Returns true only if all fields:have no error in errors[field.name], and
are not empty when required
The method returns a boolean; it doesn’t set isFormValid. The submit flow calls it directly.
clearForm()#
Removes valid/invalid classes
The email field is disabled and isn’t part of fields, so it won’t be cleared (by design).
checkForm(id, successMessage, errorMessageFail, errorMessageUserExists, errorMessageInvalidToken) (async)#
Alpine.store("toast").removeAll()
2.
Validates all fields and stops if invalid:
this.fields.forEach(validateField)
if (!this.updateFormValidity()) return;
3.
Extracts invitation token from URL:
takes everything after the last / in window.location.href
4.
Builds payload (info) from DOM ids:
email from #invitation-email-<id>
password from #invitation-password-<id>
firstname from #invitation-firstname-<id>
lastname from #invitation-lastname-<id>
servicesreusabledefault.registerUser(info, token)
6.
Error handling by HTTP status:
403 → invalid token toast (errorMessageInvalidToken)
409 → user exists toast (errorMessageUserExists)
else → generic failure toast (errorMessageFail)
redirects to /login after 1 second
Token extraction via window.location.href.substring(...) can include query params if present. Safer:new URL(window.location.href).pathname.split("/").pop()
Consider using try/finally to guarantee isSending is reset even if the service call throws unexpectedly.
Global Alpine stores (used by Invitation)#
Invitation is a “complete registration” form that uses global stores for consistent feedback and relies on a tokenized URL flow.Alpine.store("toast") (user feedback)#
Used to display different failure types and the success message.Alpine.store("toast").removeAll()
Shows specific errors by response status:403 → invalid token toast
409 → user already exists toast
default → generic failure toast
Shows success toast and then redirects:toast.add(successMessage, "ic-check", "success")
What it means in practiceThe component communicates “what happened” without embedding status banners in the page.
Differentiating errors by status code helps support teams diagnose issues quickly:invalid token vs existing user vs generic server failure.
If Alpine.store("toast") is missing, the user will not understand why the invitation completion failed.
The redirect is delayed by 1s to allow the success toast to be seen.
Services / API calls#
servicesreusabledefault.registerUser(info, token)
Completes registration using the invitation token.
Dependencies#
Theme services layer: servicesreusabledefault.registerUser(...)
Notes#
The invited email is expected to be provided by the backend in model.Settings.email (template requirement).
The password strength rules match the ChangePassword component (same regex approach).
The component redirects to /login after success; it does not auto-login the user.
Template behavior (Liquid + Alpine)#
Initialization#
The form is mounted with:x-data="invitationdefault"
@submit.prevent="checkForm(id, success, fail, userExists, invalidToken)"
Email behavior#
Email input is rendered as:value is taken from model.Settings.email
Email is still sent to the backend by reading the input value by id.
Password toggle#
Both password and confirm password inputs include a visibility toggle checkbox.
Toggle supports click and Enter key (accessibility):@click.stop="toggleVisibility($event)"
@keydown.enter.stop.prevent="toggleVisibility($event)"
Validation UI#
Required field errors are driven by:errors[fieldName] === 'required'
Password strength shows a detailed checklist when:errors[passwordFieldName] === 'weak'
Confirm password mismatch is shown when:errors[confirmFieldName] === 'unmatched'
Modified at 2026-05-04 11:51:16