Skip to content

Commit 20e195c

Browse files
committed
add intermediate confirmation states to Hub CE registration and auto-fetch license key on step 3
1 parent 18c81ca commit 20e195c

3 files changed

Lines changed: 93 additions & 30 deletions

File tree

assets/js/hubce.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ class HubCE {
1515

1616
// continue after email verified:
1717
if (searchParams.get('verifiedEmail')) {
18-
feedbackData.currentStep = 2;
19-
feedbackData.success = true;
18+
feedbackData.currentStep = 1;
19+
feedbackData.emailVerified = true;
2020
}
2121
}
2222

@@ -81,6 +81,8 @@ class HubCE {
8181
}
8282

8383
getHubLicense() {
84+
this._feedbackData.inProgress = true;
85+
this._feedbackData.errorMessage = '';
8486
$.ajax({
8587
url: REFRESH_LICENSE_URL,
8688
type: 'POST',
@@ -90,6 +92,7 @@ class HubCE {
9092
}
9193
}).done(response => {
9294
this._feedbackData.licenseText = response;
95+
this._feedbackData.inProgress = false;
9396
}).fail(xhr => {
9497
this.onRequestFailed(xhr.responseJSON?.message || 'Fetching license failed.');
9598
});
@@ -101,7 +104,7 @@ class HubCE {
101104
}
102105

103106
onRequestSucceeded() {
104-
this._feedbackData.currentStep++;
107+
this._feedbackData.emailSent = true;
105108
this._feedbackData.inProgress = false;
106109
this._feedbackData.errorMessage = '';
107110
}

i18n/en.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,8 @@
667667
translation: "Step <span x-text=\"feedbackData.currentStep + 1\"></span> of <span x-text=\"steps.length\"></span>"
668668
- id: hub_ce_registration_steps_next
669669
translation: "Next"
670+
- id: hub_ce_registration_steps_continue
671+
translation: "Continue"
670672

671673
- id: hub_ce_registration_step_1_nav_title
672674
translation: "Email Address"
@@ -681,11 +683,19 @@
681683
translation: "Please confirm your email address"
682684
- id: hub_ce_registration_step_2_instructions
683685
translation: "We are going to send a confirmation email to <span x-text=\"submitData.email\"></span>"
686+
- id: hub_ce_registration_step_2_check_email
687+
translation: "Please check your e-mails."
688+
- id: hub_ce_registration_step_2_email_verified
689+
translation: "Your email has been verified successfully."
684690

685691
- id: hub_ce_registration_step_3_license_nav_title
686692
translation: "License Key"
687693
- id: hub_ce_registration_step_3_license_title
688694
translation: "Your Community Edition License Key"
695+
- id: hub_ce_registration_step_3_loading
696+
translation: "Loading license key..."
697+
- id: hub_ce_registration_step_3_success
698+
translation: "Your new license key:"
689699

690700

691701
# Hub Managed

layouts/hub-register/single.html

Lines changed: 77 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
{{ partial "altcha-css.html" . }}
33
{{ end }}
44
{{ define "main" }}
5-
<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">
5+
<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, emailSent: false, emailVerified: false}, 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">
66
<header class="mb-6">
77
<h1 class="font-h1 mb-8">{{ .Title }}</h1>
88
<p class="lead">{{ i18n "hub_ce_registration_description" }}</p>
@@ -18,8 +18,8 @@ <h1 class="font-h1 mb-8">{{ .Title }}</h1>
1818
<ol role="list" class="flex items-center gap-3 md:flex-col md:items-start md:gap-6">
1919
<template x-for="(step, index) in steps" :key="index">
2020
<li>
21-
<!-- Complete Step -->
22-
<template x-if="index < feedbackData.currentStep &amp;&amp; !feedbackData.success">
21+
<!-- Complete Step (clickable) -->
22+
<template x-if="index < feedbackData.currentStep &amp;&amp; !feedbackData.success &amp;&amp; !feedbackData.emailSent">
2323
<a href="#" class="group" @click.prevent="feedbackData.currentStep = index" :data-umami-event="`hub-managed-nav-step-${index + 1}`">
2424
<span class="flex items-center gap-3">
2525
<div class="relative flex w-5 h-5 shrink-0 items-center justify-center">
@@ -31,7 +31,8 @@ <h1 class="font-h1 mb-8">{{ .Title }}</h1>
3131
</span>
3232
</a>
3333
</template>
34-
<template x-if="index < feedbackData.currentStep &amp;&amp; feedbackData.success">
34+
<!-- Complete Step (not clickable) -->
35+
<template x-if="index < feedbackData.currentStep &amp;&amp; (feedbackData.success || feedbackData.emailSent)">
3536
<span class="flex items-center gap-3">
3637
<div class="relative flex w-5 h-5 shrink-0 items-center justify-center">
3738
<svg class="w-full h-full text-primary group-hover:text-secondary" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
@@ -91,10 +92,10 @@ <h2 class="font-h2 mb-6">
9192
</div>
9293
</template>
9394

94-
<!-- Step 2: Confirmation -->
95-
<template x-if="feedbackData.currentStep == 1">
96-
<div class="md:col-span-2 grid grid-cols-6 gap-6">
97-
<div class="flex flex-col col-span-6 lg:col-span-4">
95+
<!-- Step 2a: Confirmation (form with checkboxes) -->
96+
<template x-if="feedbackData.currentStep == 1 &amp;&amp; !feedbackData.emailSent &amp;&amp; !feedbackData.emailVerified">
97+
<div class="md:col-span-2 gap-6">
98+
<div class="flex flex-col">
9899
<p class="hidden md:block font-p text-sm text-gray-500 mb-2">
99100
{{ i18n "hub_managed_steps_title" | safeHTML }}
100101
</p>
@@ -121,23 +122,44 @@ <h2 class="font-h2 mb-6">
121122
</div>
122123
</template>
123124

124-
<!-- Step 3a: License Key (loading...) -->
125-
<template x-if="feedbackData.currentStep == 2 &amp;&amp; !feedbackData.success">
126-
<div class="md:col-span-2 grid grid-cols-6 gap-6">
127-
<div class="flex flex-col col-span-6 lg:col-span-4">
125+
<!-- Step 2b: Confirmation (email sent, waiting for verification) -->
126+
<template x-if="feedbackData.currentStep == 1 &amp;&amp; feedbackData.emailSent &amp;&amp; !feedbackData.emailVerified">
127+
<div class="md:col-span-2 gap-6">
128+
<div class="flex flex-col">
128129
<p class="hidden md:block font-p text-sm text-gray-500 mb-2">
129130
{{ i18n "hub_managed_steps_title" | safeHTML }}
130131
</p>
131132
<h2 class="font-h2 mb-6">
132-
{{ i18n "hub_ce_registration_step_3_license_title" }}
133+
{{ i18n "hub_ce_registration_step_2_confirmation_title" }}
134+
</h2>
135+
<p class="font-p mb-6">{{ i18n "hub_ce_registration_step_2_check_email" | safeHTML }}</p>
136+
</div>
137+
</div>
138+
</template>
139+
140+
<!-- Step 2c: Confirmation (email verified, show continue button) -->
141+
<template x-if="feedbackData.currentStep == 1 &amp;&amp; feedbackData.emailVerified">
142+
<div class="md:col-span-2 gap-6">
143+
<div class="flex flex-col">
144+
<p class="hidden md:block font-p text-sm text-gray-500 mb-2">
145+
{{ i18n "hub_managed_steps_title" | safeHTML }}
146+
</p>
147+
<h2 class="font-h2 mb-6">
148+
{{ i18n "hub_ce_registration_step_2_confirmation_title" }}
133149
</h2>
134-
<p>Todo: Please check your e-mails.</p>
150+
<p class="font-p mb-6">{{ i18n "hub_ce_registration_step_2_email_verified" | safeHTML }}</p>
151+
<div class="mt-auto">
152+
<button @click.prevent="feedbackData.currentStep++; feedbackData.success = true" class="btn btn-primary w-full md:w-64" data-umami-event="hub-ce-registration-continue">
153+
<i class="fa-solid fa-chevron-right" aria-hidden="true"></i>
154+
{{ i18n "hub_ce_registration_steps_continue" }}
155+
</button>
156+
</div>
135157
</div>
136158
</div>
137159
</template>
138160

139-
<!-- Step 3b: License Key (success) -->
140-
<template x-if="feedbackData.currentStep == 2 &amp;&amp; feedbackData.success">
161+
<!-- Step 3: License Key -->
162+
<template x-if="feedbackData.currentStep == 2">
141163
<div class="md:col-span-2 grid grid-cols-6 gap-6">
142164
<div class="flex flex-col col-span-6 lg:col-span-4">
143165
<p class="hidden md:block font-p text-sm text-gray-500 mb-2">
@@ -146,17 +168,45 @@ <h2 class="font-h2 mb-6">
146168
<h2 class="font-h2 mb-6">
147169
{{ i18n "hub_ce_registration_step_3_license_title" }}
148170
</h2>
149-
<p>Todo: return URL</p>
150-
{{ $challengeUrl := printf "%s/licenses/hub/challenge" .Site.Params.apiBaseUrl }}
151-
{{ partial "captcha.html" (dict "challengeUrl" $challengeUrl "captchaPayload" "submitData.captcha" "captchaState" "captchaState") }}
152-
<textarea class="block input-box w-full h-48 mb-8" x-text="feedbackData.licenseText" readonly></textarea>
153-
154-
<div class="mt-auto">
155-
<p :class="{'hidden': !feedbackData.errorMessage}" class="text-sm text-red-600 mb-2" x-text="feedbackData.errorMessage"></p>
156-
<button class="btn btn-primary w-full md:w-64" data-umami-event="hub-ce-registration-step-1">
157-
<i :class="{'fa-chevron-right': !feedbackData.inProgress, 'fa-spinner fa-spin': feedbackData.inProgress}" class="fa-solid" aria-hidden="true"></i>
158-
Todo: Return to Hub
159-
</button>
171+
172+
<!-- Captcha (auto-starts on load, hidden when done) -->
173+
<div x-show="!feedbackData.licenseText" class="mb-4">
174+
<altcha-widget
175+
challengeurl="{{ .Site.Params.apiBaseUrl }}/licenses/hub/challenge"
176+
hidelogo
177+
hidefooter
178+
auto="onload"
179+
@statechange="captchaState = $event.detail.state; if ($event.detail.state === 'verified') { submitData.captcha = $event.detail.payload; hubCE.getHubLicense() }"
180+
:strings="JSON.stringify({
181+
label: '{{ i18n "altcha_label" }}',
182+
error: '{{ i18n "altcha_error" }}',
183+
expired: '{{ i18n "altcha_expired" }}',
184+
verified: '{{ i18n "altcha_verified" }}',
185+
verifying: '{{ i18n "altcha_verifying" }}',
186+
waitAlert: '{{ i18n "altcha_waitAlert" }}'
187+
})"
188+
x-ref="licenseCaptcha"
189+
></altcha-widget>
190+
</div>
191+
192+
<!-- Loading state -->
193+
<div x-show="captchaState === 'verified' &amp;&amp; !feedbackData.licenseText &amp;&amp; !feedbackData.errorMessage" class="mb-8">
194+
<p class="font-p text-gray-500">
195+
<i class="fa-solid fa-spinner fa-spin mr-2" aria-hidden="true"></i>
196+
{{ i18n "hub_ce_registration_step_3_loading" }}
197+
</p>
198+
</div>
199+
200+
<!-- License Key display -->
201+
<div x-show="feedbackData.licenseText">
202+
<p class="font-p mb-4">{{ i18n "hub_ce_registration_step_3_success" }}</p>
203+
<textarea class="block input-box w-full h-32 md:h-48 mb-8" x-text="feedbackData.licenseText" readonly></textarea>
204+
<div class="mt-auto">
205+
<button class="btn btn-primary w-full md:w-64" data-umami-event="hub-ce-registration-step-1">
206+
<i :class="{'fa-chevron-right': !feedbackData.inProgress, 'fa-spinner fa-spin': feedbackData.inProgress}" class="fa-solid" aria-hidden="true"></i>
207+
Todo: Return to Hub
208+
</button>
209+
</div>
160210
</div>
161211
</div>
162212
</div>

0 commit comments

Comments
 (0)