Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions assets/js/hubsubscription.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const CUSTOM_BILLING_URL = LEGACY_STORE_URL + '/hub/custom-billing';
const GENERATE_PAY_LINK_URL = LEGACY_STORE_URL + '/hub/generate-pay-link';
const MANAGE_SUBSCRIPTION_URL = LEGACY_STORE_URL + '/hub/manage-subscription';
const UPDATE_PAYMENT_METHOD_URL = LEGACY_STORE_URL + '/hub/update-payment-method';
const REFRESH_LICENSE_URL = API_BASE_URL + '/licenses/hub/refresh';

class HubSubscription {

Expand Down Expand Up @@ -56,14 +57,15 @@ class HubSubscription {
}

onLoadSubscriptionSucceeded(data) {
this._subscriptionData.token = data.token;
this._subscriptionData.verificationToken = data.token;
this._subscriptionData.details = data.subscription;
if (data.subscription.quantity) {
this._subscriptionData.quantity = data.subscription.quantity;
}
this._subscriptionData.state = 'EXISTING_CUSTOMER';
this._subscriptionData.errorMessage = '';
this._subscriptionData.inProgress = false;
this._subscriptionData.needsTokenRefresh = true;
}

onLoadSubscriptionFailed(status, error) {
Expand Down Expand Up @@ -271,7 +273,7 @@ class HubSubscription {
override: payLink,
email: this._subscriptionData.email,
locale: locale,
passthrough: '{"hub_id": ' + this._subscriptionData.hubId + '}',
passthrough: JSON.stringify({ hub_id: this._subscriptionData.hubId }),
successCallback: data => this.getPaddleOrderDetails(data.checkout.id),
closeCallback: () => {
this._subscriptionData.inProgress = false;
Expand Down Expand Up @@ -311,7 +313,7 @@ class HubSubscription {

onPostSucceeded(data) {
this._subscriptionData.state = 'EXISTING_CUSTOMER';
this._subscriptionData.token = data.token;
this._subscriptionData.verificationToken = data.token;
this._subscriptionData.details = data.subscription;
this._subscriptionData.session = data.session;
var searchParams = new URLSearchParams(window.location.search)
Expand All @@ -320,7 +322,8 @@ class HubSubscription {
history.pushState(null, '', newRelativePathQuery);
this._subscriptionData.errorMessage = '';
this._subscriptionData.inProgress = false;
this.transferTokenToHub();
this._subscriptionData.shouldTransferToHub = true;
this._subscriptionData.needsTokenRefresh = true;
}

onPostFailed(error) {
Expand Down Expand Up @@ -477,12 +480,13 @@ class HubSubscription {
}

onPutSucceeded(data, shouldOpenReturnUrl) {
this._subscriptionData.token = data.token;
this._subscriptionData.verificationToken = data.token;
this._subscriptionData.details = data.subscription;
this._subscriptionData.errorMessage = '';
this._subscriptionData.inProgress = false;
if (shouldOpenReturnUrl) {
this.transferTokenToHub();
this._subscriptionData.shouldTransferToHub = true;
this._subscriptionData.needsTokenRefresh = true;
}
}

Expand All @@ -494,6 +498,31 @@ class HubSubscription {
this._subscriptionData.inProgress = false;
}

refreshToken() {
this._subscriptionData.inProgress = true;
this._subscriptionData.errorMessage = '';
$.ajax({
url: REFRESH_LICENSE_URL,
type: 'POST',
data: {
token: this._subscriptionData.verificationToken,
captcha: this._subscriptionData.captcha
}
}).done(token => {
this._subscriptionData.token = token;
this._subscriptionData.needsTokenRefresh = false;
this._subscriptionData.errorMessage = '';
this._subscriptionData.inProgress = false;
if (this._subscriptionData.shouldTransferToHub) {
this.transferTokenToHub();
}
}).fail(xhr => {
this._subscriptionData.errorMessage = xhr.responseJSON?.message || 'Refreshing license failed.';
this._subscriptionData.needsTokenRefresh = false;
this._subscriptionData.inProgress = false;
});
}

transferTokenToHub() {
window.open(this._subscriptionData.returnUrl + '?token=' + this._subscriptionData.token, '_self');
}
Expand Down
2 changes: 2 additions & 0 deletions i18n/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,8 @@
translation: "Dies ist dein Lizenzschlüssel, der an deine Hub-ID gebunden ist. Drück auf den Button unten, um ihn automatisch auf deine Hub-Instanz zu übertragen."
- id: hub_billing_manage_license_key_transfer_action
translation: "Zum Hub übertragen"
- id: hub_billing_manage_license_key_retry_action
translation: "Erneut versuchen"

- id: hub_billing_manage_modal_charge_amount_description
translation: "Rechnungsbetrag"
Expand Down
2 changes: 2 additions & 0 deletions i18n/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,8 @@
translation: "This is your license key that is bound to your Hub ID. Press the button below to transfer it to your Hub instance automatically."
- id: hub_billing_manage_license_key_transfer_action
translation: "Transfer to Hub"
- id: hub_billing_manage_license_key_retry_action
translation: "Retry"

- id: hub_billing_manage_modal_charge_amount_description
translation: "Charge Amount"
Expand Down
17 changes: 15 additions & 2 deletions layouts/hub-billing/single.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{{ end }}
{{ define "main" }}
<div class="container pt-12 pb-24">
<form x-data="{subscriptionData: {state: 'MISSING_PARAMS', captcha: null, hubId: null, returnUrl: null, session: null, customBilling: null, billingInterval: 'yearly', savingsPercent: null, errorMessage: '', inProgress: false, restartModal: {open: false, nextPayment: null}, changeSeatsModal: {open: false, confirmation: false, immediatePayment: null}, token: null, details: null, quantity: 5, email: ''}, acceptTerms: false, hubSubscription: null, captchaState: null}" x-init="hubSubscription = new HubSubscription($refs.form, subscriptionData, new URLSearchParams(location.search))" x-ref="form" @submit.prevent="hubSubscription.createSession(); $refs.captcha.reset()">
<form x-data="{subscriptionData: {state: 'MISSING_PARAMS', captcha: null, hubId: null, returnUrl: null, session: null, customBilling: null, billingInterval: 'yearly', savingsPercent: null, errorMessage: '', inProgress: false, restartModal: {open: false, nextPayment: null}, changeSeatsModal: {open: false, confirmation: false, immediatePayment: null}, token: null, details: null, quantity: 5, email: '', needsTokenRefresh: false, shouldTransferToHub: false}, acceptTerms: false, hubSubscription: null, captchaState: null}" x-init="hubSubscription = new HubSubscription($refs.form, subscriptionData, new URLSearchParams(location.search))" x-ref="form" @submit.prevent="hubSubscription.createSession(); $refs.captcha.reset()">
<template x-if="subscriptionData.state == 'MISSING_PARAMS'">
<div class="text-center max-w-xl mx-auto">
<h3 class="font-headline text-xl md:text-2xl leading-relaxed mb-4">
Expand Down Expand Up @@ -176,9 +176,22 @@ <h2 class="font-h2 mb-4 mt-12">
{{ i18n "hub_billing_manage_license_key_instruction" . }}
</p>
<textarea x-model="subscriptionData.token" class="input-box w-full text-sm md:text-base leading-relaxed break-all" rows="6" readonly></textarea>
<button :disabled="subscriptionData.inProgress || !subscriptionData.token" class="btn btn-primary text-center w-full md:w-64 mt-4" @click.prevent="hubSubscription.transferTokenToHub()">
<button x-show="!subscriptionData.token && !subscriptionData.needsTokenRefresh" :disabled="subscriptionData.inProgress" @click.prevent="subscriptionData.errorMessage = ''; subscriptionData.needsTokenRefresh = true" class="btn btn-primary text-center w-full md:w-64 mt-4">
{{ i18n "hub_billing_manage_license_key_retry_action" . }}
</button>
<button x-show="subscriptionData.token" :disabled="subscriptionData.inProgress" class="btn btn-primary text-center w-full md:w-64 mt-4" @click.prevent="hubSubscription.transferTokenToHub()">
{{ i18n "hub_billing_manage_license_key_transfer_action" . }}
</button>
<template x-if="subscriptionData.needsTokenRefresh && !subscriptionData.inProgress">
<div class="mt-4">
{{ $challengeUrl := printf "%s/licenses/hub/challenge" .Site.Params.apiBaseUrl }}
{{ partial "captcha.html" (dict "challengeUrl" $challengeUrl "captchaPayload" "subscriptionData.captcha" "captchaState" "captchaState" "ref" "refreshCaptcha" "auto" "onload" "onVerified" "hubSubscription.refreshToken()") }}
</div>
</template>
<p x-show="subscriptionData.needsTokenRefresh && subscriptionData.inProgress" class="text-sm text-gray-600 mt-4">
<i class="fa-solid fa-spinner fa-spin"></i>
{{ i18n "hub_billing_loading_description" . }}
</p>

<div x-show="subscriptionData.restartModal.open" class="relative z-10" aria-labelledby="restart-modal-title" role="dialog" aria-modal="true">
<div class="fixed inset-0 bg-gray-500/75"></div>
Expand Down
18 changes: 2 additions & 16 deletions layouts/hub-register/single.html
Original file line number Diff line number Diff line change
Expand Up @@ -171,22 +171,8 @@ <h2 class="font-h2 mb-6">

<!-- Captcha (auto-starts on load, hidden when done) -->
<div x-show="!feedbackData.licenseText" class="mb-4">
<altcha-widget
challengeurl="{{ .Site.Params.apiBaseUrl }}/licenses/hub/challenge"
hidelogo
hidefooter
auto="onload"
@statechange="captchaState = $event.detail.state; if ($event.detail.state === 'verified') { submitData.captcha = $event.detail.payload; hubCE.getHubLicense() }"
:strings="JSON.stringify({
label: '{{ i18n "altcha_label" }}',
error: '{{ i18n "altcha_error" }}',
expired: '{{ i18n "altcha_expired" }}',
verified: '{{ i18n "altcha_verified" }}',
verifying: '{{ i18n "altcha_verifying" }}',
waitAlert: '{{ i18n "altcha_waitAlert" }}'
})"
x-ref="licenseCaptcha"
></altcha-widget>
{{ $challengeUrl := printf "%s/licenses/hub/challenge" .Site.Params.apiBaseUrl }}
{{ partial "captcha.html" (dict "challengeUrl" $challengeUrl "captchaPayload" "submitData.captcha" "captchaState" "captchaState" "ref" "licenseCaptcha" "auto" "onload" "onVerified" "hubCE.getHubLicense()") }}
</div>

<!-- Loading state -->
Expand Down
4 changes: 2 additions & 2 deletions layouts/partials/captcha.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
challengeurl="{{ .challengeUrl }}"
hidelogo
hidefooter
floating="auto"
@statechange="{{ .captchaState }} = $event.detail.state; if ($event.detail.state === 'verified') { {{ .captchaPayload }} = $event.detail.payload }"
{{ with .auto }}auto="{{ . }}"{{ else }}floating="auto"{{ end }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is floating="auto"? I am pretty sure this is not to be confused with auto=...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

floating="auto" displays the widget as a popup near the submit button and internally sets auto="onsubmit" (see Floating UI docs). This is the default behavior we've used for all captchas until now.

With the new hub-register and hub-billing flows, we need auto="onload" instead so the captcha starts solving immediately. In that case we shouldn't also set floating="auto" since it would override auto back to onsubmit. That's why they're mutually exclusive in the template.

Does that make sense?

@statechange="{{ .captchaState }} = $event.detail.state; if ($event.detail.state === 'verified') { {{ .captchaPayload }} = $event.detail.payload{{ with .onVerified }}; {{ . }}{{ end }} }"
:strings="JSON.stringify({
label: '{{ i18n "altcha_label" }}',
error: '{{ i18n "altcha_error" }}',
Expand Down