wickes-css2 2.102.0 → 2.103.0-RG-599-place-order-with-gift-card-spinner.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 (38) hide show
  1. package/Readme.md +1 -3
  2. package/build/css/components/checkout-payment-details-v2.css +1 -1
  3. package/build/css/pages/page_checkout_delivery-new.css +1 -1
  4. package/build/img/giftcard.svg +28 -0
  5. package/build/js/account-members.min.js +1 -1
  6. package/build/js/basket.min.js +1 -1
  7. package/build/js/bundle.min.js +1 -1
  8. package/build/js/checkout.min.js +1 -1
  9. package/build/js/emulation.min.js +66 -16
  10. package/build/js/gift-cards.min.js +1 -0
  11. package/build/js/merged-checkout.min.js +1 -1
  12. package/build/js/page/components/gift-cards.js +634 -0
  13. package/build/js/page/components/toggle-password-visibility.js +22 -0
  14. package/build/js/page/utils/gift-cards-utils.js +43 -0
  15. package/build/js/page/utils/show-hide-input.js +28 -0
  16. package/build/js/project-list.min.js +1 -1
  17. package/build/js/toggle-password-visibility.min.js +1 -0
  18. package/package.json +2 -2
  19. package/src/components/checkout-payment-details-v2.hbs +2 -1
  20. package/src/components/gift-cards-hint.hbs +9 -0
  21. package/src/components/gift-cards.hbs +89 -0
  22. package/src/components/giftcard-chip.hbs +23 -0
  23. package/src/elements/form-row.hbs +1 -1
  24. package/src/elements/input.hbs +31 -2
  25. package/src/img/giftcard.svg +28 -0
  26. package/src/js/emulation/checkout-data.js +35 -0
  27. package/src/js/emulation/checkout-payment-details.js +23 -14
  28. package/src/js/emulation/forms.js +7 -2
  29. package/src/js/page/components/gift-cards.js +634 -0
  30. package/src/js/page/components/toggle-password-visibility.js +22 -0
  31. package/src/js/page/utils/gift-cards-utils.js +43 -0
  32. package/src/js/page/utils/show-hide-input.js +28 -0
  33. package/src/page_my-account_change-password.html +1 -0
  34. package/src/page_payment-details-with-gift-card.html +2 -1
  35. package/src/scss/components/_gift-cards.scss +357 -0
  36. package/src/scss/components/checkout-payment-details-v2.scss +2 -0
  37. package/src/scss/pages/page_checkout_delivery-new.scss +19 -0
  38. package/src/js/components/toggle-password-visibility.js +0 -58
@@ -0,0 +1,634 @@
1
+ import { initializeInputToggle } from "../utils/show-hide-input";
2
+ import { updateOrderSummary } from './order-summary';
3
+ import { showLoader, hideLoader } from "../utils/loader";
4
+ import { formatGc16, buildSummaryEqualMap, buildChipData, buildHintContext } from "../utils/gift-cards-utils";
5
+ const Handlebars = require('hbsfy/runtime');
6
+
7
+ Handlebars.registerPartial('info-icon', require("../../../components/info-icon.hbs"));
8
+ Handlebars.registerPartial('loader', require("../../../elements/loader.hbs"));
9
+
10
+ const giftCardsHint = require("../../../components/gift-cards-hint.hbs");
11
+ const giftCardChip = require("../../../components/giftcard-chip.hbs");
12
+ const renderLoader = require("../../../elements/loader.hbs");
13
+
14
+ var Wick = window.Wick || {};
15
+
16
+ Wick.GiftCard = {
17
+ el: {
18
+ $blocks: $('.giftcard'),
19
+ block: '.giftcard',
20
+ toggle: '#giftcard-toggle',
21
+ panel: '#giftcard-inline',
22
+ hint: '.giftcard-hint',
23
+ closeBtn: '.giftcard-inline__close',
24
+ form: '.giftcard-inline__form',
25
+ number: 'input[name="giftcard-number"]',
26
+ pin: 'input[name="giftcard-pin"]',
27
+ note: '.giftcard-note',
28
+ field: '.giftcard__field',
29
+ errorText: '.giftcard__error-text',
30
+ fieldError: 'giftcard-field--error',
31
+ showToggle: '.toggle-show',
32
+ loader: '.giftcard__container .loader-wrapper',
33
+ wrapper: '.giftcard__wrapper',
34
+ success: '#giftcard-applied',
35
+ container: '.giftcard__container',
36
+ paymentForm: '.checkout-payment-details__payment-method',
37
+ billieField: '.form-row__field.form-row__field-billie',
38
+ clearpayField: '.form-row__field.form-row__field-clearpay',
39
+ appleField: '.form-row__field.form-row__field-apple',
40
+ googleField: '.form-row__field.form-row__field-google',
41
+ paypalField: '.form-row__field.form-row__field-paypal',
42
+ summaryHint: '.giftcard-summary__hint',
43
+ chipList: '.giftcard-chip-list',
44
+ summary: '.giftcard-summary',
45
+ chip: '.giftcard-chip',
46
+ giftcardRow: '.giftcard-row',
47
+ checkoutContainer: '.checkout-payment-details',
48
+ formRow: '.form-row',
49
+ iconInfo: '.icon-info-component',
50
+ toggleIcon: 'svg, i',
51
+ iconEye: 'fa-eye',
52
+ iconEyeSlash: 'fa-eye-slash',
53
+ iconSvgEyeSlash: 'eye-slash',
54
+ passwordToggleEvent: 'input.passwordToggle',
55
+ ariaInvalidAttr: 'aria-invalid',
56
+ typeAttr: 'type',
57
+ dataIconAttr: 'data-icon',
58
+ svg: 'svg',
59
+ expandedAttr: 'aria-expanded',
60
+ giftcardBtn: '.giftcard__btn',
61
+ jsGiftcardAdd: '.js-giftcard-add',
62
+ giftcardChipClose: '.giftcard-chip__close',
63
+ body: 'body',
64
+ loaderChip: '.loader-wrapper',
65
+ chipListLoader: '.giftcard-chip-list > .loader-wrapper',
66
+ ctaSelector: '.billing-address .btn-enter-details .btn__text',
67
+ btnDetails: '.btn-enter-details',
68
+ btnText: '.btn__text',
69
+ pageLoader: '.loader-wrapper.page-loader',
70
+ btnEnterDetails: '.billing-address .btn-enter-details',
71
+ checkoutPaymentFields: '.billing-address .checkout-payment-details__descr',
72
+ iframe: '#hopIframe',
73
+ payBtnSelector: '#btnSubmit,input[type="submit"].submit-PayNow,.submitButton.btn.primary.submit-PayNow',
74
+ },
75
+
76
+ messages: {
77
+ numberMessage: 'Gift Card should consist of 16 digits',
78
+ pinMessage: 'Gift Card PIN should consist of 8 digits',
79
+ ctaDefaultText: 'Enter card details',
80
+ ctaGiftcardText: 'Pay with Gift Card',
81
+ },
82
+
83
+ maxChips: 3,
84
+ lastChipData: null,
85
+ successTimer: null,
86
+
87
+ showError($input, message) {
88
+ const { field, errorText, fieldError, ariaInvalidAttr } = this.el;
89
+ const $field = $input.closest(field);
90
+ $field.addClass(fieldError);
91
+ $input.attr(ariaInvalidAttr, 'true');
92
+
93
+ let $err = $field.find(errorText);
94
+ if (!$err.length) {
95
+ $err = $('<div class="giftcard__error-text" />').appendTo($field);
96
+ }
97
+ $err.text(message);
98
+ },
99
+
100
+ clearError($input) {
101
+ const { field, errorText, fieldError, ariaInvalidAttr } = this.el;
102
+ const $field = $input.closest(field);
103
+ $field.removeClass(fieldError);
104
+ $input.removeAttr(ariaInvalidAttr);
105
+ $field.find(errorText).remove();
106
+ },
107
+
108
+ resetPinToggle($root) {
109
+ const {
110
+ pin,
111
+ field,
112
+ showToggle,
113
+ toggleIcon,
114
+ iconEye,
115
+ iconEyeSlash,
116
+ iconSvgEyeSlash,
117
+ passwordToggleEvent,
118
+ typeAttr,
119
+ dataIconAttr,
120
+ svg
121
+ } = this.el;
122
+
123
+ const $pinField = $root.find(pin).closest(field);
124
+ const $pinInput = $pinField.find(pin).first();
125
+
126
+ $pinInput.attr(typeAttr, 'password');
127
+
128
+ const $toggle = $pinField.find(showToggle).first();
129
+ const $icon = $toggle.find(toggleIcon).first();
130
+
131
+ if ($icon.length) {
132
+ $icon.removeClass(`${iconEye} ${iconEyeSlash}`).addClass(iconEyeSlash);
133
+ if ($icon.is(svg) && $icon.attr(dataIconAttr)) {
134
+ $icon.attr(dataIconAttr, iconSvgEyeSlash);
135
+ }
136
+ }
137
+
138
+ const hasValue = ($pinInput.val() || '').length > 0;
139
+ $toggle.toggle(hasValue);
140
+
141
+ $pinInput.trigger(passwordToggleEvent);
142
+ },
143
+
144
+ resetForm($root) {
145
+ const { number, pin, note } = this.el;
146
+ const $num = $root.find(number);
147
+ const $pinInput = $root.find(pin);
148
+
149
+ $num.val('');
150
+ $pinInput.val('');
151
+ this.clearError($num);
152
+ this.clearError($pinInput);
153
+ $root.find(note).remove();
154
+
155
+ this.resetPinToggle($root);
156
+ },
157
+
158
+ open($root) {
159
+ const { toggle, panel, hint, pin, expandedAttr, passwordToggleEvent } = this.el;
160
+ $root.show();
161
+
162
+ $root.find(panel).prop('hidden', false);
163
+ $root.find(toggle).attr(expandedAttr, 'true').hide();
164
+ $root.find(hint).hide();
165
+ $root.find(pin).trigger(passwordToggleEvent);
166
+ },
167
+
168
+ close($root) {
169
+ const { toggle, panel, loader, expandedAttr } = this.el;
170
+ const $toggle = $root.find(toggle);
171
+ const $panel = $root.find(panel);
172
+ const $loader = $root.find(loader);
173
+
174
+ showLoader($loader);
175
+
176
+ setTimeout(() => {
177
+ hideLoader($loader);
178
+
179
+ $panel.prop('hidden', true);
180
+ $toggle.attr(expandedAttr, 'false').show().trigger('focus');
181
+ this.updateHintVisibility($root);
182
+ }, 1000);
183
+ },
184
+
185
+ showSubmitSpinner($root) {
186
+ const { loader, panel, toggle, hint, expandedAttr } = this.el;
187
+ const $loader = $root.find(loader);
188
+
189
+ showLoader($loader);
190
+
191
+ setTimeout(() => {
192
+ hideLoader($loader);
193
+
194
+ $root.find(panel).prop('hidden', true);
195
+ $root.find(toggle).attr(expandedAttr, 'false').show().trigger('focus');
196
+ $root.find(hint).show();
197
+ this.showSuccess($root);
198
+ }, 1000);
199
+ },
200
+
201
+ handleNumberInput(e) {
202
+ const { field, fieldError } = this.el;
203
+ const input = e.currentTarget;
204
+ const $input = $(input);
205
+
206
+ const atEnd = input.selectionStart === input.value.length;
207
+ const hadErr = $input.closest(field).hasClass(fieldError);
208
+
209
+ input.value = formatGc16(input.value);
210
+ if (hadErr) this.clearError($input);
211
+ if (atEnd) input.setSelectionRange(input.value.length, input.value.length);
212
+ },
213
+
214
+ handleNumberKeypress(e) {
215
+ if (!/\d/.test(String.fromCharCode(e.which || e.keyCode))) e.preventDefault();
216
+ },
217
+
218
+ handleNumberBlur(e) {
219
+ const $input = $(e.currentTarget);
220
+ const len = String($input.val() || '').replace(/\D/g, '').length;
221
+ this.clearError($input);
222
+ if (len < 16) this.showError($input, this.messages.numberMessage);
223
+ },
224
+
225
+ handlePinInput(e) {
226
+ const { field, fieldError } = this.el;
227
+ const input = e.currentTarget;
228
+ const $input = $(input);
229
+
230
+ const hadErr = $input.closest(field).hasClass(fieldError);
231
+ input.value = String(input.value || '').replace(/\D/g, '').slice(0, 8);
232
+ if (hadErr) this.clearError($input);
233
+ },
234
+
235
+ handlePinKeypress(e) {
236
+ if (!/\d/.test(String.fromCharCode(e.which || e.keyCode))) e.preventDefault();
237
+ },
238
+
239
+ handlePinBlur(e) {
240
+ const $input = $(e.currentTarget);
241
+ const length = String($input.val() || '').replace(/\D/g, '').length;
242
+ this.clearError($input);
243
+ if (length < 8) {
244
+ this.showError($input, this.messages.pinMessage);
245
+ }
246
+ },
247
+
248
+ handleToggleClick(e) {
249
+ e.preventDefault();
250
+ this.open($(e.currentTarget).closest(this.el.$blocks));
251
+ },
252
+
253
+ handleCloseClick(e) {
254
+ e.preventDefault();
255
+ const $root = $(e.currentTarget).closest(this.el.$blocks);
256
+ this.resetForm($root);
257
+ this.close($root);
258
+ },
259
+
260
+ finalizeSuccess($root, $success) {
261
+ let { panel, toggle, hint, expandedAttr, chipList } = this.el;
262
+
263
+ if ($success && $success.length) {
264
+ $success.attr('hidden', 'hidden').removeClass('fade show').off('transitionend');
265
+ }
266
+
267
+ this.resetForm($root);
268
+ $root.find(panel).prop('hidden', true);
269
+ $root.find(toggle).attr(expandedAttr, 'false').show();
270
+ $root.find(hint).show();
271
+
272
+ if (this.lastChipData) {
273
+ const $summary = this.ensureSummaryContainer($root);
274
+ const html = this.renderChipHTML(this.lastChipData);
275
+ $summary.find(chipList).append(html);
276
+ $summary.show();
277
+ this.lastChipData = null;
278
+ this.updateCtaButton($root);
279
+ }
280
+
281
+ const data = Wick.CheckoutData.successGiftCardData;
282
+ updateOrderSummary(
283
+ data,
284
+ this.getEqualMapForGiftCardUpdate(data),
285
+ true,
286
+ );
287
+
288
+ this.toggleBillingDescrForZero($root, data);
289
+ this.updateCtaButton($root, data);
290
+ this.updateHintVisibility($root, data);
291
+ },
292
+
293
+
294
+ showSuccess($root) {
295
+ const { success} = this.el;
296
+
297
+ if (this.successTimer) {
298
+ clearTimeout(this.successTimer);
299
+ this.successTimer = null;
300
+ }
301
+
302
+ $root.hide();
303
+ const $success = $(success);
304
+ $success.removeAttr('hidden').addClass('fade');
305
+ $success[0] && $success[0].offsetWidth;
306
+ $success.addClass('show');
307
+
308
+ this.successTimer = setTimeout(() => {
309
+ $success.removeClass('show');
310
+ const handler = () => this.finalizeSuccess($root, $success);
311
+
312
+ $success.on('transitionend', handler);
313
+ setTimeout(handler, 200)
314
+ }, 3000);
315
+ },
316
+
317
+ isValid($root) {
318
+ const {number, pin} = this.el;
319
+ const $numInput = $root.find(number);
320
+ const $pinInput = $root.find(pin);
321
+ const numField = String($numInput.val() || '').replace(/\D/g, '');
322
+ const pinField = String($pinInput.val() || '').replace(/\D/g, '');
323
+ let valid = true;
324
+
325
+ if (numField.length !== 16) {
326
+ this.showError($numInput, this.messages.numberMessage);
327
+ valid = false;
328
+ }
329
+
330
+ if (pinField.length !== 8) {
331
+ this.showError($pinInput, this.messages.pinMessage);
332
+ valid = false;
333
+ }
334
+
335
+ return valid;
336
+ },
337
+
338
+ handleFormSubmit(e) {
339
+ const { number, block } = this.el;
340
+ e.preventDefault();
341
+ const $root = $(e.currentTarget).closest(block);
342
+
343
+ const $num = $root.find(number);
344
+ $num.val(formatGc16($num.val()));
345
+
346
+ if (!this.isValid($root)) return;
347
+
348
+ this.lastChipData = buildChipData($root, number);
349
+ this.resetForm($root);
350
+ this.showSubmitSpinner($root);
351
+ },
352
+
353
+ updateHintVisibility($root, summaryData) {
354
+ const {
355
+ chipList,
356
+ giftcardRow,
357
+ hint,
358
+ panel,
359
+ toggle,
360
+ iconInfo,
361
+ expandedAttr,
362
+ summaryHint,
363
+ chip,
364
+ block,
365
+ body
366
+ } = this.el;
367
+ const $row = $root.closest(giftcardRow);
368
+ const $giftcard = $row.find(block).first();
369
+ const count = $row.find(`${chipList} ${chip}`).length;
370
+ const limit= this.maxChips || 3;
371
+
372
+ this.toggleAltPayments($giftcard, count === 0);
373
+
374
+ const $summary = this.ensureSummaryContainer($giftcard);
375
+
376
+ if (count === 0) {
377
+ $summary.hide();
378
+ $giftcard.show();
379
+ this.resetForm($giftcard);
380
+ $giftcard.find(panel).prop('hidden', true);
381
+ $giftcard.find(toggle).attr(expandedAttr, 'false').show();
382
+ $giftcard.find(hint).show();
383
+ this.updateCtaButton($giftcard);
384
+ return;
385
+ }
386
+
387
+ $summary.show();
388
+ $giftcard.hide();
389
+ $giftcard.find(hint).hide();
390
+
391
+ const ctx= buildHintContext(count, limit);
392
+ const html = giftCardsHint(ctx);
393
+ const $old = $summary.find(summaryHint).first();
394
+ const $new = $(html);
395
+
396
+ if ($old.length) {
397
+ $old.replaceWith($new);
398
+ } else {
399
+ $summary.append($new);
400
+ }
401
+
402
+ const shouldHideHint = summaryData ? this.isZeroAmount(summaryData.total) : false;
403
+ $new.toggle(!shouldHideHint);
404
+
405
+
406
+ if ($.fn.tooltip) {
407
+ $new.find(iconInfo).tooltip({ container: body });
408
+ }
409
+ },
410
+
411
+ renderChipHTML({ id, last5, currency, amount }) {
412
+ return giftCardChip({ id, last5, currency, amount });
413
+ },
414
+
415
+ toggleAltPayments($root, show) {
416
+ const {
417
+ paymentForm,
418
+ billieField,
419
+ clearpayField,
420
+ appleField,
421
+ googleField,
422
+ paypalField,
423
+ checkoutContainer,
424
+ formRow,
425
+ } = this.el;
426
+
427
+ const $paymentField = $root.closest(checkoutContainer).find(paymentForm);
428
+
429
+ const paymentSelectors = [
430
+ billieField,
431
+ clearpayField,
432
+ appleField,
433
+ googleField,
434
+ paypalField,
435
+ ];
436
+
437
+ paymentSelectors.forEach((sel) => {
438
+ const $row = $paymentField.find(sel).closest(formRow);
439
+ if ($row.length) {
440
+ $row[show ? 'show' : 'hide']();
441
+ }
442
+ });
443
+ },
444
+
445
+ handleAddAnotherClick(e) {
446
+ e.preventDefault();
447
+ const { giftcardRow, chipList, chip, block, number, summaryHint } = this.el;
448
+
449
+ const $row = $(e.currentTarget).closest(giftcardRow);
450
+ const count = $row.find(`${chipList} ${chip}`).length;
451
+ if (count >= this.maxChips) return;
452
+
453
+ const $giftcard = $row.find(block).first();
454
+ this.resetForm($giftcard);
455
+ this.open($giftcard);
456
+
457
+ $row.find(summaryHint).hide();
458
+
459
+ setTimeout(() => {
460
+ $giftcard.find(number).trigger('focus');
461
+ }, 0);
462
+ },
463
+
464
+ handleChipCloseClick(e) {
465
+ e.preventDefault();
466
+ const {
467
+ chip, giftcardRow, block,
468
+ giftcardChipClose, chipListLoader
469
+ } = this.el;
470
+
471
+ const $clickedChip = $(e.currentTarget).closest(chip);
472
+ const $row= $clickedChip.closest(giftcardRow);
473
+ const $giftcard = $row.find(block).first();
474
+ const $summary = this.ensureSummaryContainer($giftcard);
475
+ const $listLoader = $summary.find(chipListLoader);
476
+
477
+ showLoader($listLoader);
478
+ $row.find(giftcardChipClose)
479
+ .css('pointer-events', 'none')
480
+ .attr('aria-disabled', 'true');
481
+
482
+ setTimeout(() => {
483
+ $clickedChip.remove();
484
+ hideLoader($listLoader);
485
+ $row.find(giftcardChipClose)
486
+ .css('pointer-events', '')
487
+ .removeAttr('aria-disabled');
488
+
489
+ this.updateHintVisibility($giftcard);
490
+ }, 1000);
491
+ },
492
+
493
+ getEqualMapForGiftCardUpdate(data) {
494
+ return buildSummaryEqualMap(data);
495
+ },
496
+
497
+ ensureSummaryContainer($root) {
498
+ const {
499
+ chipList, summary, giftcardRow, loaderChip
500
+ } = this.el;
501
+ const $row = $root.closest(giftcardRow);
502
+ let $summary = $row.find(summary).first();
503
+
504
+ if (!$summary.length) {
505
+ $summary = $(`
506
+ <div class="giftcard-summary" style="display:none">
507
+ <div class="giftcard-chip-list"></div>
508
+ <p class="giftcard-summary__hint"></p>
509
+ </div>
510
+ `);
511
+ $row.append($summary);
512
+ }
513
+
514
+ const $list = $summary.find(chipList);
515
+ if (!$list.children(loaderChip).length) {
516
+ const html = renderLoader({ hidden: true });
517
+ $list.append(html);
518
+ }
519
+
520
+ return $summary;
521
+ },
522
+
523
+ updateCtaButton($scope, summaryData) {
524
+ const { chip, ctaSelector, btnDetails, btnText, giftcardRow } = this.el;
525
+ const hasChips = $scope.closest(giftcardRow).find(chip).length > 0;
526
+ const $cta = $(ctaSelector).closest(btnDetails);
527
+
528
+ if (!$cta.length) return;
529
+
530
+ const forceGiftcard = summaryData ? this.isZeroAmount(summaryData.total) : false;
531
+ const useGiftcard = forceGiftcard || hasChips;
532
+ $cta.find(btnText).text(useGiftcard ? this.messages.ctaGiftcardText : this.messages.ctaDefaultText);
533
+ $cta.attr('data-mode', useGiftcard ? 'giftcards' : 'card');
534
+ },
535
+
536
+ isZeroAmount(val) {
537
+ const num = Number(String(val ?? '').replace(/[^\d.]/g, ''));
538
+ return Number.isFinite(num) && num === 0;
539
+ },
540
+
541
+ toggleBillingDescrForZero($scope, summaryData) {
542
+ const $container = $scope.closest(this.el.checkoutContainer);
543
+ const $descr = $container.find(this.el.checkoutPaymentFields);
544
+ if (!$descr.length) return;
545
+
546
+ const shouldHide = summaryData ? this.isZeroAmount(summaryData.total) : false;
547
+ $descr[shouldHide ? 'hide' : 'show']();
548
+ },
549
+
550
+ getPageLoader() {
551
+ const $pageLoader = $(this.el.pageLoader);
552
+ if (!$pageLoader.parent().is('body')) $pageLoader.appendTo('body');
553
+ return $pageLoader;
554
+ },
555
+
556
+ showPageLoader() {
557
+ const $pageLoader = this.getPageLoader();
558
+ showLoader($pageLoader);
559
+ },
560
+
561
+
562
+ bindIframePaypageLoader() {
563
+ const { iframe, payBtnSelector } = this.el;
564
+ const self = this;
565
+ $(iframe).off('load.giftcard').on('load.giftcard', (ev) => {
566
+ const iframeEl = ev.currentTarget;
567
+
568
+ let doc;
569
+ try {
570
+ doc = iframeEl.contentDocument || iframeEl.contentWindow?.document;
571
+ } catch (e) {
572
+ return;
573
+ }
574
+ if (!doc) return;
575
+
576
+ const $doc = $(doc);
577
+ $doc.off('.giftcard');
578
+
579
+ $doc
580
+ .on('click.giftcard', payBtnSelector, () => self.showPageLoader())
581
+ .on('submit.giftcard', 'form', () => self.showPageLoader());
582
+ });
583
+ },
584
+
585
+ bindCtaGiftcardLoader() {
586
+ const self = this;
587
+ $(document).on('click.giftcard', this.el.btnEnterDetails, function () {
588
+ if ($(this).attr('data-mode') === 'giftcards') {
589
+ self.showPageLoader();
590
+ }
591
+ });
592
+ },
593
+
594
+ bindEvents() {
595
+ const { number, pin, toggle, closeBtn, giftcardBtn, jsGiftcardAdd, giftcardChipClose } = this.el;
596
+
597
+ $(document).off('.giftcard');
598
+
599
+ $(document)
600
+ .on('input.giftcard', number, this.handleNumberInput.bind(this))
601
+ .on('keypress.giftcard', number, this.handleNumberKeypress.bind(this))
602
+ .on('blur.giftcard', number, this.handleNumberBlur.bind(this));
603
+
604
+ $(document)
605
+ .on('input.giftcard', pin, this.handlePinInput.bind(this))
606
+ .on('keypress.giftcard', pin, this.handlePinKeypress.bind(this))
607
+ .on('blur.giftcard', pin, this.handlePinBlur.bind(this));
608
+
609
+ $(document)
610
+ .on('click.giftcard', toggle, this.handleToggleClick.bind(this))
611
+ .on('click.giftcard', closeBtn, this.handleCloseClick.bind(this))
612
+ .on('click.giftcard', giftcardBtn, this.handleFormSubmit.bind(this))
613
+ .on('click.giftcard', jsGiftcardAdd, this.handleAddAnotherClick.bind(this))
614
+ .on('click.giftcard', giftcardChipClose, this.handleChipCloseClick.bind(this))
615
+
616
+ this.bindIframePaypageLoader();
617
+ this.bindCtaGiftcardLoader();
618
+ },
619
+
620
+ init() {
621
+ const { field, pin, $blocks } = this.el;
622
+ this.bindEvents();
623
+ $blocks.each((index, block) => {
624
+ const $pinField = $(block).find(pin).closest(field);
625
+ if ($pinField.length) {
626
+ initializeInputToggle($pinField);
627
+ }
628
+ });
629
+ }
630
+ };
631
+
632
+ $(function () {
633
+ Wick.GiftCard.init();
634
+ });
@@ -0,0 +1,22 @@
1
+ import { initializeInputToggle } from "../utils/show-hide-input";
2
+
3
+ var Wick = window.Wick || {};
4
+
5
+ Wick.TogglePasswordVisibility = {
6
+ el: {
7
+ $containers: $('.form-row[data-show-content] .input-wrap'),
8
+ },
9
+
10
+ init() {
11
+ if (!this.el.$containers.length) {
12
+ return;
13
+ }
14
+ this.el.$containers.each(function () {
15
+ initializeInputToggle($(this));
16
+ });
17
+ },
18
+ };
19
+
20
+ $(document).ready(function () {
21
+ Wick.TogglePasswordVisibility.init();
22
+ });
@@ -0,0 +1,43 @@
1
+ const SUMMARY_SELECTORS = {
2
+ subTotal: { item: '.checkout-widget__item-bold', value: '.checkout-widget__item-value', title: 'Items subtotal:' },
3
+ vat: { item: '.checkout-widget__item-vat', value: '.checkout-widget__item-value', title: 'VAT:' },
4
+ clickAndCollectCost: { item: '.checkout-widget__item-cc', value: '.checkout-widget__item-value', title: 'Click & Collect:' },
5
+ deliveryCost: { item: '.checkout-widget__item-delivery', value: '.checkout-widget__item-value', title: 'Delivery:' },
6
+ charityPrice: { item: '.checkout-widget__item-charity', value: '.checkout-widget__item-value', title: 'Charity donation:' },
7
+ discountTotal: { item: '.checkout-widget__details-discount', value: '.checkout-widget__detail-value' },
8
+ total: { item: '.checkout-widget__total', value: '.checkout-widget__total-value' },
9
+ giftCardApplied: { item: '.checkout-widget__gift-card', value: '.checkout-widget__total-value', title: 'Gift Card:' },
10
+ };
11
+
12
+ export function formatGc16(raw) {
13
+ const digits = String(raw || '').replace(/\D/g, '').slice(0, 16);
14
+ return digits.replace(/(\d{4})(?=\d)/g, '$1-');
15
+ }
16
+
17
+ export function buildHintContext(count, limit) {
18
+ const max = count >= limit;
19
+ return {
20
+ canAdd: !max,
21
+ max,
22
+ hintClass: `giftcard-summary__hint${max ? ' giftcard-summary__hint--max' : ''}`,
23
+ };
24
+ }
25
+
26
+ export function buildChipData($root, numberSelector) {
27
+ const digits = String($root.find(numberSelector).val() || '').replace(/\D/g, '');
28
+ const last5 = digits.slice(-5);
29
+ const id= `giftcard_${Date.now()}`;
30
+ const $giftcard = $root.closest('.giftcard');
31
+ const currency = $giftcard.data('currency') || '£';
32
+ const amount= ($giftcard.data('amount') != null ? $giftcard.data('amount') : '100.00');
33
+ return { id, last5, currency, amount };
34
+ }
35
+
36
+ export function buildSummaryEqualMap(data) {
37
+ return Object.entries(SUMMARY_SELECTORS).map(([key, d]) => ({
38
+ item: d.item,
39
+ itemValue: d.value,
40
+ dataValue: data[key],
41
+ ...(d.title ? { title: d.title } : {}),
42
+ }));
43
+ }