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).
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.$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 $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-04-14 13:18:56