wickes-css2 2.106.0-develop.1 → 2.106.0-develop.11

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