diff --git a/core/static/core/forms.scss b/core/static/core/forms.scss index 0982b3d0..511190b6 100644 --- a/core/static/core/forms.scss +++ b/core/static/core/forms.scss @@ -141,7 +141,6 @@ form { display: block; margin: calc(var(--nf-input-size) * 1.5) auto 10px; line-height: 1; - white-space: nowrap; .fields-centered { padding: 10px 10px 0; diff --git a/eboutic/static/bundled/eboutic/checkout-index.ts b/eboutic/static/bundled/eboutic/checkout-index.ts index 08683218..21bdbdba 100644 --- a/eboutic/static/bundled/eboutic/checkout-index.ts +++ b/eboutic/static/bundled/eboutic/checkout-index.ts @@ -6,67 +6,71 @@ interface Basket { timeout: Date; } document.addEventListener("alpine:init", () => { - Alpine.data("etransaction", (initialData, basket: Basket) => ({ - data: initialData, - isCbAvailable: Object.keys(initialData).length > 0, - isSithAvailable: true, + Alpine.data( + "etransaction", + (initialData: Record, basket: Basket) => ({ + data: initialData, + isCbAvailable: Object.keys(initialData).length > 0, + isSithAvailable: true, - init() { - const now = new Date(); - const timeout = basket.timeout.getTime() - now.getTime(); - if (timeout <= 0) { - // basket was already outdated at initial page load - this.timeoutBasket(); - } else { - setTimeout(() => this.timeoutBasket(), timeout); - } - }, + init() { + const now = new Date(); + const timeout = basket.timeout.getTime() - now.getTime(); + if (timeout > 0) { + // if not going inside this condition, it means that + // basket was already outdated at initial page load, + // in which case disabling buttons and displaying + // error message has been done at rendering time + setTimeout(() => this.timeoutBasket(), timeout); + } + }, - /** - * Make this basket into a timeout state. - * All submission inputs are disabled, and an error message is displayed. - */ - timeoutBasket() { - this.isCbAvailable = false; - this.isSithAvailable = false; - const message = gettext("Basket expired"); + /** + * Make this basket into a timeout state. + * All submission inputs are disabled, and an error message is displayed. + */ + timeoutBasket() { + this.isCbAvailable = false; + this.isSithAvailable = false; + const message = gettext("Basket expired"); - const existingNotif: Notification | undefined = this.$notifications - .getAll() - .find( - (n: Notification) => - n.tag === NotificationLevel.Error && n.message === message, - ); - if (existingNotif === undefined) { - this.$notifications.error(message); - } - }, + const existingNotif: Notification | undefined = this.$notifications + .getAll() + .find( + (n: Notification) => + n.tag === NotificationLevel.Error && n.text === message, + ); + if (existingNotif === undefined) { + this.$notifications.error(message); + } + }, - /** - * Refresh the data used for etransaction. - * - * Note: if this is called while the basket is expired, it will be a no-op - */ - async fill() { - if (new Date() > basket.timeout) { - // refresh etransaction data only if the basket is still valid. - this.timeoutBasket(); - return; - } - this.isCbAvailable = false; - const res = await etransactioninfoFetchEtransactionData({ - // biome-ignore lint/style/useNamingConvention: api is in snake_case - path: { basket_id: basket.id }, - }); - if (res.response.ok) { - this.data = res.data; - this.isCbAvailable = true; - } else if (res.response.status === 410) { - // The basket is expired, so no payment method should be available at all. - // This shouldn't happen, because we don't send the request - // when the timeout is passed, but we are better safe than sorry - this.timeoutBasket(); - } - }, - })); + /** + * Refresh the data used for etransaction. + * + * Note: if this is called while the basket is expired, it will be a no-op + */ + async fill() { + if (new Date() > basket.timeout) { + // refresh etransaction data only if the basket is still valid. + this.timeoutBasket(); + return; + } + this.isCbAvailable = false; + const res = await etransactioninfoFetchEtransactionData({ + // biome-ignore lint/style/useNamingConvention: api is in snake_case + path: { basket_id: basket.id }, + }); + if (res.response.ok) { + this.data = res.data as Record; + this.isCbAvailable = true; + } else if (res.response.status === 410) { + // The basket is expired, so no payment method should be available at all. + // This shouldn't happen, because we don't send the request + // when the timeout is passed, but we are better safe than sorry + this.timeoutBasket(); + } + }, + }), + ); }); diff --git a/eboutic/templates/eboutic/eboutic_checkout.jinja b/eboutic/templates/eboutic/eboutic_checkout.jinja index e299852b..277f4ee1 100644 --- a/eboutic/templates/eboutic/eboutic_checkout.jinja +++ b/eboutic/templates/eboutic/eboutic_checkout.jinja @@ -28,8 +28,8 @@ Article - Quantity - Unit price + {% trans %}Quantity{% endtrans %} + {% trans %}Unit price{% endtrans %} @@ -63,10 +63,41 @@
{{ billing_infos_form }}
- {% include "core/base/notifications.jinja" %} + {% endif %} + {% include "core/base/notifications.jinja" %} + {% if settings.SITH_EBOUTIC_CB_ENABLED or (basket.total <= user.account_balance and not basket.contains_refilling_item) %} + {# don't display the cgv form if no payment mean is available #} +
+ {# In order to have one CGV button for both payment means, + we have a third dummy form, containing only the cgv button, + which validation is triggered when one of the two other forms is submitted. + If the validation of this form fails, the submit event will be cancelled. #} +
+ + +
+
+ {% endif %} + {% if settings.SITH_EBOUTIC_CB_ENABLED %}