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