wickes-css2 2.103.0-gift-cards.17 → 2.103.0-lg-788-no-extra-req-empty-cart.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/Readme.md +2 -1
  2. package/build/css/category-main.css +1 -1
  3. package/build/css/components/checkout-payment-details-v2.css +1 -1
  4. package/build/css/homepage-main.css +1 -1
  5. package/build/css/kitchen-plp-main.css +1 -1
  6. package/build/css/main.css +1 -1
  7. package/build/css/my-account-main-v2.css +1 -1
  8. package/build/css/my-account-main.css +1 -1
  9. package/build/css/pages/page_checkout_delivery-new.css +1 -1
  10. package/build/css/pages/page_product-details-v2.css +1 -1
  11. package/build/css/pdp-main-before-combine.css +1 -1
  12. package/build/css/pdp-main-non-critical.css +1 -1
  13. package/build/css/pdp-main.css +1 -1
  14. package/build/css/plp-main.css +1 -1
  15. package/build/css/store-locator-main.css +1 -1
  16. package/build/js/account-members.min.js +1 -1
  17. package/build/js/add-project-list-id.min.js +1 -1
  18. package/build/js/address-book.min.js +1 -1
  19. package/build/js/basket.min.js +2 -2
  20. package/build/js/bundle.min.js +1 -1
  21. package/build/js/change-password.min.js +1 -1
  22. package/build/js/checkout.min.js +2 -2
  23. package/build/js/emulation.min.js +970 -282
  24. package/build/js/general.bundle.min.js +1 -1
  25. package/build/js/merged-checkout.min.js +2 -2
  26. package/build/js/mini-basket-slider.min.js +1 -0
  27. package/build/js/page/basket/basket-update-cart-action.js +59 -0
  28. package/build/js/page/basket/basket-update-cart.js +29 -0
  29. package/build/js/page/basket/basket-utils.js +50 -0
  30. package/build/js/page/basket/mini-basket-total.js +97 -0
  31. package/build/js/page/basket/quantity-change-handler.js +64 -0
  32. package/build/js/page/basket/update-quantity-operation.js +37 -0
  33. package/build/js/page/basket/update-quantity.js +65 -0
  34. package/build/js/page/basket-v2.js +138 -244
  35. package/build/js/page/components/discounts.js +6 -6
  36. package/build/js/page/components/mini-basket-slider.js +569 -0
  37. package/build/js/page/components/order-summary.js +25 -42
  38. package/build/js/page/utils/validation.js +1 -46
  39. package/build/js/pdp.bundle.min.js +1 -1
  40. package/build/js/personal-details.min.js +1 -1
  41. package/build/js/plp.bundle.min.js +1 -1
  42. package/build/js/project-list.min.js +1 -44
  43. package/build/js/quiz.min.js +1 -1
  44. package/build/js/track-my-order.min.js +1 -1
  45. package/package.json +2 -2
  46. package/src/components/checkout-payment-details-v2.hbs +11 -10
  47. package/src/components/checkout_payment-new.hbs +4 -1
  48. package/src/components/checkout_payment-other-methods.hbs +4 -1
  49. package/src/components/mini-basket/mini-basket-empty.hbs +3 -13
  50. package/src/components/mini-basket/mini-basket-order-item.hbs +73 -0
  51. package/src/components/mini-basket/mini-basket.hbs +32 -13
  52. package/src/components/mini-basket/product-item.hbs +37 -16
  53. package/src/components/payments-checkout-v2.hbs +7 -2
  54. package/src/components/payments-checkout.hbs +6 -1
  55. package/src/components/payments.hbs +5 -1
  56. package/src/components/table_order-details-klarna.hbs +1 -1
  57. package/src/components/table_payment.hbs +4 -1
  58. package/src/data/data_confirmation-summary.json +4 -2
  59. package/src/data/data_mini-basket.json +4 -80
  60. package/src/data/data_wismo.json +1 -1
  61. package/src/elements/form-row.hbs +1 -1
  62. package/src/elements/input.hbs +2 -31
  63. package/src/js/components/general/cart-slider.js +4 -0
  64. package/src/js/components/general/create-popup-slider.js +5 -2
  65. package/src/js/components/general/notification.js +1 -2
  66. package/src/js/components/toggle-password-visibility.js +58 -0
  67. package/src/js/emulation/checkout-payment-details.js +14 -23
  68. package/src/js/emulation/custom-slider-emulation.js +4 -10
  69. package/src/js/emulation/forms.js +2 -7
  70. package/src/js/emulation/mini-basket-data.js +949 -0
  71. package/src/js/page/basket/basket-update-cart-action.js +59 -0
  72. package/src/js/page/basket/basket-update-cart.js +29 -0
  73. package/src/js/page/basket/basket-utils.js +50 -0
  74. package/src/js/page/basket/mini-basket-total.js +97 -0
  75. package/src/js/page/basket/quantity-change-handler.js +64 -0
  76. package/src/js/page/basket/update-quantity-operation.js +37 -0
  77. package/src/js/page/basket/update-quantity.js +65 -0
  78. package/src/js/page/basket-v2.js +138 -244
  79. package/src/js/page/components/discounts.js +6 -6
  80. package/src/js/page/components/mini-basket-slider.js +569 -0
  81. package/src/js/page/components/order-summary.js +25 -42
  82. package/src/js/page/utils/validation.js +1 -46
  83. package/src/layouts/base.hbs +0 -6
  84. package/src/layouts/checkout.hbs +5 -1
  85. package/src/page_checkout_payment-details_guest-with-checkout-journey.html +1 -1
  86. package/src/page_my-account_change-password.html +0 -1
  87. package/src/page_my-order.html +1 -1
  88. package/src/page_payment-details-with-clearpay.html +2 -2
  89. package/src/page_payment-details-with-gift-card.html +5 -8
  90. package/src/page_shopping-cart-v2.html +2 -2
  91. package/src/page_split-orders-klarna.html +106 -0
  92. package/src/partials/scripts.hbs +1 -0
  93. package/src/scss/components/_custom-slider.scss +131 -3
  94. package/src/scss/components/_popover-mini-basket.scss +0 -4
  95. package/src/scss/components/checkout-payment-details-v2.scss +0 -2
  96. package/src/scss/pages/page_checkout_delivery-new.scss +0 -26
  97. package/src/scss/pages/page_product-details-v2.scss +0 -4
  98. package/src/sitemap.html +6 -0
  99. package/build/img/giftcard.svg +0 -28
  100. package/build/img/klarna.svg +0 -10
  101. package/build/img/payment/checkout/klarna.svg +0 -10
  102. package/build/img/payment/footer/klarna.svg +0 -10
  103. package/build/js/gift-cards.min.js +0 -1
  104. package/build/js/page/components/gift-cards.js +0 -894
  105. package/build/js/page/components/toggle-password-visibility.js +0 -22
  106. package/build/js/page/utils/gift-cards-utils.js +0 -170
  107. package/build/js/page/utils/input-handling.js +0 -92
  108. package/build/js/page/utils/show-hide-input.js +0 -28
  109. package/build/js/toggle-password-visibility.min.js +0 -1
  110. package/src/components/gift-cards-hint.hbs +0 -9
  111. package/src/components/gift-cards.hbs +0 -90
  112. package/src/components/giftcard-chip.hbs +0 -23
  113. package/src/components/giftcard-summary.hbs +0 -6
  114. package/src/img/giftcard.svg +0 -28
  115. package/src/img/klarna.svg +0 -10
  116. package/src/img/payment/checkout/klarna.svg +0 -10
  117. package/src/img/payment/footer/klarna.svg +0 -10
  118. package/src/js/components/general/mini-basket-slider.js +0 -8
  119. package/src/js/emulation/checkout-data.js +0 -35
  120. package/src/js/emulation/gift-cards.js +0 -205
  121. package/src/js/page/components/gift-cards.js +0 -894
  122. package/src/js/page/components/toggle-password-visibility.js +0 -22
  123. package/src/js/page/utils/gift-cards-utils.js +0 -170
  124. package/src/js/page/utils/input-handling.js +0 -92
  125. package/src/js/page/utils/show-hide-input.js +0 -28
  126. package/src/scss/components/_gift-cards.scss +0 -360
@@ -1,894 +0,0 @@
1
- import {initializeInputToggle} from "../utils/show-hide-input";
2
- import {updateOrderSummary} from './order-summary';
3
- import {hideLoader, showLoader, appendLoader} from "../utils/loader";
4
- import {
5
- ADD_GIFT_CARD,
6
- buildHintContext,
7
- buildSummaryEqualMap,
8
- formatGc16,
9
- isZeroAmount,
10
- linkifyClickHere,
11
- MESSAGE_BY_CODE,
12
- OK_CODE,
13
- PAY_WITH_GIFT_CARD,
14
- payWithGiftCard,
15
- REMOVE_GIFT_CARD,
16
- removeGiftCard,
17
- verifyGiftCard,
18
- PAY_MESSAGE_BY_CODE,
19
- DEFAULT_ERROR_MESSAGE
20
- } from "../utils/gift-cards-utils";
21
-
22
- import { clearErrorText, validateExactDigits } from "../utils/validation";
23
- import {
24
- createGcNumberInputHandler,
25
- digitsOnlyKeypress,
26
- handleGcNumberBlur,
27
- handleGcPinInput,
28
- handleGcPinKeypress,
29
- handleGcPinBlur,
30
- } from '../utils/input-handling';
31
-
32
- const Handlebars = require('hbsfy/runtime');
33
-
34
- Handlebars.registerPartial('info-icon', require("../../../components/info-icon.hbs"));
35
- Handlebars.registerPartial('loader', require("../../../elements/loader.hbs"));
36
-
37
- const giftCardsHint = require("../../../components/gift-cards-hint.hbs");
38
- const giftCardChip = require("../../../components/giftcard-chip.hbs");
39
- const giftcardSummary = require("../../../components/giftcard-summary.hbs");
40
- const notificationTpl = require("../../../elements/notifications.hbs");
41
-
42
- var Wick = window.Wick || {};
43
-
44
- Wick.GiftCard = {
45
- ADD_GIFT_CARD,
46
- REMOVE_GIFT_CARD,
47
- PAY_WITH_GIFT_CARD,
48
- el: {
49
- $blocks: $('.giftcard'),
50
- block: '.giftcard',
51
- toggle: '#giftcard-toggle',
52
- panel: '#giftcard-inline',
53
- hint: '.giftcard-hint',
54
- closeBtn: '.giftcard-inline__close',
55
- form: '.giftcard-inline__form',
56
- number: 'input[name="giftcard-number"]',
57
- pin: 'input[name="giftcard-pin"]',
58
- note: '.giftcard-note',
59
- field: '.giftcard__field',
60
- errorText: '.giftcard__error-text',
61
- fieldError: 'giftcard-field--error',
62
- showToggle: '.toggle-show',
63
- loader: '.giftcard__container .loader-wrapper',
64
- success: '#giftcard-applied',
65
- container: '.giftcard__container',
66
- paymentForm: '.checkout-payment-details__payment-method',
67
- billieField: '.form-row__field.form-row__field-billie',
68
- klarnaField: '.form-row__field.form-row__field-klarna',
69
- clearpayField: '.form-row__field.form-row__field-clearpay',
70
- appleField: '.form-row__field.form-row__field-apple',
71
- googleField: '.form-row__field.form-row__field-google',
72
- paypalField: '.form-row__field.form-row__field-paypal',
73
- cardField: '.form-row__field.form-row__card-payment',
74
- summaryHint: '.giftcard-summary__hint',
75
- chipList: '.giftcard-chip-list',
76
- summary: '.giftcard-summary',
77
- chip: '.giftcard-chip',
78
- giftcardRow: '.giftcard-row',
79
- checkoutContainer: '.checkout-payment-details',
80
- formRow: '.form-row',
81
- iconInfo: '.icon-info-component',
82
- toggleIcon: 'svg, i',
83
- iconEye: 'fa-eye',
84
- iconEyeSlash: 'fa-eye-slash',
85
- iconSvgEyeSlash: 'eye-slash',
86
- passwordToggleEvent: 'input.passwordToggle',
87
- ariaInvalidAttr: 'aria-invalid',
88
- typeAttr: 'type',
89
- dataIconAttr: 'data-icon',
90
- svg: 'svg',
91
- expandedAttr: 'aria-expanded',
92
- giftcardBtn: '.giftcard__btn',
93
- jsGiftcardAdd: '.js-giftcard-add',
94
- giftcardChipClose: '.giftcard-chip__close',
95
- body: 'body',
96
- loaderChip: '.loader-wrapper',
97
- chipListLoader: '.giftcard-chip-list > .loader-wrapper',
98
- notification: '.giftcard-inline .notification',
99
- giftCardInline: '.giftcard-inline',
100
- notificationRoot: '.notification',
101
- inlineHeader: '.giftcard-inline__header',
102
- ctaSelector: '.btn-enter-details',
103
- btnDetails: 'button',
104
- btnText: '.btn__text',
105
- btnEnterDetails: '.btn-enter-details',
106
- checkoutPaymentFields: '.billing-address .checkout-payment-details__descr',
107
- pageLoader: '.loader-wrapper.page-loader',
108
- cardRadio: '#checkout-payment-details-card, #_checkout-payment-details-card_card',
109
- billieInfo: '.checkout-payment-details__billie',
110
- klarnaInfo: '.checkout-payment-details__klarna',
111
- billingAddress: '.billing-address',
112
- altPaymentRowsAttr: '[data-apple],[data-google],[data-paypal],[data-klarna],[data-billie],[data-clearpay],[data-existing-card]',
113
- hiddenCard: 'checkout-payment-details__card-details_hidden',
114
- cardDetails: '.checkout-payment-details__card-details',
115
- },
116
-
117
- messages: {
118
- numberMessage: 'Gift Card should consist of 16 digits',
119
- pinMessage: 'Gift Card PIN should consist of 8 digits',
120
- ctaDefaultText: 'Enter card details',
121
- ctaGiftcardText: 'Pay with Gift Card',
122
- },
123
-
124
- maxChips: 3,
125
- successTimer: null,
126
- pendingServerGiftCards: null,
127
- altPaymentInfosLocked: false,
128
- altPaymentPanelsLocked: false,
129
- summaryTotal: null,
130
-
131
- resetPinToggle($root) {
132
- const {
133
- pin,
134
- field,
135
- showToggle,
136
- toggleIcon,
137
- iconEye,
138
- iconEyeSlash,
139
- iconSvgEyeSlash,
140
- passwordToggleEvent,
141
- typeAttr,
142
- dataIconAttr,
143
- svg
144
- } = this.el;
145
-
146
- const $pinField = $root.find(pin).closest(field);
147
- const $pinInput = $pinField.find(pin).first();
148
-
149
- $pinInput.attr(typeAttr, 'password');
150
-
151
- const $toggle = $pinField.find(showToggle).first();
152
- const $icon = $toggle.find(toggleIcon).first();
153
-
154
- if ($icon.length) {
155
- $icon.removeClass(`${iconEye} ${iconEyeSlash}`).addClass(iconEyeSlash);
156
- if ($icon.is(svg) && $icon.attr(dataIconAttr)) {
157
- $icon.attr(dataIconAttr, iconSvgEyeSlash);
158
- }
159
- }
160
-
161
- const hasValue = ($pinInput.val() || '').length > 0;
162
- $toggle.toggle(hasValue);
163
-
164
- $pinInput.trigger(passwordToggleEvent);
165
- },
166
-
167
- resetForm($root) {
168
- const { number, pin, note } = this.el;
169
- const $num = $root.find(number);
170
- const $pinInput = $root.find(pin);
171
-
172
- $num.val('');
173
- $pinInput.val('');
174
- clearErrorText($num, this.el.field, this.el.errorText, this.el.fieldError, this.el.ariaInvalidAttr);
175
- clearErrorText($pinInput, this.el.field, this.el.errorText, this.el.fieldError, this.el.ariaInvalidAttr);
176
- $root.find(note).remove();
177
-
178
- this.hideBanner($root);
179
- this.resetPinToggle($root);
180
- },
181
-
182
- open($root) {
183
- const { toggle, panel, hint, pin, expandedAttr, passwordToggleEvent } = this.el;
184
- this.hideBanner($root);
185
- $root.show();
186
-
187
- $root.find(panel).prop('hidden', false);
188
- $root.find(toggle).attr(expandedAttr, 'true').hide();
189
- $root.find(hint).hide();
190
- $root.find(pin).trigger(passwordToggleEvent);
191
- },
192
-
193
- close($root) {
194
- const { toggle, panel, loader, expandedAttr } = this.el;
195
- const $toggle = $root.find(toggle);
196
- const $panel = $root.find(panel);
197
- const $loader = $root.find(loader);
198
-
199
- showLoader($loader);
200
-
201
- setTimeout(() => {
202
- hideLoader($loader);
203
-
204
- $panel.prop('hidden', true);
205
- $toggle.attr(expandedAttr, 'false').show().trigger('focus');
206
- this.updateHintVisibility($root);
207
- }, 1000);
208
- },
209
-
210
- showSubmitSpinner($root) {
211
- const { panel, toggle, hint, expandedAttr } = this.el;
212
- $root.find(panel).prop('hidden', true);
213
- $root.find(toggle).attr(expandedAttr, 'false').show().trigger('focus');
214
- $root.find(hint).show();
215
- this.showSuccess($root);
216
- },
217
-
218
- handleToggleClick(e) {
219
- e.preventDefault();
220
- this.open($(e.currentTarget).closest(this.el.$blocks));
221
- },
222
-
223
- handleCloseClick(e) {
224
- e.preventDefault();
225
- const $root = $(e.currentTarget).closest(this.el.$blocks);
226
- this.resetForm($root);
227
- this.close($root);
228
- },
229
-
230
- finalizeSuccess($root, $success) {
231
- let { panel, toggle, hint, expandedAttr } = this.el;
232
-
233
- if ($success && $success.length) {
234
- $success.attr('hidden', 'hidden').removeClass('fade show').off('transitionend');
235
- }
236
-
237
- this.resetForm($root);
238
- $root.find(panel).prop('hidden', true);
239
- $root.find(toggle).attr(expandedAttr, 'false').show();
240
- $root.find(hint).show();
241
-
242
- if (this.pendingServerGiftCards) {
243
- this.renderGiftCardsFromList($root, this.pendingServerGiftCards);
244
- this.pendingServerGiftCards = null;
245
- }
246
-
247
- this.updateHintVisibility($root);
248
- this.successTimer = null;
249
- },
250
-
251
- showSuccess($root) {
252
- const { success} = this.el;
253
-
254
- if (this.successTimer) {
255
- clearTimeout(this.successTimer);
256
- this.successTimer = null;
257
- }
258
-
259
- $root.hide();
260
- const $success = $(success);
261
- $success.removeAttr('hidden').addClass('fade');
262
- $success[0] && $success[0].offsetWidth;
263
- $success.addClass('show');
264
-
265
- this.successTimer = setTimeout(() => {
266
- $success.removeClass('show');
267
- const handler = () => this.finalizeSuccess($root, $success);
268
-
269
- $success.on('transitionend', handler);
270
- setTimeout(handler, 200)
271
- }, 3000);
272
- },
273
-
274
- handleFormSubmit(e) {
275
- const { number, block, giftcardRow, loaderChip } = this.el;
276
- e.preventDefault();
277
-
278
- const $root = $(e.currentTarget).closest(block);
279
- this.hideBanner($root);
280
-
281
- const $num = $root.find(number);
282
- $num.val(formatGc16($num.val()));
283
-
284
- const $numInput = $root.find(this.el.number);
285
- const $pinInput = $root.find(this.el.pin);
286
-
287
- const numberBlurOpts = {
288
- fieldSelector: this.el.field,
289
- errorTextSelector: this.el.errorText,
290
- errorClass: this.el.fieldError,
291
- ariaInvalidAttr: this.el.ariaInvalidAttr,
292
- numberMessage: this.messages.numberMessage,
293
- };
294
-
295
- const pinBlurOpts = {
296
- fieldSelector: this.el.field,
297
- errorTextSelector: this.el.errorText,
298
- errorClass: this.el.fieldError,
299
- ariaInvalidAttr: this.el.ariaInvalidAttr,
300
- pinMessage: this.messages.pinMessage,
301
- };
302
-
303
- const okNumber = validateExactDigits($numInput, 16, this.messages.numberMessage, this.el);
304
- const okPin = validateExactDigits($pinInput, 8, this.messages.pinMessage, this.el);
305
-
306
- if (!(okNumber && okPin)) {
307
- handleGcNumberBlur({ currentTarget: $numInput[0] }, numberBlurOpts);
308
- handleGcPinBlur({ currentTarget: $pinInput[0] }, pinBlurOpts);
309
- (!okNumber ? $numInput : $pinInput).trigger('focus');
310
- return;
311
- }
312
-
313
- const giftCardNumber = this.getNumberValue($root);
314
- const pin = this.getPinValue($root);
315
- const $row = $root.closest(giftcardRow);
316
-
317
- let $loader = $row.children(loaderChip);
318
-
319
- if (!$loader.length) {
320
- appendLoader({ wrapper: $row });
321
- $loader = $row.children(loaderChip).last();
322
- }
323
-
324
- verifyGiftCard($loader, giftCardNumber, pin)
325
- .then((res) => this.handleVerifyResponse($root, res))
326
- .catch((err) => {
327
- const msg = this.getErrorMessage(err);
328
- this.showBannerError($root, msg);
329
- });
330
- },
331
-
332
- handleVerifyResponse($root, res) {
333
- if (res && res.code === OK_CODE) {
334
- if (!Array.isArray(res.giftCards)) {
335
- this.showBannerError($root, DEFAULT_ERROR_MESSAGE);
336
- return;
337
- }
338
-
339
- this.pendingServerGiftCards = res.giftCards.slice();
340
-
341
- if (res.orderTotal != null || res.giftCardTotal != null) {
342
- const data = { total: res.orderTotal, giftCardApplied: res.giftCardTotal };
343
- updateOrderSummary(data, buildSummaryEqualMap(data), true);
344
- this.summaryTotal = res.orderTotal;
345
- this.toggleBillingDescrForZero($root);
346
- this.updateCtaButton($root);
347
- }
348
-
349
- this.resetForm($root);
350
- this.showSubmitSpinner($root);
351
- return;
352
- }
353
-
354
- const msg = (res && MESSAGE_BY_CODE[res.code]) || DEFAULT_ERROR_MESSAGE;
355
- this.showBannerError($root, msg);
356
- },
357
-
358
- updateHintVisibility($root) {
359
- const {
360
- chipList, giftcardRow, hint, panel, toggle, iconInfo, expandedAttr,
361
- summaryHint, chip, block, body
362
- } = this.el;
363
-
364
- const $row = $root.closest(giftcardRow);
365
- const $giftcard = $row.find(block).first();
366
- const count = $row.find(`${chipList} ${chip}`).length;
367
- const limit = this.maxChips || 3;
368
-
369
- const zeroTotal = this.summaryTotal != null ? isZeroAmount(this.summaryTotal) : false;
370
-
371
- this.toggleAltPayments($giftcard, count === 0);
372
- this.toggleAltPaymentInfos($giftcard, count === 0);
373
-
374
- if (count > 0) {
375
- if (!this.altPaymentPanelsLocked) {
376
- this.showOnlyBillingAddress($giftcard);
377
- this.altPaymentPanelsLocked = true;
378
- } else {
379
- this.showOnlyBillingAddress($giftcard);
380
- }
381
- } else {
382
- if (!this.altPaymentPanelsLocked) {
383
- this.toggleAltPayments($giftcard, true);
384
- this.toggleAltPaymentInfos($giftcard, true);
385
- } else {
386
- this.showOnlyBillingAddress($giftcard);
387
- }
388
- }
389
-
390
- const $summary = this.ensureSummaryContainer($giftcard);
391
-
392
- if (count === 0) {
393
- $summary.hide();
394
- $giftcard.show();
395
- this.resetForm($giftcard);
396
- $giftcard.find(panel).prop('hidden', true);
397
- $giftcard.find(toggle).attr(expandedAttr, 'false').show();
398
- $giftcard.find(hint)[zeroTotal ? 'hide' : 'show']();
399
- this.updateCtaButton($giftcard);
400
- return;
401
- }
402
-
403
- this.setBillingLabelToCard($giftcard);
404
- $summary.show();
405
- $giftcard.hide();
406
- $giftcard.find(hint).hide();
407
-
408
- const ctx = buildHintContext(count, limit, zeroTotal);
409
- const html = giftCardsHint(ctx);
410
- const $old = $summary.find(summaryHint).first();
411
- const $new = $(html);
412
-
413
- if ($old.length) $old.replaceWith($new);
414
- else $summary.append($new);
415
-
416
-
417
- if (zeroTotal) {
418
- $summary.find(summaryHint).hide();
419
- }
420
-
421
- this.toggleCardDetailsForTotal($giftcard);
422
-
423
- if ($.fn.tooltip) {
424
- $summary.find(summaryHint).find(iconInfo).tooltip({ container: body });
425
- }
426
- },
427
-
428
- renderChipHTML({ id, maskedNumber, currency, amount }) {
429
- return giftCardChip({ id, maskedNumber, currency, amount });
430
- },
431
-
432
- toggleAltPaymentInfos($root, show) {
433
- const { checkoutContainer, billieInfo, klarnaInfo } = this.el;
434
- const $container = $root.closest(checkoutContainer);
435
-
436
- if (this.altPaymentInfosLocked) {
437
- show = false;
438
- }
439
-
440
- [$container.find(billieInfo), $container.find(klarnaInfo)].forEach(($panel) => {
441
- if ($panel && $panel.length) {
442
- $panel[show ? 'show' : 'hide']();
443
- }
444
- });
445
-
446
- if (!show) this.altPaymentInfosLocked = true;
447
- },
448
-
449
- toggleAltPayments($root, show) {
450
- const {
451
- paymentForm,
452
- billieField,
453
- klarnaField,
454
- clearpayField,
455
- appleField,
456
- googleField,
457
- paypalField,
458
- checkoutContainer,
459
- formRow,
460
- cardField,
461
- } = this.el;
462
-
463
- const $container = $root.closest(checkoutContainer);
464
- const $paymentField = $container.find(paymentForm);
465
- const isTotalZero = this.summaryTotal != null ? isZeroAmount(this.summaryTotal) : false;
466
-
467
- const paymentSelectors = [
468
- billieField,
469
- klarnaField,
470
- clearpayField,
471
- appleField,
472
- googleField,
473
- paypalField,
474
- ];
475
-
476
- paymentSelectors.forEach((sel) => {
477
- const $row = $paymentField.find(sel).closest(formRow);
478
- if ($row.length) {
479
- const shouldShow = show && !isTotalZero;
480
- $row[shouldShow ? 'show' : 'hide']();
481
- }
482
- });
483
-
484
- const $cardRow = $paymentField.find(cardField).closest(formRow);
485
- if ($cardRow.length) {
486
- $cardRow[isTotalZero ? 'hide' : 'show']();
487
- }
488
-
489
- if (!show) {
490
- this.ensureCardPaymentSelected($paymentField);
491
- }
492
- },
493
-
494
- ensureCardPaymentSelected($paymentField) {
495
- const { cardField, cardRadio, formRow } = this.el;
496
-
497
- const $cardFieldRow = $paymentField.find(cardField).closest(formRow);
498
- if (!$cardFieldRow.length) {
499
- return;
500
- }
501
-
502
- const $radio = $cardFieldRow.find(cardRadio);
503
-
504
- if ($radio.length && !$radio.prop('checked')) {
505
- $radio.prop('checked', true);
506
- $radio.trigger('change');
507
- this.updateCtaButton($cardFieldRow);
508
- }
509
- },
510
-
511
- handleAddAnotherClick(e) {
512
- e.preventDefault();
513
- const { giftcardRow, chipList, chip, block, number, summaryHint } = this.el;
514
-
515
- const $row = $(e.currentTarget).closest(giftcardRow);
516
- const count = $row.find(`${chipList} ${chip}`).length;
517
- if (count >= this.maxChips) return;
518
-
519
- const $giftcard = $row.find(block).first();
520
- this.resetForm($giftcard);
521
- this.open($giftcard);
522
-
523
- $row.find(summaryHint).hide();
524
-
525
- setTimeout(() => {
526
- $giftcard.find(number).trigger('focus');
527
- }, 0);
528
- },
529
-
530
- getErrorMessage(payload) {
531
- const code =
532
- payload && (typeof payload.code === 'number' || typeof payload.code === 'string')
533
- ? payload.code
534
- : undefined;
535
-
536
- return (code != null && MESSAGE_BY_CODE[code]) || DEFAULT_ERROR_MESSAGE;
537
- },
538
-
539
- handleChipCloseClick(e) {
540
- e.preventDefault();
541
- const {
542
- chip,
543
- giftcardRow,
544
- block,
545
- giftcardChipClose,
546
- chipList,
547
- loaderChip,
548
- } = this.el;
549
-
550
- const $clickedChip = $(e.currentTarget).closest(chip);
551
- const $row = $clickedChip.closest(giftcardRow);
552
- const $giftcard = $row.find(block).first();
553
- const $summary = this.ensureSummaryContainer($giftcard);
554
-
555
- const $chips = $summary.find(`${chipList} ${chip}`);
556
- const index = $chips.index($clickedChip);
557
- if (index < 0) return;
558
-
559
- let $loader = $row.children(loaderChip);
560
- if (!$loader.length) {
561
- appendLoader({ wrapper: $row });
562
- $loader = $row.children(loaderChip).last();
563
- }
564
-
565
- $row
566
- .find(giftcardChipClose)
567
- .css('pointer-events', 'none')
568
- .attr('aria-disabled', 'true');
569
-
570
- removeGiftCard($loader, index)
571
- .then((res) => this.handleRemoveResponse($giftcard, res))
572
- .catch((err) => {
573
- const msg = this.getErrorMessage(err);
574
- this.showBannerError($giftcard, msg);
575
- })
576
- .finally(() => {
577
- hideLoader($loader);
578
- $row.find(giftcardChipClose).css('pointer-events', '').removeAttr('aria-disabled');
579
- });
580
- },
581
-
582
- handleRemoveResponse($giftcard, res) {
583
- if (res && res.code === OK_CODE) {
584
- const giftCardsList = Array.isArray(res.giftCards) ? res.giftCards : [];
585
- const data = { total: res.orderTotal, giftCardApplied: res.giftCardTotal };
586
- this.summaryTotal = res.orderTotal;
587
-
588
- this.renderGiftCardsFromList($giftcard, giftCardsList, data);
589
-
590
- if (res.orderTotal != null || res.giftCardTotal != null) {
591
- updateOrderSummary(data, buildSummaryEqualMap(data), true);
592
- }
593
- this.updateCtaButton($giftcard);
594
- this.toggleBillingDescrForZero($giftcard);
595
- return;
596
- }
597
-
598
- const msg = (res && MESSAGE_BY_CODE[res.code]) || DEFAULT_ERROR_MESSAGE;
599
- this.showBannerError($giftcard, msg);
600
- },
601
-
602
- ensureSummaryContainer($root) {
603
- const { summary, giftcardRow } = this.el;
604
- const $row = $root.closest(giftcardRow);
605
- let $summary = $row.find(summary).first();
606
-
607
- if (!$summary.length) {
608
- $summary = $(giftcardSummary({}));
609
- $row.append($summary);
610
- }
611
-
612
- return $summary;
613
- },
614
-
615
- getPageLoader() {
616
- const $pl = $(this.el.pageLoader);
617
- if (!$pl.parent().is('body')) $pl.appendTo('body');
618
- return $pl;
619
- },
620
-
621
- showPageLoader() {
622
- const $pl = this.getPageLoader();
623
- showLoader($pl);
624
- },
625
-
626
- updateCtaButton($scope) {
627
- const { ctaSelector, btnDetails, btnText, checkoutContainer } = this.el;
628
- let $cta = $(ctaSelector);
629
- if (!$cta.length) {
630
- $cta = $scope.closest(checkoutContainer).find(ctaSelector);
631
- }
632
- if (!$cta.length) return;
633
-
634
- const $wrap = $cta.closest(btnDetails).length ? $cta.closest(btnDetails) : $cta;
635
- const $text = $wrap.find(btnText).first().length ? $wrap.find(btnText).first() : $wrap;
636
- const useGiftcard = isZeroAmount(this.summaryTotal);
637
-
638
- $text.text(useGiftcard ? this.messages.ctaGiftcardText : this.messages.ctaDefaultText);
639
- $wrap.attr('data-mode', useGiftcard ? 'giftcards' : 'card');
640
-
641
- if (useGiftcard) {
642
- $wrap.attr('type', 'button').removeAttr('form');
643
- } else {
644
- $wrap.attr('type', 'submit').attr('form', 'hopPaymentAddressPostForm');
645
- }
646
- },
647
-
648
- toggleBillingDescrForZero($scope) {
649
- const $container = $scope.closest(this.el.checkoutContainer);
650
- const $descr = $container.find(this.el.checkoutPaymentFields);
651
- if (!$descr.length) return;
652
-
653
- const shouldHide = isZeroAmount(this.summaryTotal);
654
- $descr[shouldHide ? 'hide' : 'show']();
655
- },
656
-
657
- getNumberValue($root) {
658
- const { number } = this.el;
659
- return String($root.find(number).val() || '').replace(/\D/g, '');
660
- },
661
-
662
- getPinValue($root) {
663
- const { pin } = this.el;
664
- return String($root.find(pin).val() || '').replace(/\D/g, '');
665
- },
666
-
667
- bindGiftcardCtaHandler() {
668
- const self = this;
669
-
670
- $(document).off('click.giftcard', this.el.btnEnterDetails);
671
- $(document).on('click.giftcard', this.el.btnEnterDetails, function (e) {
672
- const $btn = $(this);
673
- const mode = $btn.attr('data-mode');
674
-
675
- if (mode !== 'giftcards') return;
676
-
677
- e.preventDefault();
678
- e.stopPropagation();
679
- e.stopImmediatePropagation();
680
-
681
- const $scope = $btn.closest(self.el.checkoutContainer).find(self.el.block).first();
682
- const $root = $scope.length ? $scope : $(self.el.block).first();
683
-
684
- self.showPageLoader();
685
-
686
- payWithGiftCard()
687
- .then(({ url }) => {
688
- if (typeof url === 'string' && url) {
689
- window.location.href = url;
690
- }
691
- })
692
- .catch((error) => {
693
- if (Array.isArray(error?.giftCards)) {
694
- self.renderGiftCardsFromList($root, error.giftCards);
695
- }
696
-
697
- const numberCode = Number(error?.errorCode);
698
-
699
- if (Number.isFinite(numberCode) && PAY_MESSAGE_BY_CODE[numberCode]) {
700
- Wick.Notification.show({
701
- text: linkifyClickHere(PAY_MESSAGE_BY_CODE[numberCode]),
702
- container: '.globalMessages .container',
703
- type: 'error',
704
- });
705
- }
706
- })
707
- .finally(() => {
708
- const $pl = self.getPageLoader();
709
- hideLoader($pl);
710
- });
711
- });
712
- },
713
-
714
- showBannerError($root, message, title = '') {
715
- const { notificationRoot, giftCardInline, inlineHeader } = this.el;
716
- const $inline = $root.find(giftCardInline);
717
-
718
- $inline.find(notificationRoot).remove();
719
-
720
- const html = notificationTpl({
721
- classModifier: 'notification_error',
722
- error: true,
723
- withCloseBtn: true,
724
- title: title || undefined,
725
- text: linkifyClickHere(message)
726
- });
727
-
728
- $inline.find(inlineHeader).after(html);
729
- },
730
-
731
-
732
- hideBanner($root) {
733
- const { notification } = this.el;
734
- $root.find(notification).remove();
735
- },
736
-
737
- mapGiftToChipData($root, gift) {
738
- const $giftcard = $root.closest(this.el.block);
739
- const currency = $giftcard.data('currency') || '£';
740
- const rawAmount = Number(gift.amountToRedeem || 0);
741
- const amount = Number.isFinite(rawAmount) ? rawAmount.toFixed(2) : '0.00';
742
- return {
743
- id: gift.id,
744
- maskedNumber: String(gift.maskedNumber || ''),
745
- currency,
746
- amount,
747
- };
748
- },
749
-
750
- renderGiftCardsFromList($root, giftCards, summaryData) {
751
- const { chipList, loaderChip, chip } = this.el;
752
- const $summary = this.ensureSummaryContainer($root);
753
- const $list = $summary.find(chipList);
754
- $list.children(`${chip}:not(${loaderChip})`).remove();
755
-
756
- const html = (giftCards || [])
757
- .map((g) => this.renderChipHTML(this.mapGiftToChipData($root, g)))
758
- .join('');
759
-
760
- if (html) {
761
- $list.append(html);
762
- $summary.show();
763
- }
764
-
765
- this.updateHintVisibility($root, summaryData);
766
-
767
- if (Array.isArray(giftCards) && giftCards.length > 0) {
768
- this.setBillingLabelToCard($root);
769
- }
770
- },
771
-
772
- toggleCardDetailsForTotal($scope) {
773
- const { checkoutContainer, cardDetails, hiddenCard } = this.el;
774
- const $container = $scope.closest(checkoutContainer);
775
- const $cardDetails = $container.find(cardDetails);
776
- if (!$cardDetails.length) return;
777
-
778
- const zero = this.summaryTotal != null ? isZeroAmount(this.summaryTotal) : false;
779
- if (zero) $cardDetails.addClass(hiddenCard);
780
- },
781
-
782
- setBillingLabelToCard($scope) {
783
- const $container = $scope.closest(this.el.checkoutContainer);
784
- const $billing = $container.find(this.el.billingAddress);
785
- if (!$billing.length) return;
786
-
787
- const $label = $billing.find('[for="card-name"]');
788
- if ($label.length) {
789
- $label.text('Name on card');
790
- }
791
- },
792
-
793
- showOnlyBillingAddress($root) {
794
- const { checkoutContainer, billingAddress, altPaymentRowsAttr, hiddenCard } = this.el;
795
- const $container = $root.closest(checkoutContainer);
796
- $container.find(billingAddress).removeClass(hiddenCard);
797
- $container.find(altPaymentRowsAttr).addClass(hiddenCard);
798
- this.toggleAltPaymentInfos($root, false);
799
- },
800
-
801
- useGlobalError($root, message) {
802
- if (window.Wick && Wick.Notification && typeof Wick.Notification.show === 'function') {
803
- const text = linkifyClickHere ? linkifyClickHere(message) : String(message || '');
804
- Wick.Notification.show({
805
- text,
806
- container: '.globalMessages .container',
807
- type: 'error',
808
- });
809
- }
810
- },
811
-
812
- bindEvents() {
813
- const { number, pin, toggle, closeBtn, giftcardBtn, jsGiftcardAdd, giftcardChipClose } = this.el;
814
-
815
- $(document).off('.giftcard');
816
-
817
- const handleNumberInput = createGcNumberInputHandler({
818
- fieldSelector: this.el.field,
819
- fieldErrorClass: this.el.fieldError,
820
- errorTextSelector: this.el.errorText,
821
- ariaInvalidAttr: this.el.ariaInvalidAttr,
822
- });
823
-
824
- const onNumberBlur = (e) =>
825
- handleGcNumberBlur(e, {
826
- fieldSelector: this.el.field,
827
- errorTextSelector: this.el.errorText,
828
- errorClass: this.el.fieldError,
829
- ariaInvalidAttr: this.el.ariaInvalidAttr,
830
- numberMessage: this.messages.numberMessage,
831
- });
832
-
833
- const onPinInput = (e) =>
834
- handleGcPinInput(e, {
835
- fieldSelector: this.el.field,
836
- errorTextSelector: this.el.errorText,
837
- errorClass: this.el.fieldError,
838
- ariaInvalidAttr: this.el.ariaInvalidAttr,
839
- });
840
-
841
- const onPinBlur = (e) =>
842
- handleGcPinBlur(e, {
843
- fieldSelector: this.el.field,
844
- errorTextSelector: this.el.errorText,
845
- errorClass: this.el.fieldError,
846
- ariaInvalidAttr: this.el.ariaInvalidAttr,
847
- pinMessage: this.messages.pinMessage,
848
- });
849
-
850
-
851
- $(document)
852
- .on('input.giftcard', number, handleNumberInput)
853
- .on('keypress.giftcard', number, digitsOnlyKeypress)
854
- .on('blur.giftcard', number, onNumberBlur);
855
-
856
- $(document)
857
- .on('input.giftcard', pin, onPinInput)
858
- .on('keypress.giftcard', pin, handleGcPinKeypress)
859
- .on('blur.giftcard', pin, onPinBlur);
860
-
861
- $(document)
862
- .on('click.giftcard', toggle, this.handleToggleClick.bind(this))
863
- .on('click.giftcard', closeBtn, this.handleCloseClick.bind(this))
864
- .on('click.giftcard', giftcardBtn, this.handleFormSubmit.bind(this))
865
- .on('click.giftcard', jsGiftcardAdd, this.handleAddAnotherClick.bind(this))
866
- .on('click.giftcard', giftcardChipClose, this.handleChipCloseClick.bind(this))
867
-
868
- this.bindGiftcardCtaHandler();
869
- },
870
-
871
- init(payload = {}) {
872
- const { field, pin, $blocks } = this.el;
873
- this.bindEvents();
874
- if ($blocks && $blocks.length) {
875
- const $firstBlock = $blocks.first();
876
- if (Array.isArray(payload.giftCards) && payload.giftCards.length) {
877
- this.renderGiftCardsFromList($firstBlock, payload.giftCards);
878
- }
879
-
880
- const code = payload.errorCode;
881
-
882
- if (Number.isFinite(code) && PAY_MESSAGE_BY_CODE[code]) {
883
- this.useGlobalError($firstBlock, PAY_MESSAGE_BY_CODE[code]);
884
- }
885
- }
886
-
887
- $blocks.each((index, block) => {
888
- const $pinField = $(block).find(pin).closest(field);
889
- if ($pinField.length) {
890
- initializeInputToggle($pinField);
891
- }
892
- });
893
- }
894
- };