@foxy.io/elements 1.14.0-beta.5 → 1.14.0-beta.9

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 (90) hide show
  1. package/dist/cdn/foxy-access-recovery-form.js +1 -1
  2. package/dist/cdn/foxy-address-card.js +1 -1
  3. package/dist/cdn/foxy-address-form.js +1 -1
  4. package/dist/cdn/foxy-applied-tax-card.js +1 -1
  5. package/dist/cdn/foxy-attribute-card.js +1 -1
  6. package/dist/cdn/foxy-attribute-form.js +1 -1
  7. package/dist/cdn/foxy-cancellation-form.js +1 -1
  8. package/dist/cdn/foxy-collection-page.js +1 -1
  9. package/dist/cdn/foxy-collection-pages.js +1 -1
  10. package/dist/cdn/foxy-custom-field-card.js +1 -1
  11. package/dist/cdn/foxy-custom-field-form.js +1 -1
  12. package/dist/cdn/foxy-customer-card.js +1 -1
  13. package/dist/cdn/foxy-customer-form.js +1 -1
  14. package/dist/cdn/foxy-customer-portal-settings.js +17 -17
  15. package/dist/cdn/foxy-customer-portal.js +2 -2
  16. package/dist/cdn/foxy-customer.js +4 -4
  17. package/dist/cdn/foxy-customers-table.js +1 -1
  18. package/dist/cdn/foxy-discount-card.js +1 -1
  19. package/dist/cdn/foxy-donation.js +1 -1
  20. package/dist/cdn/foxy-email-template-form.js +1 -1
  21. package/dist/cdn/foxy-error-entry-card.js +1 -1
  22. package/dist/cdn/foxy-form-dialog.js +1 -1
  23. package/dist/cdn/foxy-i18n.js +1 -1
  24. package/dist/cdn/foxy-items-form.js +1 -1
  25. package/dist/cdn/foxy-payment-card.js +1 -1
  26. package/dist/cdn/foxy-payment-method-card.js +1 -1
  27. package/dist/cdn/foxy-query-builder.js +1 -1
  28. package/dist/cdn/foxy-sign-in-form.js +1 -1
  29. package/dist/cdn/foxy-spinner.js +1 -1
  30. package/dist/cdn/foxy-subscription-card.js +1 -1
  31. package/dist/cdn/foxy-subscription-form.js +3 -3
  32. package/dist/cdn/foxy-subscriptions-table.js +1 -1
  33. package/dist/cdn/foxy-table.js +1 -1
  34. package/dist/cdn/foxy-tax-card.js +1 -1
  35. package/dist/cdn/foxy-tax-form.js +1 -1
  36. package/dist/cdn/foxy-template-config-form.js +1 -14
  37. package/dist/cdn/foxy-template-form.js +1 -1
  38. package/dist/cdn/foxy-transaction-card.js +1 -1
  39. package/dist/cdn/foxy-transactions-table.js +1 -1
  40. package/dist/cdn/foxy-user-form.js +1 -1
  41. package/dist/cdn/foxy-users-table.js +1 -1
  42. package/dist/cdn/{shared-10bdb6b9.js → shared-00070cc4.js} +1 -1
  43. package/dist/cdn/shared-007c4e34.js +1 -0
  44. package/dist/cdn/shared-07134f93.js +14 -0
  45. package/dist/cdn/{shared-782bf922.js → shared-0f9809ab.js} +1 -1
  46. package/dist/cdn/{shared-166c44ae.js → shared-31d03530.js} +7 -7
  47. package/dist/cdn/{shared-4a52d9b5.js → shared-4ba926ca.js} +1 -1
  48. package/dist/cdn/{shared-87190eae.js → shared-5d94bacb.js} +1 -1
  49. package/dist/cdn/{shared-1469c1c4.js → shared-7007dedb.js} +1 -1
  50. package/dist/cdn/{shared-396320f9.js → shared-a3d2c48e.js} +1 -1
  51. package/dist/cdn/{shared-fb90e05c.js → shared-b24377bf.js} +1 -1
  52. package/dist/cdn/{shared-2174bcd4.js → shared-c5ae5d33.js} +1 -1
  53. package/dist/cdn/{shared-9d779f46.js → shared-ca7c3b9a.js} +1 -1
  54. package/dist/cdn/shared-d01035c5.js +1 -0
  55. package/dist/cdn/{shared-614e1a4e.js → shared-d05c93a5.js} +1 -1
  56. package/dist/cdn/{shared-7a39a41f.js → shared-da787055.js} +1 -1
  57. package/dist/cdn/{shared-3d868b17.js → shared-daf6b763.js} +1 -1
  58. package/dist/cdn/shared-fe8a7aa2.js +1 -0
  59. package/dist/cdn/translations/shared/en.json +32 -1
  60. package/dist/elements/private/Checkbox/Checkbox.d.ts +3 -1
  61. package/dist/elements/private/Checkbox/Checkbox.js +45 -12
  62. package/dist/elements/private/Checkbox/Checkbox.js.map +1 -1
  63. package/dist/elements/private/Choice/Choice.js +7 -5
  64. package/dist/elements/private/Choice/Choice.js.map +1 -1
  65. package/dist/elements/public/EmailTemplateForm/EmailTemplateForm.d.ts +24 -2
  66. package/dist/elements/public/EmailTemplateForm/EmailTemplateForm.js +89 -50
  67. package/dist/elements/public/EmailTemplateForm/EmailTemplateForm.js.map +1 -1
  68. package/dist/elements/public/EmailTemplateForm/types.d.ts +14 -0
  69. package/dist/elements/public/EmailTemplateForm/types.js.map +1 -1
  70. package/dist/elements/public/TemplateConfigForm/CountriesList.js +11 -2
  71. package/dist/elements/public/TemplateConfigForm/CountriesList.js.map +1 -1
  72. package/dist/elements/public/TemplateConfigForm/CountryCard.d.ts +2 -0
  73. package/dist/elements/public/TemplateConfigForm/CountryCard.js +36 -4
  74. package/dist/elements/public/TemplateConfigForm/CountryCard.js.map +1 -1
  75. package/dist/elements/public/TemplateConfigForm/TemplateConfigForm.d.ts +60 -1
  76. package/dist/elements/public/TemplateConfigForm/TemplateConfigForm.js +664 -43
  77. package/dist/elements/public/TemplateConfigForm/TemplateConfigForm.js.map +1 -1
  78. package/dist/elements/public/TemplateConfigForm/types.d.ts +34 -0
  79. package/dist/elements/public/TemplateConfigForm/types.js.map +1 -1
  80. package/dist/elements/public/TemplateForm/TemplateForm.d.ts +23 -1
  81. package/dist/elements/public/TemplateForm/TemplateForm.js +92 -52
  82. package/dist/elements/public/TemplateForm/TemplateForm.js.map +1 -1
  83. package/dist/elements/public/TemplateForm/types.d.ts +14 -0
  84. package/dist/elements/public/TemplateForm/types.js.map +1 -1
  85. package/dist/mixins/themeable.js +43 -8
  86. package/dist/mixins/themeable.js.map +1 -1
  87. package/package.json +1 -1
  88. package/dist/cdn/shared-1b7e65e4.js +0 -1
  89. package/dist/cdn/shared-75ce6e43.js +0 -1
  90. package/dist/cdn/shared-d94ffc2b.js +0 -1
@@ -1,3 +1,4 @@
1
+ import * as logos from "../PaymentMethodCard/logos.js";
1
2
  import { ChoiceChangeEvent } from "../../private/events.js";
2
3
  import { ScopedElementsMixin } from '@open-wc/scoped-elements';
3
4
  import { html } from 'lit-html';
@@ -15,10 +16,64 @@ import { getDefaultJSON } from "./defaults.js";
15
16
  import { live } from 'lit-html/directives/live';
16
17
  const NS = 'template-config-form';
17
18
  const Base = ScopedElementsMixin(ResponsiveMixin(ConfigurableMixin(ThemeableMixin(TranslatableMixin(NucleonElement, NS)))));
19
+ /**
20
+ * Form element for creating or editing template configs (`fx:template_config`).
21
+ *
22
+ * @slot cart-type:before
23
+ * @slot cart-type:after
24
+ *
25
+ * @slot foxycomplete:before
26
+ * @slot foxycomplete:after
27
+ *
28
+ * @slot locations:before
29
+ * @slot locations:after
30
+ *
31
+ * @slot hidden-fields:before
32
+ * @slot hidden-fields:after
33
+ *
34
+ * @slot cards:before
35
+ * @slot cards:after
36
+ *
37
+ * @slot checkout-type:before
38
+ * @slot checkout-type:after
39
+ *
40
+ * @slot consent:before
41
+ * @slot consent:after
42
+ *
43
+ * @slot fields:before
44
+ * @slot fields:after
45
+ *
46
+ * @slot google-analytics:before
47
+ * @slot google-analytics:after
48
+ *
49
+ * @slot segment-io:before
50
+ * @slot segment-io:after
51
+ *
52
+ * @slot troubleshooting:before
53
+ * @slot troubleshooting:after
54
+ *
55
+ * @slot custom-config:before
56
+ * @slot custom-config:after
57
+ *
58
+ * @slot header:before
59
+ * @slot header:after
60
+ *
61
+ * @slot custom-fields:before
62
+ * @slot custom-fields:after
63
+ *
64
+ * @slot footer:before
65
+ * @slot footer:after
66
+ *
67
+ * @element foxy-template-config-form
68
+ * @since 1.14.0
69
+ */
18
70
  export class TemplateConfigForm extends Base {
19
71
  constructor() {
20
72
  super(...arguments);
73
+ this.templates = {};
74
+ /** URI of the `fx:countries` hAPI resource. */
21
75
  this.countries = '';
76
+ /** URI of the `fx:regions` hAPI resource. */
22
77
  this.regions = '';
23
78
  this.__addHiddenFieldInputValue = '';
24
79
  }
@@ -46,7 +101,7 @@ export class TemplateConfigForm extends Base {
46
101
  }
47
102
  render() {
48
103
  var _a, _b;
49
- const hidden = this.hiddenControls;
104
+ const hidden = this.hiddenSelector;
50
105
  const json = this.form.json ? JSON.parse(this.form.json) : getDefaultJSON();
51
106
  return html `
52
107
  <div class="relative" aria-busy=${this.in('busy')} aria-live="polite">
@@ -60,11 +115,16 @@ export class TemplateConfigForm extends Base {
60
115
  ${hidden.matches('foxycomplete', true) ? '' : this.__renderFoxycomplete(json)}
61
116
  ${hidden.matches('locations', true) ? '' : this.__renderLocations(json)}
62
117
  ${hidden.matches('hidden-fields', true) ? '' : this.__renderHiddenFields(json)}
118
+ ${hidden.matches('cards', true) ? '' : this.__renderCards(json)}
119
+ ${hidden.matches('checkout-type', true) ? '' : this.__renderCheckoutType(json)}
120
+ ${hidden.matches('consent', true) ? '' : this.__renderConsent(json)}
121
+ ${hidden.matches('fields', true) ? '' : this.__renderFields(json)}
63
122
  ${hidden.matches('google-analytics', true) ? '' : this.__renderGoogleAnalytics(json)}
64
123
  ${hidden.matches('segment-io', true) ? '' : this.__renderSegmentIo(json)}
65
124
  ${hidden.matches('troubleshooting', true) ? '' : this.__renderTroubleshooting(json)}
66
125
  ${hidden.matches('custom-config', true) ? '' : this.__renderCustomConfig(json)}
67
126
  ${hidden.matches('header', true) ? '' : this.__renderHeader(json)}
127
+ ${hidden.matches('custom-fields', true) ? '' : this.__renderCustomFields(json)}
68
128
  ${hidden.matches('footer', true) ? '' : this.__renderFooter(json)}
69
129
  </div>
70
130
 
@@ -89,17 +149,26 @@ export class TemplateConfigForm extends Base {
89
149
  __renderCartType(json) {
90
150
  const { lang, ns } = this;
91
151
  const items = ['default', 'fullpage', 'custom'];
152
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('cart-type', true);
92
153
  return html `
93
- <div>
154
+ <div data-testid="cart-type">
94
155
  ${this.renderTemplateOrSlot('cart-type:before')}
95
156
 
96
157
  <x-group frame>
97
- <foxy-i18n slot="header" lang=${lang} key="cart_type" ns=${ns}></foxy-i18n>
158
+ <foxy-i18n
159
+ class=${isDisabled ? 'text-disabled' : ''}
160
+ slot="header"
161
+ lang=${lang}
162
+ key="cart_type"
163
+ ns=${ns}
164
+ >
165
+ </foxy-i18n>
98
166
 
99
167
  <x-choice
168
+ data-testid="cart-type-choice"
100
169
  .value=${json.cart_type}
101
170
  .items=${items}
102
- ?disabled=${this.disabledSelector.matches('cart-type', true)}
171
+ ?disabled=${isDisabled}
103
172
  ?readonly=${this.readonlySelector.matches('cart-type', true)}
104
173
  @change=${(evt) => {
105
174
  this.edit({ json: JSON.stringify({ ...json, cart_type: evt.detail }) });
@@ -110,7 +179,7 @@ export class TemplateConfigForm extends Base {
110
179
  <div slot="${item}-label" class="grid leading-s py-s">
111
180
  <foxy-i18n lang=${lang} key="cart_type_${item}" ns=${ns}></foxy-i18n>
112
181
  <foxy-i18n
113
- class="text-secondary text-xs"
182
+ class="text-xs ${isDisabled ? 'text-disabled' : 'text-secondary'}"
114
183
  lang=${lang}
115
184
  key="cart_type_${item}_explainer"
116
185
  ns=${ns}
@@ -157,7 +226,14 @@ export class TemplateConfigForm extends Base {
157
226
  ${this.renderTemplateOrSlot('foxycomplete:before')}
158
227
 
159
228
  <x-group frame>
160
- <foxy-i18n slot="header" lang=${lang} key="foxycomplete" ns=${ns}></foxy-i18n>
229
+ <foxy-i18n
230
+ class=${isDisabled ? 'text-disabled' : ''}
231
+ slot="header"
232
+ lang=${lang}
233
+ key="foxycomplete"
234
+ ns=${ns}
235
+ >
236
+ </foxy-i18n>
161
237
 
162
238
  <x-choice
163
239
  .value=${value}
@@ -180,7 +256,7 @@ export class TemplateConfigForm extends Base {
180
256
  <div slot="${item}-label" class="grid leading-s py-s">
181
257
  <foxy-i18n lang=${lang} key="foxycomplete_${item}" ns=${ns}></foxy-i18n>
182
258
  <foxy-i18n
183
- class="text-secondary text-xs"
259
+ class="text-xs ${isDisabled ? 'text-disabled' : 'text-secondary'}"
184
260
  lang=${lang}
185
261
  key="foxycomplete_${item}_explainer"
186
262
  ns=${ns}
@@ -246,6 +322,8 @@ export class TemplateConfigForm extends Base {
246
322
  __renderLocations(json) {
247
323
  const { lang, ns } = this;
248
324
  const config = json.location_filtering;
325
+ const isDisabled = this.disabledSelector.matches('locations', true);
326
+ const isReadonly = this.readonlySelector.matches('locations', true);
249
327
  const shippingChoice = config.shipping_filter_type === 'blacklist' ? 'block' : 'allow';
250
328
  const billingChoice = config.usage === 'both'
251
329
  ? 'copy'
@@ -278,16 +356,31 @@ export class TemplateConfigForm extends Base {
278
356
  ${this.renderTemplateOrSlot('locations:before')}
279
357
 
280
358
  <x-group frame>
281
- <foxy-i18n slot="header" lang=${lang} key="location_plural" ns=${ns}></foxy-i18n>
359
+ <foxy-i18n
360
+ class=${isDisabled ? 'text-disabled' : ''}
361
+ slot="header"
362
+ lang=${lang}
363
+ key="location_plural"
364
+ ns=${ns}
365
+ >
366
+ </foxy-i18n>
282
367
 
283
368
  <div class="grid sm-grid-cols-2 bg-contrast-10" style="gap: 1px">
284
369
  <x-group class="bg-base pt-m">
285
- <foxy-i18n class="text-tertiary" slot="header" lang=${lang} key="shipping" ns=${ns}>
370
+ <foxy-i18n
371
+ class=${isDisabled ? 'text-disabled' : 'text-tertiary'}
372
+ slot="header"
373
+ lang=${lang}
374
+ key="shipping"
375
+ ns=${ns}
376
+ >
286
377
  </foxy-i18n>
287
378
 
288
379
  <x-choice
289
380
  .items=${['allow', 'block']}
290
381
  .value=${shippingChoice}
382
+ ?disabled=${isDisabled}
383
+ ?readonly=${isReadonly}
291
384
  @change=${(evt) => {
292
385
  if (config.usage !== 'both')
293
386
  config.usage = 'independent';
@@ -307,8 +400,8 @@ export class TemplateConfigForm extends Base {
307
400
  slot=${shippingChoice}
308
401
  lang=${lang}
309
402
  ns=${ns}
310
- ?disabled=${this.disabledSelector.matches('locations', true)}
311
- ?readonly=${this.readonlySelector.matches('locations', true)}
403
+ ?disabled=${isDisabled}
404
+ ?readonly=${isReadonly}
312
405
  @update:countries=${(evt) => {
313
406
  config.shipping_filter_values = evt.currentTarget.countries;
314
407
  normalize();
@@ -320,12 +413,20 @@ export class TemplateConfigForm extends Base {
320
413
  </x-group>
321
414
 
322
415
  <x-group class="bg-base pt-m">
323
- <foxy-i18n class="text-tertiary" slot="header" lang=${lang} key="billing" ns=${ns}>
416
+ <foxy-i18n
417
+ class=${isDisabled ? 'text-disabled' : 'text-tertiary'}
418
+ slot="header"
419
+ lang=${lang}
420
+ key="billing"
421
+ ns=${ns}
422
+ >
324
423
  </foxy-i18n>
325
424
 
326
425
  <x-choice
327
426
  .items=${['allow', 'block', 'copy']}
328
427
  .value=${billingChoice}
428
+ ?disabled=${isDisabled}
429
+ ?readonly=${isReadonly}
329
430
  @change=${(evt) => {
330
431
  if (evt.detail === 'copy') {
331
432
  config.usage = 'both';
@@ -350,8 +451,8 @@ export class TemplateConfigForm extends Base {
350
451
  slot=${billingChoice}
351
452
  lang=${lang}
352
453
  ns=${ns}
353
- ?disabled=${this.disabledSelector.matches('locations', true)}
354
- ?readonly=${this.readonlySelector.matches('locations', true)}
454
+ ?disabled=${isDisabled}
455
+ ?readonly=${isReadonly}
355
456
  ?hidden=${billingChoice === 'copy'}
356
457
  @update:countries=${(evt) => {
357
458
  config.billing_filter_values = evt.currentTarget.countries;
@@ -373,6 +474,8 @@ export class TemplateConfigForm extends Base {
373
474
  const suggestions = [];
374
475
  const fields = [];
375
476
  const config = json.cart_display_config;
477
+ const isDisabled = this.disabledSelector.matches('hidden-fields', true);
478
+ const isReadonly = this.readonlySelector.matches('hidden-fields', true);
376
479
  for (const key in config) {
377
480
  if (!key.startsWith('show_'))
378
481
  continue;
@@ -402,31 +505,54 @@ export class TemplateConfigForm extends Base {
402
505
  ${this.renderTemplateOrSlot('hidden-fields:before')}
403
506
 
404
507
  <x-group frame>
405
- <foxy-i18n slot="header" lang=${lang} key="hidden_fields" ns=${ns}></foxy-i18n>
508
+ <foxy-i18n
509
+ class=${isDisabled ? 'text-disabled' : ''}
510
+ slot="header"
511
+ lang=${lang}
512
+ key="hidden_fields"
513
+ ns=${ns}
514
+ >
515
+ </foxy-i18n>
406
516
 
407
517
  <div class="divide-y divide-contrast-10">
408
- ${fields.map(field => html `
409
- <div class="h-m ml-m pr-xs flex items-center justify-between">
518
+ ${fields.map(field => {
519
+ return html `
520
+ <div
521
+ class=${classMap({
522
+ 'h-m ml-m pr-xs flex items-center justify-between': true,
523
+ 'text-secondary': isReadonly,
524
+ 'text-disabled': isDisabled,
525
+ })}
526
+ >
410
527
  ${suggestions.includes(field)
411
- ? html `<foxy-i18n lang=${lang} key=${field} ns=${ns}></foxy-i18n>`
412
- : html `<span>${field}</span>`}
528
+ ? html `<foxy-i18n lang=${lang} key=${field} ns=${ns}></foxy-i18n>`
529
+ : html `<span>${field}</span>`}
413
530
 
414
531
  <button
415
- class="flex w-xs h-xs items-center justify-center rounded-full transition-colors hover-bg-error-10 hover-text-error focus-outline-none focus-ring-2 focus-ring-inset focus-ring-error-50"
532
+ class=${classMap({
533
+ 'w-xs h-xs rounded-full transition-colors': true,
534
+ 'hover-bg-error-10 hover-text-error': !isDisabled,
535
+ 'focus-outline-none focus-ring-2 ring-inset ring-error-50': !isDisabled,
536
+ 'cursor-default': isDisabled,
537
+ 'flex': !isReadonly,
538
+ 'hidden': isReadonly,
539
+ })}
540
+ ?disabled=${isDisabled}
416
541
  @click=${() => {
417
- if (typeof config[`show_${field}`] === 'boolean') {
418
- config[`show_${field}`] = true;
419
- }
420
- else {
421
- config.hidden_product_options = config.hidden_product_options.filter(option => option !== field);
422
- }
423
- this.edit({ json: JSON.stringify(json) });
424
- }}
542
+ if (typeof config[`show_${field}`] === 'boolean') {
543
+ config[`show_${field}`] = true;
544
+ }
545
+ else {
546
+ config.hidden_product_options = config.hidden_product_options.filter(option => option !== field);
547
+ }
548
+ this.edit({ json: JSON.stringify(json) });
549
+ }}
425
550
  >
426
- <iron-icon icon="icons:close" class="icon-inline text-m"></iron-icon>
551
+ <iron-icon icon="icons:close" class="icon-inline text-m m-auto"></iron-icon>
427
552
  </button>
428
553
  </div>
429
- `)}
554
+ `;
555
+ })}
430
556
  </div>
431
557
 
432
558
  <div
@@ -434,6 +560,8 @@ export class TemplateConfigForm extends Base {
434
560
  class=${classMap({
435
561
  'h-m flex items-center ring-inset ring-primary-50 focus-within-ring-2': true,
436
562
  'border-t border-contrast-10': fields.length > 0,
563
+ 'flex': !isReadonly,
564
+ 'hidden': isReadonly,
437
565
  })}
438
566
  >
439
567
  <input
@@ -441,6 +569,7 @@ export class TemplateConfigForm extends Base {
441
569
  class="w-full bg-transparent appearance-none h-m px-m focus-outline-none"
442
570
  list="hidden-fields-list"
443
571
  .value=${live(this.__addHiddenFieldInputValue)}
572
+ ?disabled=${isDisabled}
444
573
  @keydown=${(evt) => evt.key === 'Enter' && addField()}
445
574
  @input=${(evt) => {
446
575
  this.__addHiddenFieldInputValue = evt.currentTarget.value;
@@ -475,6 +604,461 @@ export class TemplateConfigForm extends Base {
475
604
  </div>
476
605
  `;
477
606
  }
607
+ __renderCards(json) {
608
+ const { lang, ns } = this;
609
+ const isDisabled = this.disabledSelector.matches('cards', true);
610
+ const isReadonly = this.readonlySelector.matches('cards', true);
611
+ const config = json.supported_payment_cards;
612
+ let skipForSaved;
613
+ let skipForSSO;
614
+ if (json.csc_requirements === 'all_cards') {
615
+ skipForSaved = false;
616
+ skipForSSO = false;
617
+ }
618
+ else if (json.csc_requirements === 'sso_only') {
619
+ skipForSaved = true;
620
+ skipForSSO = false;
621
+ }
622
+ else {
623
+ skipForSaved = true;
624
+ skipForSSO = true;
625
+ }
626
+ const typeToName = {
627
+ amex: 'American Express',
628
+ diners: 'Diners Club',
629
+ discover: 'Discover',
630
+ jcb: 'JCB',
631
+ maestro: 'Maestro',
632
+ mastercard: 'Mastercard',
633
+ unionpay: 'UnionPay',
634
+ visa: 'Visa',
635
+ };
636
+ return html `
637
+ <div>
638
+ ${this.renderTemplateOrSlot('cards:before')}
639
+
640
+ <div class="space-y-xs">
641
+ <x-group frame>
642
+ <foxy-i18n
643
+ class=${isDisabled ? 'text-disabled' : ''}
644
+ slot="header"
645
+ lang=${lang}
646
+ key="supported_cards"
647
+ ns=${ns}
648
+ >
649
+ </foxy-i18n>
650
+
651
+ <div class="flex flex-wrap m-xs p-s">
652
+ ${Object.entries(logos).map(([type, logo]) => {
653
+ if (!typeToName[type])
654
+ return;
655
+ const isChecked = config.includes(type);
656
+ return html `
657
+ <div
658
+ class=${classMap({
659
+ 'm-xs rounded': true,
660
+ 'opacity-50 cursor-default': isDisabled,
661
+ 'cursor-pointer ring-primary-50 focus-within-ring-2': !isDisabled,
662
+ })}
663
+ >
664
+ <label
665
+ class=${classMap({
666
+ 'overflow-hidden transition-colors flex rounded border': true,
667
+ 'border-primary bg-primary-10 text-primary': isChecked && !isReadonly,
668
+ 'border-contrast bg-contrast-5 text-secondary': isChecked && isReadonly,
669
+ 'hover-text-body': isChecked && !isDisabled && !isReadonly,
670
+ 'border-contrast-10': !isChecked,
671
+ 'hover-border-primary': !isChecked && !isDisabled && !isReadonly,
672
+ 'hover-text-primary': !isChecked && !isDisabled && !isReadonly,
673
+ })}
674
+ >
675
+ <div class="h-s">${logo}</div>
676
+
677
+ <div class="text-s font-medium mx-s my-auto leading-none">
678
+ ${typeToName[type]}
679
+ </div>
680
+
681
+ <input
682
+ type="checkbox"
683
+ class="sr-only"
684
+ ?disabled=${isDisabled}
685
+ ?checked=${isChecked}
686
+ @change=${(evt) => {
687
+ if (isReadonly)
688
+ return evt.preventDefault();
689
+ evt.stopPropagation();
690
+ if (isChecked) {
691
+ config.splice(config.indexOf(type), 1);
692
+ }
693
+ else {
694
+ config.push(type);
695
+ }
696
+ this.edit({ json: JSON.stringify(json) });
697
+ }}
698
+ />
699
+ </label>
700
+ </div>
701
+ `;
702
+ })}
703
+ </div>
704
+
705
+ <div class="flex flex-wrap p-s border-t border-contrast-10">
706
+ <x-checkbox
707
+ class="m-s"
708
+ ?disabled=${isDisabled || json.csc_requirements === 'new_cards_only'}
709
+ ?readonly=${isReadonly}
710
+ ?checked=${skipForSaved}
711
+ @change=${(evt) => {
712
+ json.csc_requirements = evt.detail ? 'sso_only' : 'all_cards';
713
+ this.edit({ json: JSON.stringify(json) });
714
+ }}
715
+ >
716
+ <foxy-i18n class="leading-s block" lang=${lang} key="skip_csc_for_saved" ns=${ns}>
717
+ </foxy-i18n>
718
+ </x-checkbox>
719
+
720
+ <x-checkbox
721
+ class="m-s"
722
+ ?disabled=${isDisabled}
723
+ ?readonly=${isReadonly}
724
+ ?checked=${skipForSSO}
725
+ @change=${(evt) => {
726
+ json.csc_requirements = evt.detail
727
+ ? 'new_cards_only'
728
+ : skipForSaved
729
+ ? 'sso_only'
730
+ : 'all_cards';
731
+ this.edit({ json: JSON.stringify(json) });
732
+ }}
733
+ >
734
+ <foxy-i18n class="leading-s block" lang=${lang} key="skip_csc_for_sso" ns=${ns}>
735
+ </foxy-i18n>
736
+ </x-checkbox>
737
+ </div>
738
+ </x-group>
739
+
740
+ <foxy-i18n
741
+ class="text-xs leading-s block ${isDisabled ? 'text-disabled' : 'text-secondary'}"
742
+ lang=${lang}
743
+ key="supported_cards_disclaimer"
744
+ ns=${ns}
745
+ >
746
+ </foxy-i18n>
747
+ </div>
748
+
749
+ ${this.renderTemplateOrSlot('cards:after')}
750
+ </div>
751
+ `;
752
+ }
753
+ __renderCheckoutType(json) {
754
+ const { lang, ns } = this;
755
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('checkout-type', true);
756
+ const isReadonly = this.readonlySelector.matches('checkout-type', true);
757
+ return html `
758
+ <div data-testid="checkout-type">
759
+ ${this.renderTemplateOrSlot('checkout-type:before')}
760
+
761
+ <div class="space-y-xs">
762
+ <x-group frame>
763
+ <foxy-i18n
764
+ class=${isDisabled ? 'text-disabled' : ''}
765
+ slot="header"
766
+ lang=${lang}
767
+ key="checkout_type"
768
+ ns=${ns}
769
+ >
770
+ </foxy-i18n>
771
+
772
+ <x-choice
773
+ data-testid="checkout-type-choice"
774
+ ?disabled=${isDisabled}
775
+ ?readonly=${isReadonly}
776
+ .items=${['default_account', 'default_guest', 'guest_only', 'account_only']}
777
+ .value=${json.checkout_type}
778
+ .getText=${(item) => this.t(`checkout_type_${item}`)}
779
+ @change=${(evt) => {
780
+ json.checkout_type = evt.detail;
781
+ this.edit({ json: JSON.stringify(json) });
782
+ }}
783
+ >
784
+ </x-choice>
785
+ </x-group>
786
+
787
+ <foxy-i18n
788
+ class="text-xs leading-s block ${isDisabled ? 'text-disabled' : 'text-secondary'}"
789
+ lang=${lang}
790
+ key="checkout_type_helper_text"
791
+ ns=${ns}
792
+ >
793
+ </foxy-i18n>
794
+ </div>
795
+
796
+ ${this.renderTemplateOrSlot('checkout-type:after')}
797
+ </div>
798
+ `;
799
+ }
800
+ __renderConsent(json) {
801
+ const { lang, ns } = this;
802
+ const tosConfig = json.tos_checkbox_settings;
803
+ const mailConfig = json.newsletter_subscribe;
804
+ const sdtaConfig = json.eu_secure_data_transfer_consent;
805
+ const isDisabled = this.disabledSelector.matches('consent', true);
806
+ const isReadonly = this.readonlySelector.matches('consent', true);
807
+ const dividerStyle = 'margin-left: calc(1.125rem + (var(--lumo-space-m) * 2))';
808
+ return html `
809
+ <div>
810
+ ${this.renderTemplateOrSlot('consent:before')}
811
+
812
+ <x-group frame>
813
+ <foxy-i18n
814
+ class=${isDisabled ? 'text-disabled' : ''}
815
+ slot="header"
816
+ lang=${lang}
817
+ key="consent"
818
+ ns=${ns}
819
+ >
820
+ </foxy-i18n>
821
+
822
+ <x-checkbox
823
+ ?disabled=${isDisabled}
824
+ ?readonly=${isReadonly}
825
+ ?checked=${tosConfig.usage === 'required' || tosConfig.usage === 'optional'}
826
+ class="m-m"
827
+ @change=${(evt) => {
828
+ tosConfig.initial_state = evt.detail ? tosConfig.initial_state : 'unchecked';
829
+ tosConfig.is_hidden = false;
830
+ tosConfig.usage = evt.detail ? 'required' : 'none';
831
+ tosConfig.url = evt.detail ? tosConfig.url : '';
832
+ this.edit({ json: JSON.stringify(json) });
833
+ }}
834
+ >
835
+ <div class="flex flex-col">
836
+ <foxy-i18n lang=${lang} key="display_tos_link" ns=${ns}></foxy-i18n>
837
+ <foxy-i18n
838
+ class="text-xs leading-s ${isDisabled ? 'text-disabled' : 'text-secondary'}"
839
+ lang=${lang}
840
+ key="display_tos_link_explainer"
841
+ ns=${ns}
842
+ >
843
+ </foxy-i18n>
844
+ </div>
845
+
846
+ <div slot="content" ?hidden=${tosConfig.usage === 'none'}>
847
+ <vaadin-text-field
848
+ label=${this.t('location_url')}
849
+ class="w-full mt-m"
850
+ placeholder="https://example.com/path/to/tos"
851
+ clear-button-visible
852
+ ?disabled=${isDisabled}
853
+ ?readonly=${isReadonly}
854
+ .value=${tosConfig.url}
855
+ @input=${(evt) => {
856
+ tosConfig.url = evt.currentTarget.value;
857
+ this.edit({ json: JSON.stringify(json) });
858
+ }}
859
+ >
860
+ </vaadin-text-field>
861
+
862
+ <div class="flex flex-wrap -mx-s -mb-s mt-s">
863
+ <x-checkbox
864
+ class="m-s"
865
+ ?disabled=${isDisabled}
866
+ ?checked=${tosConfig.usage === 'required'}
867
+ @change=${(evt) => {
868
+ tosConfig.usage = evt.detail ? 'required' : 'optional';
869
+ this.edit({ json: JSON.stringify(json) });
870
+ }}
871
+ >
872
+ <foxy-i18n class="leading-s block" lang=${lang} key="require_consent" ns=${ns}>
873
+ </foxy-i18n>
874
+ </x-checkbox>
875
+
876
+ <x-checkbox
877
+ class="m-s"
878
+ ?disabled=${isDisabled}
879
+ ?checked=${tosConfig.initial_state === 'checked'}
880
+ @change=${(evt) => {
881
+ tosConfig.initial_state = evt.detail ? 'checked' : 'unchecked';
882
+ this.edit({ json: JSON.stringify(json) });
883
+ }}
884
+ >
885
+ <foxy-i18n class="leading-s block" lang=${lang} key="checked_by_default" ns=${ns}>
886
+ </foxy-i18n>
887
+ </x-checkbox>
888
+ </div>
889
+ </div>
890
+ </x-checkbox>
891
+
892
+ <div style=${dividerStyle} class="border-b border-contrast-10"></div>
893
+
894
+ <x-checkbox
895
+ ?disabled=${isDisabled}
896
+ ?readonly=${isReadonly}
897
+ ?checked=${mailConfig.usage === 'required'}
898
+ class="m-m"
899
+ @change=${(evt) => {
900
+ mailConfig.usage = evt.detail ? 'required' : 'none';
901
+ this.edit({ json: JSON.stringify(json) });
902
+ }}
903
+ >
904
+ <div class="flex flex-col">
905
+ <foxy-i18n lang=${lang} key="newsletter_subscribe" ns=${ns}></foxy-i18n>
906
+ <foxy-i18n
907
+ class="text-xs leading-s ${isDisabled ? 'text-disabled' : 'text-secondary'}"
908
+ lang=${lang}
909
+ key="newsletter_subscribe_explainer"
910
+ ns=${ns}
911
+ >
912
+ </foxy-i18n>
913
+ </div>
914
+ </x-checkbox>
915
+
916
+ <div style=${dividerStyle} class="border-b border-contrast-10"></div>
917
+
918
+ <x-checkbox
919
+ ?disabled=${isDisabled}
920
+ ?readonly=${isReadonly}
921
+ ?checked=${sdtaConfig.usage === 'required'}
922
+ class="m-m"
923
+ @change=${(evt) => {
924
+ sdtaConfig.usage = evt.detail ? 'required' : 'none';
925
+ this.edit({ json: JSON.stringify(json) });
926
+ }}
927
+ >
928
+ <div class="flex flex-col">
929
+ <foxy-i18n lang=${lang} key="display_sdta" ns=${ns}></foxy-i18n>
930
+ <foxy-i18n
931
+ class="text-xs leading-s ${isDisabled ? 'text-disabled' : 'text-secondary'}"
932
+ lang=${lang}
933
+ key="display_sdta_explainer"
934
+ ns=${ns}
935
+ >
936
+ </foxy-i18n>
937
+ </div>
938
+ </x-checkbox>
939
+ </x-group>
940
+
941
+ ${this.renderTemplateOrSlot('consent:before')}
942
+ </div>
943
+ `;
944
+ }
945
+ __renderFields(json) {
946
+ const { lang, ns } = this;
947
+ const isDisabled = this.disabledSelector.matches('fields', true);
948
+ const isReadonly = this.readonlySelector.matches('fields', true);
949
+ const config = json.custom_checkout_field_requirements;
950
+ const options = {
951
+ cart_controls: ['enabled', 'disabled'],
952
+ coupon_entry: ['enabled', 'disabled'],
953
+ billing_first_name: ['default', 'optional', 'required', 'hidden'],
954
+ billing_last_name: ['default', 'optional', 'required', 'hidden'],
955
+ billing_company: ['default', 'optional', 'required', 'hidden'],
956
+ billing_tax_id: ['default', 'optional', 'required', 'hidden'],
957
+ billing_phone: ['default', 'optional', 'required', 'hidden'],
958
+ billing_address1: ['default', 'optional', 'required', 'hidden'],
959
+ billing_address2: ['default', 'optional', 'required', 'hidden'],
960
+ billing_city: ['default', 'optional', 'required', 'hidden'],
961
+ billing_region: ['default', 'optional', 'required', 'hidden'],
962
+ billing_postal_code: ['default', 'optional', 'required', 'hidden'],
963
+ billing_country: ['default', 'optional', 'required', 'hidden'],
964
+ };
965
+ return html `
966
+ <div>
967
+ ${this.renderTemplateOrSlot('fields:before')}
968
+
969
+ <x-group frame>
970
+ <foxy-i18n
971
+ class=${isDisabled ? 'text-disabled' : ''}
972
+ slot="header"
973
+ lang=${lang}
974
+ key="field_plural"
975
+ ns=${ns}
976
+ >
977
+ </foxy-i18n>
978
+
979
+ <div class="bg-contrast-10 grid grid-cols-1 md-grid-cols-2" style="gap: 1px">
980
+ ${Object.entries(options).map(([property, values]) => {
981
+ return html `
982
+ <label
983
+ class=${classMap({
984
+ 'flex items-center pl-m bg-base': true,
985
+ 'text-secondary': isReadonly,
986
+ 'text-disabled': isDisabled,
987
+ })}
988
+ >
989
+ <foxy-i18n
990
+ class="flex-1"
991
+ lang=${lang}
992
+ key=${property.replace('billing_', '')}
993
+ ns=${ns}
994
+ >
995
+ </foxy-i18n>
996
+
997
+ <div
998
+ class=${classMap({
999
+ 'flex items-center text-right font-medium h-s px-s m-xs': isReadonly,
1000
+ 'hidden': !isReadonly,
1001
+ })}
1002
+ >
1003
+ ${this.t(values.find(value => config[property] === value))}
1004
+ </div>
1005
+
1006
+ <div
1007
+ class=${classMap({
1008
+ 'px-s m-xs flex items-center rounded leading-none': true,
1009
+ 'ring-primary-50 ring-inset focus-within-ring-2': !isDisabled,
1010
+ 'hover-text-primary': !isDisabled,
1011
+ 'cursor-pointer': !isDisabled,
1012
+ 'cursor-default': isDisabled,
1013
+ 'flex': !isReadonly,
1014
+ 'hidden': isReadonly,
1015
+ })}
1016
+ >
1017
+ <select
1018
+ class=${classMap({
1019
+ 'h-s mr-xs text-right appearance-none bg-transparent font-medium': true,
1020
+ 'focus-outline-none cursor-pointer': !isDisabled,
1021
+ 'cursor-default': isDisabled,
1022
+ })}
1023
+ ?disabled=${isDisabled}
1024
+ ?readonly=${isReadonly}
1025
+ @change=${(evt) => {
1026
+ const select = evt.currentTarget;
1027
+ const value = select.options[select.options.selectedIndex].value;
1028
+ config[property] = value;
1029
+ this.edit({ json: JSON.stringify(json) });
1030
+ }}
1031
+ >
1032
+ ${values.map(value => {
1033
+ return html `
1034
+ <option
1035
+ value=${value}
1036
+ ?selected=${config[property] === value}
1037
+ >
1038
+ ${this.t(value)}
1039
+ </option>
1040
+ `;
1041
+ })}
1042
+ </select>
1043
+
1044
+ <iron-icon
1045
+ class="pointer-events-none icon-inline text-xl"
1046
+ icon="icons:expand-more"
1047
+ >
1048
+ </iron-icon>
1049
+ </div>
1050
+ </label>
1051
+ `;
1052
+ })}
1053
+
1054
+ <div class="bg-base hidden md-block"></div>
1055
+ </div>
1056
+ </x-group>
1057
+
1058
+ ${this.renderTemplateOrSlot('fields:after')}
1059
+ </div>
1060
+ `;
1061
+ }
478
1062
  __renderGoogleAnalytics(json) {
479
1063
  const { lang, ns } = this;
480
1064
  const config = json.analytics_config;
@@ -487,7 +1071,7 @@ export class TemplateConfigForm extends Base {
487
1071
  ${this.renderTemplateOrSlot('google-analytics:before')}
488
1072
 
489
1073
  <x-group frame>
490
- <span slot="header">Google Analytics</span>
1074
+ <span class=${isDisabled ? 'text-disabled' : ''} slot="header">Google Analytics</span>
491
1075
 
492
1076
  <div class="p-m space-y-m">
493
1077
  <vaadin-text-field
@@ -520,7 +1104,7 @@ export class TemplateConfigForm extends Base {
520
1104
  <div class="flex flex-col">
521
1105
  <foxy-i18n lang=${lang} key="ga_include_on_site" ns=${ns}></foxy-i18n>
522
1106
  <foxy-i18n
523
- class="text-xs leading-s text-secondary"
1107
+ class="text-xs leading-s ${isDisabled ? 'text-disabled' : 'text-secondary'}"
524
1108
  lang=${lang}
525
1109
  key="ga_include_on_site_explainer"
526
1110
  ns=${ns}
@@ -546,7 +1130,7 @@ export class TemplateConfigForm extends Base {
546
1130
  ${this.renderTemplateOrSlot('segment-io:before')}
547
1131
 
548
1132
  <x-group frame>
549
- <span slot="header">Segment.io</span>
1133
+ <span class=${isDisabled ? 'text-disabled' : ''} slot="header">Segment.io</span>
550
1134
 
551
1135
  <div class="p-m">
552
1136
  <vaadin-text-field
@@ -576,17 +1160,26 @@ export class TemplateConfigForm extends Base {
576
1160
  __renderTroubleshooting(json) {
577
1161
  const { lang, ns } = this;
578
1162
  const config = json.debug;
1163
+ const isDisabled = this.disabledSelector.matches('troubleshooting', true);
1164
+ const isReadonly = this.readonlySelector.matches('troubleshooting', true);
579
1165
  return html `
580
1166
  <div>
581
1167
  ${this.renderTemplateOrSlot('troubleshooting:before')}
582
1168
 
583
1169
  <x-group frame>
584
- <foxy-i18n slot="header" lang=${lang} key="troubleshooting" ns=${ns}></foxy-i18n>
1170
+ <foxy-i18n
1171
+ class=${isDisabled ? 'text-disabled' : ''}
1172
+ slot="header"
1173
+ lang=${lang}
1174
+ key="troubleshooting"
1175
+ ns=${ns}
1176
+ >
1177
+ </foxy-i18n>
585
1178
 
586
1179
  <div class="p-m space-y-m">
587
1180
  <x-checkbox
588
- ?disabled=${this.disabledSelector.matches('troubleshooting', true)}
589
- ?readonly=${this.readonlySelector.matches('troubleshooting', true)}
1181
+ ?disabled=${isDisabled}
1182
+ ?readonly=${isReadonly}
590
1183
  ?checked=${config.usage === 'required'}
591
1184
  @change=${(evt) => {
592
1185
  config.usage = evt.detail ? 'required' : 'none';
@@ -596,7 +1189,7 @@ export class TemplateConfigForm extends Base {
596
1189
  <div class="flex flex-col">
597
1190
  <foxy-i18n lang=${lang} key="troubleshooting_debug" ns=${ns}></foxy-i18n>
598
1191
  <foxy-i18n
599
- class="text-xs leading-s text-secondary"
1192
+ class="text-xs leading-s ${isDisabled ? 'text-disabled' : 'text-secondary'}"
600
1193
  lang=${lang}
601
1194
  key="troubleshooting_debug_explainer"
602
1195
  ns=${ns}
@@ -613,16 +1206,17 @@ export class TemplateConfigForm extends Base {
613
1206
  }
614
1207
  __renderCustomConfig(json) {
615
1208
  return html `
616
- <div>
1209
+ <div data-testid="custom-config">
617
1210
  ${this.renderTemplateOrSlot('custom-config:before')}
618
1211
 
619
1212
  <vaadin-text-area
1213
+ data-testid="custom-config-field"
620
1214
  class="w-full"
621
1215
  label=${this.t('custom_config')}
622
1216
  placeholder='{ "key": "value" }'
623
1217
  helper-text=${this.t('custom_config_helper_text')}
624
1218
  .value=${json.custom_config ? JSON.stringify(json.custom_config, null, 2) : ''}
625
- ?disabled=${this.disabledSelector.matches('custom-config', true)}
1219
+ ?disabled=${!this.in('idle') || this.disabledSelector.matches('custom-config', true)}
626
1220
  ?readonly=${this.readonlySelector.matches('custom-config', true)}
627
1221
  @input=${(evt) => {
628
1222
  const input = evt.currentTarget;
@@ -644,15 +1238,16 @@ export class TemplateConfigForm extends Base {
644
1238
  }
645
1239
  __renderHeader(json) {
646
1240
  return html `
647
- <div>
1241
+ <div data-testid="header">
648
1242
  ${this.renderTemplateOrSlot('header:before')}
649
1243
 
650
1244
  <vaadin-text-area
1245
+ data-testid="header-field"
651
1246
  class="w-full"
652
1247
  label=${this.t('custom_header')}
653
1248
  helper-text=${this.t('custom_header_helper_text')}
654
1249
  .value=${json.custom_script_values.header}
655
- ?disabled=${this.disabledSelector.matches('header', true)}
1250
+ ?disabled=${!this.in('idle') || this.disabledSelector.matches('header', true)}
656
1251
  ?readonly=${this.readonlySelector.matches('header', true)}
657
1252
  @input=${(evt) => {
658
1253
  const target = evt.currentTarget;
@@ -669,17 +1264,43 @@ export class TemplateConfigForm extends Base {
669
1264
  </div>
670
1265
  `;
671
1266
  }
1267
+ __renderCustomFields(json) {
1268
+ return html `
1269
+ <div data-testid="custom-fields">
1270
+ ${this.renderTemplateOrSlot('custom-fields:before')}
1271
+
1272
+ <vaadin-text-area
1273
+ data-testid="custom-fields-field"
1274
+ class="w-full"
1275
+ label=${this.t('custom_fields')}
1276
+ helper-text=${this.t('custom_fields_helper_text')}
1277
+ .value=${json.custom_script_values.checkout_fields}
1278
+ ?disabled=${!this.in('idle') || this.disabledSelector.matches('custom-fields', true)}
1279
+ ?readonly=${this.readonlySelector.matches('custom-fields', true)}
1280
+ @input=${(evt) => {
1281
+ const newValue = evt.currentTarget.value;
1282
+ json.custom_script_values.checkout_fields = newValue;
1283
+ this.edit({ json: JSON.stringify(json) });
1284
+ }}
1285
+ >
1286
+ </vaadin-text-area>
1287
+
1288
+ ${this.renderTemplateOrSlot('custom-fields:after')}
1289
+ </div>
1290
+ `;
1291
+ }
672
1292
  __renderFooter(json) {
673
1293
  return html `
674
- <div>
1294
+ <div data-testid="footer">
675
1295
  ${this.renderTemplateOrSlot('footer:before')}
676
1296
 
677
1297
  <vaadin-text-area
1298
+ data-testid="footer-field"
678
1299
  class="w-full"
679
1300
  label=${this.t('custom_footer')}
680
1301
  helper-text=${this.t('custom_footer_helper_text')}
681
1302
  .value=${json.custom_script_values.footer}
682
- ?disabled=${this.disabledSelector.matches('footer', true)}
1303
+ ?disabled=${!this.in('idle') || this.disabledSelector.matches('footer', true)}
683
1304
  ?readonly=${this.readonlySelector.matches('footer', true)}
684
1305
  @input=${(evt) => {
685
1306
  const target = evt.currentTarget;