-
Notifications
You must be signed in to change notification settings - Fork 10
Register Hub CE #141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Register Hub CE #141
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,108 @@ | ||||||||||||||||||||||
| "use strict"; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // requires newsletter.js | ||||||||||||||||||||||
| const VERIFY_EMAIL_URL = API_BASE_URL + '/connect/email/verify'; | ||||||||||||||||||||||
| const REFRESH_LICENSE_URL = API_BASE_URL + '/licenses/hub/refresh'; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| class HubCE { | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| constructor(form, feedbackData, submitData, searchParams) { | ||||||||||||||||||||||
| this._form = form; | ||||||||||||||||||||||
| this._feedbackData = feedbackData; | ||||||||||||||||||||||
| this._submitData = submitData; | ||||||||||||||||||||||
| this._searchParams = searchParams; | ||||||||||||||||||||||
| this._submitData.oldLicense = searchParams.get('oldLicense'); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // continue after email verified: | ||||||||||||||||||||||
| if (searchParams.get('verifiedEmail')) { | ||||||||||||||||||||||
| feedbackData.currentStep = 2; | ||||||||||||||||||||||
| feedbackData.success = true; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| submit() { | ||||||||||||||||||||||
| if (this._feedbackData.currentStep === 0) { | ||||||||||||||||||||||
| this.validateEmail(); | ||||||||||||||||||||||
| } else if (this._feedbackData.currentStep === 1) { | ||||||||||||||||||||||
| this.sendConfirmationEmail(); | ||||||||||||||||||||||
| } else if (this._feedbackData.currentStep === 2) { | ||||||||||||||||||||||
| this.getHubLicense(); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| validateEmail() { | ||||||||||||||||||||||
| if (!$(this._form)[0].checkValidity()) { | ||||||||||||||||||||||
| $(this._form).find(':input').addClass('show-invalid'); | ||||||||||||||||||||||
| this._feedbackData.errorMessage = 'Please fill in all required fields.'; | ||||||||||||||||||||||
| return; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
||||||||||||||||||||||
| } | |
| } | |
| // Ensure oldLicense is present before allowing progression. | |
| const oldLicense = this._submitData.oldLicense; | |
| if (!oldLicense) { | |
| this._feedbackData.inProgress = false; | |
| this._feedbackData.errorMessage = 'License information is missing. Please open this page using the link provided in your email.'; | |
| return; | |
| } |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getHubLicense() doesn’t set inProgress/clear errorMessage, so the UI can’t reliably show loading state or prevent duplicate submits. Also, the template renders an Altcha captcha for the license step, but this request doesn’t send any captcha payload—either remove the captcha from the license step or include its payload in the POST so the widget has an effect.
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,5 @@ | ||||||||
| --- | ||||||||
| title: "Cryptomator Hub: Registrieren" | ||||||||
| url: "/de/hub/register" | ||||||||
| type: "hub-register" | ||||||||
|
||||||||
| type: "hub-register" | |
| type: "hub-register" | |
| draft: true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| title: "Cryptomator Hub: Register" | ||
| url: "/hub/register" | ||
| type: "hub-register" | ||
| --- |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,188 @@ | ||||||||||||||
| {{ define "preloads" }} | ||||||||||||||
| {{ partial "altcha-css.html" . }} | ||||||||||||||
| {{ end }} | ||||||||||||||
| {{ define "main" }} | ||||||||||||||
| <section x-data="{steps: ['{{ i18n "hub_ce_registration_step_1_nav_title" }}', '{{ i18n "hub_ce_registration_step_2_confirmation_nav_title" }}', '{{ i18n "hub_ce_registration_step_3_license_nav_title" }}'], feedbackData: {currentStep: 0, success: false, inProgress: false, errorMessage: '', licenseText: null}, submitData: {captcha: null, oldLicense: '', email: '', acceptNewsletter: false}, acceptTerms: false, hubCE: null, captchaState: null}" x-init="hubCE = new HubCE($refs.form, feedbackData, submitData, new URLSearchParams(location.hash.substring(1)))" class="container py-12"> | ||||||||||||||
|
||||||||||||||
| <header class="mb-6"> | ||||||||||||||
| <h1 class="font-h1 mb-8">{{ .Title }}</h1> | ||||||||||||||
| <p class="lead">{{ i18n "hub_ce_registration_description" }}</p> | ||||||||||||||
| </header> | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| <section class="white-box md:min-h-110 px-4 py-5 md:p-6 md:grid md:grid-cols-3 md:gap-6"> | ||||||||||||||
| <header class="mb-8 md:col-span-1 md:mt-4"> | ||||||||||||||
| <nav class="flex items-center justify-center gap-6" aria-label="Progress"> | ||||||||||||||
| <p class="font-p text-sm text-gray-500 md:hidden"> | ||||||||||||||
| {{ i18n "hub_ce_registration_steps_title" | safeHTML }} | ||||||||||||||
| </p> | ||||||||||||||
| <ol role="list" class="flex items-center gap-3 md:flex-col md:items-start md:gap-6"> | ||||||||||||||
| <template x-for="(step, index) in steps" :key="index"> | ||||||||||||||
| <li> | ||||||||||||||
| <!-- Complete Step --> | ||||||||||||||
| <template x-if="index < feedbackData.currentStep && !feedbackData.success"> | ||||||||||||||
| <a href="#" class="group" @click.prevent="feedbackData.currentStep = index" :data-umami-event="`hub-managed-nav-step-${index + 1}`"> | ||||||||||||||
| <span class="flex items-center gap-3"> | ||||||||||||||
| <div class="relative flex w-5 h-5 shrink-0 items-center justify-center"> | ||||||||||||||
| <svg class="w-full h-full text-primary group-hover:text-secondary" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"> | ||||||||||||||
| <path fill-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm3.857-9.809a.75.75 0 0 0-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 1 0-1.06 1.061l2.5 2.5a.75.75 0 0 0 1.137-.089l4-5.5Z" clip-rule="evenodd" /> | ||||||||||||||
| </svg> | ||||||||||||||
| </div> | ||||||||||||||
| <p class="hidden md:block font-p text-sm text-gray-500 group-hover:text-gray-900" x-text="step"></p> | ||||||||||||||
| </span> | ||||||||||||||
| </a> | ||||||||||||||
| </template> | ||||||||||||||
| <template x-if="index < feedbackData.currentStep && feedbackData.success"> | ||||||||||||||
| <span class="flex items-center gap-3"> | ||||||||||||||
| <div class="relative flex w-5 h-5 shrink-0 items-center justify-center"> | ||||||||||||||
| <svg class="w-full h-full text-primary group-hover:text-secondary" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"> | ||||||||||||||
| <path fill-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm3.857-9.809a.75.75 0 0 0-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 1 0-1.06 1.061l2.5 2.5a.75.75 0 0 0 1.137-.089l4-5.5Z" clip-rule="evenodd" /> | ||||||||||||||
| </svg> | ||||||||||||||
| </div> | ||||||||||||||
| <p class="hidden md:block font-p text-sm text-gray-500 group-hover:text-gray-900" x-text="step"></p> | ||||||||||||||
| </span> | ||||||||||||||
| </template> | ||||||||||||||
|
|
||||||||||||||
| <!-- Current Step --> | ||||||||||||||
| <template x-if="index === feedbackData.currentStep"> | ||||||||||||||
| <div class="flex items-center gap-3" aria-current="step"> | ||||||||||||||
| <div class="relative flex w-5 h-5 shrink-0 items-center justify-center" aria-hidden="true"> | ||||||||||||||
| <span class="absolute w-4 h-4 rounded-full bg-primary-l2"></span> | ||||||||||||||
| <span class="relative block w-2 h-2 rounded-full bg-primary"></span> | ||||||||||||||
| </div> | ||||||||||||||
| <p class="hidden md:block font-p text-sm font-medium text-primary" x-text="step"></p> | ||||||||||||||
| </div> | ||||||||||||||
| </template> | ||||||||||||||
|
|
||||||||||||||
| <!-- Upcoming Step --> | ||||||||||||||
| <template x-if="index > feedbackData.currentStep"> | ||||||||||||||
| <div class="flex items-center gap-3"> | ||||||||||||||
| <div class="relative flex w-5 h-5 shrink-0 items-center justify-center" aria-hidden="true"> | ||||||||||||||
| <div class="w-2 h-2 rounded-full bg-gray-300"></div> | ||||||||||||||
| </div> | ||||||||||||||
| <p class="hidden md:block font-p text-sm text-gray-500" x-text="step"></p> | ||||||||||||||
| </div> | ||||||||||||||
| </template> | ||||||||||||||
| </li> | ||||||||||||||
| </template> | ||||||||||||||
| </ol> | ||||||||||||||
| </nav> | ||||||||||||||
| </header> | ||||||||||||||
|
|
||||||||||||||
| <form x-ref="form" class="md:col-span-2" @submit.prevent="hubCE.submit(); $refs.captcha.reset()"> | ||||||||||||||
| <!-- Step 1: Email Address --> | ||||||||||||||
|
Comment on lines
+71
to
+72
|
||||||||||||||
| <template x-if="feedbackData.currentStep == 0"> | ||||||||||||||
| <div class="grid grid-cols-6 gap-6"> | ||||||||||||||
| <div class="flex flex-col col-span-6 lg:col-span-4"> | ||||||||||||||
| <p class="hidden md:block font-p text-sm text-gray-500 mb-2"> | ||||||||||||||
| {{ i18n "hub_managed_steps_title" | safeHTML }} | ||||||||||||||
|
||||||||||||||
| {{ i18n "hub_managed_steps_title" | safeHTML }} | |
| {{ i18n "hub_ce_registration_steps_title" | safeHTML }} |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This submit button still uses Hub Managed copy/analytics (hub_managed_step_4_submit, hub-managed-form) on the CE registration flow. That will show the wrong label (and mix Umami events). Add CE-specific i18n/event names or reuse the CE ..._steps_next/submit wording consistently.
| <button :disabled="feedbackData.inProgress || !acceptTerms || captchaState == 'verifying'" type="submit" class="btn btn-primary w-full md:w-64" data-umami-event="hub-managed-form" x-cloak> | |
| <i :class="{'fa-paper-plane': !feedbackData.inProgress, 'fa-spinner fa-spin': feedbackData.inProgress}" class="fa-solid" aria-hidden="true"></i> | |
| {{ i18n "hub_managed_step_4_submit" }} | |
| <button :disabled="feedbackData.inProgress || !acceptTerms || captchaState == 'verifying'" type="submit" class="btn btn-primary w-full md:w-64" data-umami-event="hub-ce-registration-step-2-submit" x-cloak> | |
| <i :class="{'fa-paper-plane': !feedbackData.inProgress, 'fa-spinner fa-spin': feedbackData.inProgress}" class="fa-solid" aria-hidden="true"></i> | |
| {{ i18n "hub_ce_registration_steps_submit" }} |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<textarea ... x-text="feedbackData.licenseText"> won’t update the textarea’s value reliably (the project generally uses x-model/:value for textareas). Bind the textarea’s value (e.g., x-model to a readonly field or :value) so the license text updates when the AJAX call completes.
| <textarea class="block input-box w-full h-48 mb-8" x-text="feedbackData.licenseText" readonly></textarea> | |
| <textarea class="block input-box w-full h-48 mb-8" :value="feedbackData.licenseText" readonly></textarea> |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are user-facing placeholder strings (Todo: ...) and a “Return to Hub” button that currently lives inside the form and will submit the form (triggering hubCE.submit()), not actually return anywhere. These placeholders/actions should be implemented (or removed) before merging to avoid shipping incomplete UX and unintended behavior.
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In production, altchaWorkerJs isn’t minify|fingerprint’d but an integrity attribute is still emitted. This will likely produce an empty/incorrect integrity value and prevents cache-busting. Apply the same minify | fingerprint pipeline as the other scripts (or drop integrity if you intentionally don’t fingerprint).
| {{ $altchaWorkerJs := resources.Get "js/altcha/worker.js" }} | |
| {{ $altchaWorkerJs := resources.Get "js/altcha/worker.js" | minify | fingerprint }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused class HubCE.