wickes-css2 2.103.0-RG-1576-error-handling-new-codes.8 → 2.103.0-RG-1587-replace-klarna-logo-with-svg-image.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 (100) hide show
  1. package/Readme.md +2 -2
  2. package/build/css/components/card-product-banner.css +1 -1
  3. package/build/css/components/checkout-payment-details-v2.css +1 -1
  4. package/build/css/main.css +1 -1
  5. package/build/css/pages/page_checkout_delivery-new.css +1 -1
  6. package/build/css/pages/page_products-list-combined.css +1 -1
  7. package/build/css/pages/page_products-list.css +1 -1
  8. package/build/css/pdp-main-non-critical.css +1 -1
  9. package/build/css/plp-main.css +1 -1
  10. package/build/img/klarna.svg +10 -0
  11. package/build/img/payment/checkout/klarna.svg +10 -0
  12. package/build/img/payment/footer/klarna.svg +10 -0
  13. package/build/js/account-members.min.js +1 -1
  14. package/build/js/add-project-list-id.min.js +1 -1
  15. package/build/js/address-book.min.js +1 -1
  16. package/build/js/basket.min.js +2 -2
  17. package/build/js/bundle.min.js +1 -1
  18. package/build/js/change-password.min.js +1 -1
  19. package/build/js/checkout.min.js +2 -2
  20. package/build/js/emulation.min.js +70 -272
  21. package/build/js/general.bundle.min.js +1 -1
  22. package/build/js/merged-checkout.min.js +2 -2
  23. package/build/js/page/components/order-summary.js +25 -42
  24. package/build/js/page/plp-cards-v2.js +15 -6
  25. package/build/js/page/plp-load-more.js +1 -1
  26. package/build/js/page/utils/validation.js +1 -46
  27. package/build/js/pdp.bundle.min.js +1 -1
  28. package/build/js/personal-details.min.js +1 -1
  29. package/build/js/plp.bundle.min.js +1 -1
  30. package/build/js/project-list.min.js +1 -44
  31. package/build/js/quiz.min.js +1 -1
  32. package/build/js/track-my-order.min.js +1 -1
  33. package/package.json +2 -2
  34. package/src/components/card_product_v2.hbs +10 -5
  35. package/src/components/card_sponsor_banner.hbs +8 -0
  36. package/src/components/card_sponsor_product.hbs +6 -0
  37. package/src/components/checkout-payment-details-v2.hbs +9 -12
  38. package/src/components/checkout_payment-new.hbs +1 -4
  39. package/src/components/checkout_payment-other-methods.hbs +1 -4
  40. package/src/components/injected-content.hbs +1 -1
  41. package/src/components/payments-checkout-v2.hbs +2 -7
  42. package/src/components/payments-checkout.hbs +1 -6
  43. package/src/components/payments.hbs +1 -5
  44. package/src/components/table_order-details-klarna.hbs +1 -1
  45. package/src/components/table_payment.hbs +1 -4
  46. package/src/data/data_search-results_v2.json +56 -141
  47. package/src/data/data_wismo.json +1 -1
  48. package/src/elements/form-row.hbs +1 -1
  49. package/src/elements/input.hbs +2 -31
  50. package/src/img/klarna.svg +10 -0
  51. package/src/img/payment/checkout/klarna.svg +10 -0
  52. package/src/img/payment/footer/klarna.svg +10 -0
  53. package/src/js/components/banner-placement-manager.js +267 -0
  54. package/src/js/components/general/notification.js +1 -2
  55. package/src/js/components/toggle-password-visibility.js +58 -0
  56. package/src/js/emulation/banner-placement-manager.js +53 -0
  57. package/src/js/emulation/checkout-payment-details.js +14 -23
  58. package/src/js/emulation/forms.js +2 -7
  59. package/src/js/page/components/order-summary.js +25 -42
  60. package/src/js/page/plp-cards-v2.js +15 -6
  61. package/src/js/page/plp-load-more.js +1 -1
  62. package/src/js/page/utils/validation.js +1 -46
  63. package/src/layouts/checkout.hbs +5 -1
  64. package/src/page_checkout_payment-details_guest-with-checkout-journey.html +1 -1
  65. package/src/page_my-account_change-password.html +0 -1
  66. package/src/page_my-order.html +1 -1
  67. package/src/page_payment-details-with-clearpay.html +2 -2
  68. package/src/page_payment-details-with-gift-card.html +5 -8
  69. package/src/page_plp_v2.html +16 -6
  70. package/src/page_search-results.html +12 -2
  71. package/src/page_shopping-cart-v2.html +2 -2
  72. package/src/scss/components/card-product-banner.scss +91 -3
  73. package/src/scss/components/checkout-payment-details-v2.scss +0 -2
  74. package/src/scss/pages/page_checkout_delivery-new.scss +0 -26
  75. package/src/scss/pages/page_products-list-combined.scss +11 -0
  76. package/src/scss/pages/page_products-list.scss +8 -0
  77. package/src/sitemap.html +0 -6
  78. package/build/img/giftcard.svg +0 -28
  79. package/build/js/gift-cards.min.js +0 -1
  80. package/build/js/page/components/gift-cards.js +0 -892
  81. package/build/js/page/components/toggle-password-visibility.js +0 -22
  82. package/build/js/page/utils/gift-cards-utils.js +0 -170
  83. package/build/js/page/utils/input-handling.js +0 -92
  84. package/build/js/page/utils/show-hide-input.js +0 -28
  85. package/build/js/toggle-password-visibility.min.js +0 -1
  86. package/src/components/gift-cards-hint.hbs +0 -9
  87. package/src/components/gift-cards.hbs +0 -90
  88. package/src/components/giftcard-chip.hbs +0 -23
  89. package/src/components/giftcard-summary.hbs +0 -6
  90. package/src/img/giftcard.svg +0 -28
  91. package/src/js/components/product-banner.js +0 -148
  92. package/src/js/emulation/checkout-data.js +0 -35
  93. package/src/js/emulation/gift-cards.js +0 -205
  94. package/src/js/page/components/gift-cards.js +0 -892
  95. package/src/js/page/components/toggle-password-visibility.js +0 -22
  96. package/src/js/page/utils/gift-cards-utils.js +0 -170
  97. package/src/js/page/utils/input-handling.js +0 -92
  98. package/src/js/page/utils/show-hide-input.js +0 -28
  99. package/src/page_split-orders-klarna.html +0 -106
  100. package/src/scss/components/_gift-cards.scss +0 -360
@@ -1,892 +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',
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.toggleBillingDescrForZero($root, { total: res.orderTotal });
345
- this.summaryTotal = res.orderTotal;
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
-
466
- const paymentSelectors = [
467
- billieField,
468
- klarnaField,
469
- clearpayField,
470
- appleField,
471
- googleField,
472
- paypalField,
473
- ];
474
-
475
- paymentSelectors.forEach((sel) => {
476
- const $row = $paymentField.find(sel).closest(formRow);
477
- if ($row.length) {
478
- $row[show ? 'show' : 'hide']();
479
- }
480
- });
481
-
482
- const $cardRow = $paymentField.find(cardField).closest(formRow);
483
- if ($cardRow.length) {
484
- $cardRow.show();
485
- }
486
-
487
- if (!show) {
488
- this.ensureCardPaymentSelected($paymentField);
489
- }
490
- },
491
-
492
- ensureCardPaymentSelected($paymentField) {
493
- const { cardField, cardRadio, formRow } = this.el;
494
-
495
- const $cardFieldRow = $paymentField.find(cardField).closest(formRow);
496
- if (!$cardFieldRow.length) {
497
- return;
498
- }
499
-
500
- const $radio = $cardFieldRow.find(cardRadio);
501
-
502
- if ($radio.length && !$radio.prop('checked')) {
503
- $radio.prop('checked', true);
504
- $radio.trigger('change');
505
- this.updateCtaButton($cardFieldRow);
506
- }
507
- },
508
-
509
- handleAddAnotherClick(e) {
510
- e.preventDefault();
511
- const { giftcardRow, chipList, chip, block, number, summaryHint } = this.el;
512
-
513
- const $row = $(e.currentTarget).closest(giftcardRow);
514
- const count = $row.find(`${chipList} ${chip}`).length;
515
- if (count >= this.maxChips) return;
516
-
517
- const $giftcard = $row.find(block).first();
518
- this.resetForm($giftcard);
519
- this.open($giftcard);
520
-
521
- $row.find(summaryHint).hide();
522
-
523
- setTimeout(() => {
524
- $giftcard.find(number).trigger('focus');
525
- }, 0);
526
- },
527
-
528
- getErrorMessage(payload) {
529
- const code =
530
- payload && (typeof payload.code === 'number' || typeof payload.code === 'string')
531
- ? payload.code
532
- : undefined;
533
-
534
- return (code != null && MESSAGE_BY_CODE[code]) || DEFAULT_ERROR_MESSAGE;
535
- },
536
-
537
- handleChipCloseClick(e) {
538
- e.preventDefault();
539
- const {
540
- chip,
541
- giftcardRow,
542
- block,
543
- giftcardChipClose,
544
- chipList,
545
- loaderChip,
546
- } = this.el;
547
-
548
- const $clickedChip = $(e.currentTarget).closest(chip);
549
- const $row = $clickedChip.closest(giftcardRow);
550
- const $giftcard = $row.find(block).first();
551
- const $summary = this.ensureSummaryContainer($giftcard);
552
-
553
- const $chips = $summary.find(`${chipList} ${chip}`);
554
- const index = $chips.index($clickedChip);
555
- if (index < 0) return;
556
-
557
- let $loader = $row.children(loaderChip);
558
- if (!$loader.length) {
559
- appendLoader({ wrapper: $row });
560
- $loader = $row.children(loaderChip).last();
561
- }
562
-
563
- $row
564
- .find(giftcardChipClose)
565
- .css('pointer-events', 'none')
566
- .attr('aria-disabled', 'true');
567
-
568
- removeGiftCard($loader, index)
569
- .then((res) => this.handleRemoveResponse($giftcard, res))
570
- .catch((err) => {
571
- const msg = this.getErrorMessage(err);
572
- this.showBannerError($giftcard, msg);
573
- })
574
- .finally(() => {
575
- hideLoader($loader);
576
- $row.find(giftcardChipClose).css('pointer-events', '').removeAttr('aria-disabled');
577
- });
578
- },
579
-
580
- handleRemoveResponse($giftcard, res) {
581
- if (res && res.code === OK_CODE) {
582
- const giftCardsList = Array.isArray(res.giftCards) ? res.giftCards : [];
583
- const data = { total: res.orderTotal, giftCardApplied: res.giftCardTotal };
584
- this.summaryTotal = res.orderTotal;
585
-
586
- this.renderGiftCardsFromList($giftcard, giftCardsList, data);
587
-
588
- if (res.orderTotal != null || res.giftCardTotal != null) {
589
- updateOrderSummary(data, buildSummaryEqualMap(data), true);
590
- }
591
- this.updateCtaButton($root);
592
- this.toggleBillingDescrForZero && this.toggleBillingDescrForZero($giftcard, { total: res.orderTotal });
593
- return;
594
- }
595
-
596
- const msg = (res && MESSAGE_BY_CODE[res.code]) || DEFAULT_ERROR_MESSAGE;
597
- this.showBannerError($giftcard, msg);
598
- },
599
-
600
- ensureSummaryContainer($root) {
601
- const { summary, giftcardRow } = this.el;
602
- const $row = $root.closest(giftcardRow);
603
- let $summary = $row.find(summary).first();
604
-
605
- if (!$summary.length) {
606
- $summary = $(giftcardSummary({}));
607
- $row.append($summary);
608
- }
609
-
610
- return $summary;
611
- },
612
-
613
- getPageLoader() {
614
- const $pl = $(this.el.pageLoader);
615
- if (!$pl.parent().is('body')) $pl.appendTo('body');
616
- return $pl;
617
- },
618
-
619
- showPageLoader() {
620
- const $pl = this.getPageLoader();
621
- showLoader($pl);
622
- },
623
-
624
- updateCtaButton($scope) {
625
- const { ctaSelector, btnDetails, btnText, checkoutContainer } = this.el;
626
- let $cta = $(ctaSelector);
627
- if (!$cta.length) {
628
- $cta = $scope.closest(checkoutContainer).find(ctaSelector);
629
- }
630
- if (!$cta.length) return;
631
-
632
- const $wrap = $cta.closest(btnDetails).length ? $cta.closest(btnDetails) : $cta;
633
- const $text = $wrap.find(btnText).first().length ? $wrap.find(btnText).first() : $wrap;
634
- const useGiftcard = isZeroAmount(this.summaryTotal);
635
-
636
- $text.text(useGiftcard ? this.messages.ctaGiftcardText : this.messages.ctaDefaultText);
637
- $wrap.attr('data-mode', useGiftcard ? 'giftcards' : 'card');
638
-
639
- if (useGiftcard) {
640
- $wrap.attr('type', 'button').removeAttr('form');
641
- } else {
642
- $wrap.attr('type', 'submit').attr('form', 'hopPaymentAddressPostForm');
643
- }
644
- },
645
-
646
- toggleBillingDescrForZero($scope, summaryData) {
647
- const $container = $scope.closest(this.el.checkoutContainer);
648
- const $descr = $container.find(this.el.checkoutPaymentFields);
649
- if (!$descr.length) return;
650
-
651
- const shouldHide = summaryData ? isZeroAmount(summaryData.total) : false;
652
- $descr[shouldHide ? 'hide' : 'show']();
653
- },
654
-
655
- getNumberValue($root) {
656
- const { number } = this.el;
657
- return String($root.find(number).val() || '').replace(/\D/g, '');
658
- },
659
-
660
- getPinValue($root) {
661
- const { pin } = this.el;
662
- return String($root.find(pin).val() || '').replace(/\D/g, '');
663
- },
664
-
665
- bindGiftcardCtaHandler() {
666
- const self = this;
667
-
668
- $(document).off('click.giftcard', this.el.btnEnterDetails);
669
- $(document).on('click.giftcard', this.el.btnEnterDetails, function (e) {
670
- const $btn = $(this);
671
- const mode = $btn.attr('data-mode');
672
-
673
- if (mode !== 'giftcards') return;
674
-
675
- e.preventDefault();
676
- e.stopPropagation();
677
- e.stopImmediatePropagation();
678
-
679
- const $scope = $btn.closest(self.el.checkoutContainer).find(self.el.block).first();
680
- const $root = $scope.length ? $scope : $(self.el.block).first();
681
-
682
- self.showPageLoader();
683
-
684
- payWithGiftCard()
685
- .then(({ url }) => {
686
- if (typeof url === 'string' && url) {
687
- window.location.href = url;
688
- }
689
- })
690
- .catch((error) => {
691
- if (Array.isArray(error?.giftCards)) {
692
- self.renderGiftCardsFromList($root, error.giftCards);
693
- }
694
-
695
- const numberCode = Number(error?.errorCode);
696
-
697
- if (Number.isFinite(numberCode) && PAY_MESSAGE_BY_CODE[numberCode]) {
698
- Wick.Notification.show({
699
- text: linkifyClickHere(PAY_MESSAGE_BY_CODE[numberCode]),
700
- container: '.globalMessages .container',
701
- type: 'error',
702
- });
703
- }
704
- })
705
- .finally(() => {
706
- const $pl = self.getPageLoader();
707
- hideLoader($pl);
708
- });
709
- });
710
- },
711
-
712
- showBannerError($root, message, title = '') {
713
- const { notificationRoot, giftCardInline, inlineHeader } = this.el;
714
- const $inline = $root.find(giftCardInline);
715
-
716
- $inline.find(notificationRoot).remove();
717
-
718
- const html = notificationTpl({
719
- classModifier: 'notification_error',
720
- error: true,
721
- withCloseBtn: true,
722
- title: title || undefined,
723
- text: linkifyClickHere(message)
724
- });
725
-
726
- $inline.find(inlineHeader).after(html);
727
- },
728
-
729
-
730
- hideBanner($root) {
731
- const { notification } = this.el;
732
- $root.find(notification).remove();
733
- },
734
-
735
- mapGiftToChipData($root, gift) {
736
- const $giftcard = $root.closest(this.el.block);
737
- const currency = $giftcard.data('currency') || '£';
738
- const rawAmount = Number(gift.amountToRedeem || 0);
739
- const amount = Number.isFinite(rawAmount) ? rawAmount.toFixed(2) : '0.00';
740
- return {
741
- id: gift.id,
742
- maskedNumber: String(gift.maskedNumber || ''),
743
- currency,
744
- amount,
745
- };
746
- },
747
-
748
- renderGiftCardsFromList($root, giftCards, summaryData) {
749
- const { chipList, loaderChip, chip } = this.el;
750
- const $summary = this.ensureSummaryContainer($root);
751
- const $list = $summary.find(chipList);
752
- $list.children(`${chip}:not(${loaderChip})`).remove();
753
-
754
- const html = (giftCards || [])
755
- .map((g) => this.renderChipHTML(this.mapGiftToChipData($root, g)))
756
- .join('');
757
-
758
- if (html) {
759
- $list.append(html);
760
- $summary.show();
761
- }
762
-
763
- this.updateHintVisibility($root, summaryData);
764
-
765
- if (Array.isArray(giftCards) && giftCards.length > 0) {
766
- this.setBillingLabelToCard($root);
767
- }
768
- },
769
-
770
- toggleCardDetailsForTotal($scope) {
771
- const { checkoutContainer, cardDetails, hiddenCard } = this.el;
772
- const $container = $scope.closest(checkoutContainer);
773
- const $cardDetails = $container.find(cardDetails);
774
- if (!$cardDetails.length) return;
775
-
776
- const zero = this.summaryTotal != null ? isZeroAmount(this.summaryTotal) : false;
777
- if (zero) $cardDetails.addClass(hiddenCard);
778
- },
779
-
780
- setBillingLabelToCard($scope) {
781
- const $container = $scope.closest(this.el.checkoutContainer);
782
- const $billing = $container.find(this.el.billingAddress);
783
- if (!$billing.length) return;
784
-
785
- const $label = $billing.find('[for="card-name"]');
786
- if ($label.length) {
787
- $label.text('Name on card');
788
- }
789
- },
790
-
791
- showOnlyBillingAddress($root) {
792
- const { checkoutContainer, billingAddress, altPaymentRowsAttr, hiddenCard } = this.el;
793
- const $container = $root.closest(checkoutContainer);
794
- $container.find(billingAddress).removeClass(hiddenCard);
795
- $container.find(altPaymentRowsAttr).addClass(hiddenCard);
796
- this.toggleAltPaymentInfos($root, false);
797
- },
798
-
799
- useGlobalError($root, message) {
800
- if (window.Wick && Wick.Notification && typeof Wick.Notification.show === 'function') {
801
- const text = linkifyClickHere ? linkifyClickHere(message) : String(message || '');
802
- Wick.Notification.show({
803
- text,
804
- container: '.globalMessages .container',
805
- type: 'error',
806
- });
807
- }
808
- },
809
-
810
- bindEvents() {
811
- const { number, pin, toggle, closeBtn, giftcardBtn, jsGiftcardAdd, giftcardChipClose } = this.el;
812
-
813
- $(document).off('.giftcard');
814
-
815
- const handleNumberInput = createGcNumberInputHandler({
816
- fieldSelector: this.el.field,
817
- fieldErrorClass: this.el.fieldError,
818
- errorTextSelector: this.el.errorText,
819
- ariaInvalidAttr: this.el.ariaInvalidAttr,
820
- });
821
-
822
- const onNumberBlur = (e) =>
823
- handleGcNumberBlur(e, {
824
- fieldSelector: this.el.field,
825
- errorTextSelector: this.el.errorText,
826
- errorClass: this.el.fieldError,
827
- ariaInvalidAttr: this.el.ariaInvalidAttr,
828
- numberMessage: this.messages.numberMessage,
829
- });
830
-
831
- const onPinInput = (e) =>
832
- handleGcPinInput(e, {
833
- fieldSelector: this.el.field,
834
- errorTextSelector: this.el.errorText,
835
- errorClass: this.el.fieldError,
836
- ariaInvalidAttr: this.el.ariaInvalidAttr,
837
- });
838
-
839
- const onPinBlur = (e) =>
840
- handleGcPinBlur(e, {
841
- fieldSelector: this.el.field,
842
- errorTextSelector: this.el.errorText,
843
- errorClass: this.el.fieldError,
844
- ariaInvalidAttr: this.el.ariaInvalidAttr,
845
- pinMessage: this.messages.pinMessage,
846
- });
847
-
848
-
849
- $(document)
850
- .on('input.giftcard', number, handleNumberInput)
851
- .on('keypress.giftcard', number, digitsOnlyKeypress)
852
- .on('blur.giftcard', number, onNumberBlur);
853
-
854
- $(document)
855
- .on('input.giftcard', pin, onPinInput)
856
- .on('keypress.giftcard', pin, handleGcPinKeypress)
857
- .on('blur.giftcard', pin, onPinBlur);
858
-
859
- $(document)
860
- .on('click.giftcard', toggle, this.handleToggleClick.bind(this))
861
- .on('click.giftcard', closeBtn, this.handleCloseClick.bind(this))
862
- .on('click.giftcard', giftcardBtn, this.handleFormSubmit.bind(this))
863
- .on('click.giftcard', jsGiftcardAdd, this.handleAddAnotherClick.bind(this))
864
- .on('click.giftcard', giftcardChipClose, this.handleChipCloseClick.bind(this))
865
-
866
- this.bindGiftcardCtaHandler();
867
- },
868
-
869
- init(payload = {}) {
870
- const { field, pin, $blocks } = this.el;
871
- this.bindEvents();
872
- if ($blocks && $blocks.length) {
873
- const $firstBlock = $blocks.first();
874
- if (Array.isArray(payload.giftCards) && payload.giftCards.length) {
875
- this.renderGiftCardsFromList($firstBlock, payload.giftCards);
876
- }
877
-
878
- const code = payload.errorCode;
879
-
880
- if (Number.isFinite(code) && PAY_MESSAGE_BY_CODE[code]) {
881
- this.useGlobalError($firstBlock, PAY_MESSAGE_BY_CODE[code]);
882
- }
883
- }
884
-
885
- $blocks.each((index, block) => {
886
- const $pinField = $(block).find(pin).closest(field);
887
- if ($pinField.length) {
888
- initializeInputToggle($pinField);
889
- }
890
- });
891
- }
892
- };