@foxy.io/elements 1.14.2 → 1.15.0-beta.3

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 (175) 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-coupon-card.js +1 -0
  11. package/dist/cdn/foxy-coupon-code-form.js +1 -0
  12. package/dist/cdn/foxy-coupon-codes-form.js +1 -0
  13. package/dist/cdn/foxy-coupon-form.js +1 -0
  14. package/dist/cdn/foxy-custom-field-card.js +1 -1
  15. package/dist/cdn/foxy-custom-field-form.js +1 -1
  16. package/dist/cdn/foxy-customer-api.js +1 -1
  17. package/dist/cdn/foxy-customer-card.js +1 -1
  18. package/dist/cdn/foxy-customer-form.js +1 -1
  19. package/dist/cdn/foxy-customer-portal-settings.js +4 -807
  20. package/dist/cdn/foxy-customer-portal.js +2 -2
  21. package/dist/cdn/foxy-customer.js +1 -1
  22. package/dist/cdn/foxy-customers-table.js +1 -1
  23. package/dist/cdn/foxy-discount-card.js +1 -1
  24. package/dist/cdn/foxy-donation.js +1 -1
  25. package/dist/cdn/foxy-email-template-form.js +1 -1
  26. package/dist/cdn/foxy-error-entry-card.js +1 -1
  27. package/dist/cdn/foxy-form-dialog.js +1 -1
  28. package/dist/cdn/foxy-generate-codes-form.js +1 -0
  29. package/dist/cdn/foxy-i18n.js +1 -1
  30. package/dist/cdn/foxy-items-form.js +1 -1
  31. package/dist/cdn/foxy-nucleon-element.js +1 -1
  32. package/dist/cdn/foxy-pagination.js +1 -0
  33. package/dist/cdn/foxy-payment-card.js +1 -1
  34. package/dist/cdn/foxy-payment-method-card.js +1 -1
  35. package/dist/cdn/foxy-query-builder.js +1 -69
  36. package/dist/cdn/foxy-sign-in-form.js +1 -1
  37. package/dist/cdn/foxy-spinner.js +1 -1
  38. package/dist/cdn/foxy-subscription-card.js +1 -1
  39. package/dist/cdn/foxy-subscription-form.js +3 -3
  40. package/dist/cdn/foxy-subscriptions-table.js +1 -1
  41. package/dist/cdn/foxy-table.js +1 -1
  42. package/dist/cdn/foxy-tax-card.js +1 -1
  43. package/dist/cdn/foxy-tax-form.js +1 -1
  44. package/dist/cdn/foxy-template-config-form.js +1 -1
  45. package/dist/cdn/foxy-template-form.js +1 -1
  46. package/dist/cdn/foxy-transaction-card.js +1 -1
  47. package/dist/cdn/foxy-transactions-table.js +1 -1
  48. package/dist/cdn/foxy-user-form.js +1 -1
  49. package/dist/cdn/foxy-users-table.js +1 -1
  50. package/dist/cdn/{shared-74b9e1d1.js → shared-0bda8ecb.js} +1 -1
  51. package/dist/cdn/{shared-07abcd7b.js → shared-0fcdd1c4.js} +1 -1
  52. package/dist/cdn/{shared-a46edf4b.js → shared-30131f76.js} +1 -1
  53. package/dist/cdn/shared-36629ded.js +131 -0
  54. package/dist/cdn/{shared-bc2bfe52.js → shared-4038cb18.js} +1 -1
  55. package/dist/cdn/{shared-44cfc617.js → shared-423a4840.js} +1 -1
  56. package/dist/cdn/shared-4fa5f144.js +1 -0
  57. package/dist/cdn/shared-51b5e223.js +1 -0
  58. package/dist/cdn/{shared-593f7e2c.js → shared-51e28c83.js} +1 -1
  59. package/dist/cdn/shared-710ed658.js +134 -0
  60. package/dist/cdn/shared-800a5471.js +1 -0
  61. package/dist/cdn/{shared-8a7bee0d.js → shared-8f7a66c4.js} +1 -1
  62. package/dist/cdn/{shared-91e768be.js → shared-9af7b5f0.js} +1 -1
  63. package/dist/cdn/{shared-7a42073a.js → shared-a11160e7.js} +5 -5
  64. package/dist/cdn/{shared-5f54e916.js → shared-a4e6ecb0.js} +1 -1
  65. package/dist/cdn/{shared-6ebe3825.js → shared-a8d96c23.js} +1 -1
  66. package/dist/cdn/{shared-322e60b1.js → shared-b03b6d72.js} +1 -1
  67. package/dist/cdn/shared-b2330475.js +1 -0
  68. package/dist/cdn/{shared-1761daef.js → shared-c1dadefe.js} +1 -1
  69. package/dist/cdn/shared-c6a4b2d6.js +1 -0
  70. package/dist/cdn/shared-ccea5a33.js +69 -0
  71. package/dist/cdn/shared-cd3c902e.js +1 -0
  72. package/dist/cdn/{shared-34b2c1e2.js → shared-d3831f99.js} +1 -1
  73. package/dist/cdn/shared-d9a260f0.js +1 -0
  74. package/dist/cdn/{shared-b1fc5dc3.js → shared-f875a4f8.js} +1 -1
  75. package/dist/cdn/{shared-e7f8ffe9.js → shared-fb403e1f.js} +1 -1
  76. package/dist/cdn/shared-ff149b55.js +804 -0
  77. package/dist/cdn/translations/customer-portal/zh-hk.json +35 -0
  78. package/dist/cdn/translations/shared/en.json +105 -0
  79. package/dist/cdn/translations/shared/zh-hk.json +179 -0
  80. package/dist/elements/private/Checkbox/Checkbox.js +36 -22
  81. package/dist/elements/private/Checkbox/Checkbox.js.map +1 -1
  82. package/dist/elements/private/EditableList/EditableList.d.ts +20 -0
  83. package/dist/elements/private/EditableList/EditableList.js +123 -0
  84. package/dist/elements/private/EditableList/EditableList.js.map +1 -0
  85. package/dist/elements/public/CouponCard/CouponCard.d.ts +29 -0
  86. package/dist/elements/public/CouponCard/CouponCard.js +130 -0
  87. package/dist/elements/public/CouponCard/CouponCard.js.map +1 -0
  88. package/dist/elements/public/CouponCard/index.d.ts +5 -0
  89. package/dist/elements/public/CouponCard/index.js +7 -0
  90. package/dist/elements/public/CouponCard/index.js.map +1 -0
  91. package/dist/elements/public/CouponCard/types.d.ts +15 -0
  92. package/dist/elements/public/CouponCard/types.js +2 -0
  93. package/dist/elements/public/CouponCard/types.js.map +1 -0
  94. package/dist/elements/public/CouponCodeForm/CouponCodeForm.d.ts +45 -0
  95. package/dist/elements/public/CouponCodeForm/CouponCodeForm.js +218 -0
  96. package/dist/elements/public/CouponCodeForm/CouponCodeForm.js.map +1 -0
  97. package/dist/elements/public/CouponCodeForm/index.d.ts +8 -0
  98. package/dist/elements/public/CouponCodeForm/index.js +10 -0
  99. package/dist/elements/public/CouponCodeForm/index.js.map +1 -0
  100. package/dist/elements/public/CouponCodeForm/types.d.ts +15 -0
  101. package/dist/elements/public/CouponCodeForm/types.js +2 -0
  102. package/dist/elements/public/CouponCodeForm/types.js.map +1 -0
  103. package/dist/elements/public/CouponCodesForm/CouponCodesForm.d.ts +29 -0
  104. package/dist/elements/public/CouponCodesForm/CouponCodesForm.js +209 -0
  105. package/dist/elements/public/CouponCodesForm/CouponCodesForm.js.map +1 -0
  106. package/dist/elements/public/CouponCodesForm/index.d.ts +8 -0
  107. package/dist/elements/public/CouponCodesForm/index.js +12 -0
  108. package/dist/elements/public/CouponCodesForm/index.js.map +1 -0
  109. package/dist/elements/public/CouponCodesForm/internal/InternalCouponCodesFormListItem.d.ts +14 -0
  110. package/dist/elements/public/CouponCodesForm/internal/InternalCouponCodesFormListItem.js +48 -0
  111. package/dist/elements/public/CouponCodesForm/internal/InternalCouponCodesFormListItem.js.map +1 -0
  112. package/dist/elements/public/CouponCodesForm/types.d.ts +16 -0
  113. package/dist/elements/public/CouponCodesForm/types.js +2 -0
  114. package/dist/elements/public/CouponCodesForm/types.js.map +1 -0
  115. package/dist/elements/public/CouponForm/CouponForm.d.ts +77 -0
  116. package/dist/elements/public/CouponForm/CouponForm.js +1266 -0
  117. package/dist/elements/public/CouponForm/CouponForm.js.map +1 -0
  118. package/dist/elements/public/CouponForm/index.d.ts +19 -0
  119. package/dist/elements/public/CouponForm/index.js +21 -0
  120. package/dist/elements/public/CouponForm/index.js.map +1 -0
  121. package/dist/elements/public/CouponForm/private/CategoryRestrictionsPage.d.ts +19 -0
  122. package/dist/elements/public/CouponForm/private/CategoryRestrictionsPage.js +98 -0
  123. package/dist/elements/public/CouponForm/private/CategoryRestrictionsPage.js.map +1 -0
  124. package/dist/elements/public/CouponForm/private/CategoryRestrictionsPageItem.d.ts +19 -0
  125. package/dist/elements/public/CouponForm/private/CategoryRestrictionsPageItem.js +51 -0
  126. package/dist/elements/public/CouponForm/private/CategoryRestrictionsPageItem.js.map +1 -0
  127. package/dist/elements/public/CouponForm/private/CategoryRestrictionsPageItemContent.d.ts +19 -0
  128. package/dist/elements/public/CouponForm/private/CategoryRestrictionsPageItemContent.js +52 -0
  129. package/dist/elements/public/CouponForm/private/CategoryRestrictionsPageItemContent.js.map +1 -0
  130. package/dist/elements/public/CouponForm/types.d.ts +27 -0
  131. package/dist/elements/public/CouponForm/types.js +2 -0
  132. package/dist/elements/public/CouponForm/types.js.map +1 -0
  133. package/dist/elements/public/GenerateCodesForm/GenerateCodesForm.d.ts +39 -0
  134. package/dist/elements/public/GenerateCodesForm/GenerateCodesForm.js +197 -0
  135. package/dist/elements/public/GenerateCodesForm/GenerateCodesForm.js.map +1 -0
  136. package/dist/elements/public/GenerateCodesForm/index.d.ts +8 -0
  137. package/dist/elements/public/GenerateCodesForm/index.js +10 -0
  138. package/dist/elements/public/GenerateCodesForm/index.js.map +1 -0
  139. package/dist/elements/public/GenerateCodesForm/types.d.ts +24 -0
  140. package/dist/elements/public/GenerateCodesForm/types.js +2 -0
  141. package/dist/elements/public/GenerateCodesForm/types.js.map +1 -0
  142. package/dist/elements/public/I18n/format/date.js +7 -6
  143. package/dist/elements/public/I18n/format/date.js.map +1 -1
  144. package/dist/elements/public/I18n/format/discount.d.ts +6 -0
  145. package/dist/elements/public/I18n/format/discount.js +20 -0
  146. package/dist/elements/public/I18n/format/discount.js.map +1 -0
  147. package/dist/elements/public/I18n/format/index.js +4 -0
  148. package/dist/elements/public/I18n/format/index.js.map +1 -1
  149. package/dist/elements/public/I18n/format/ordinal.d.ts +6 -0
  150. package/dist/elements/public/I18n/format/ordinal.js +9 -0
  151. package/dist/elements/public/I18n/format/ordinal.js.map +1 -0
  152. package/dist/elements/public/Pagination/Pagination.d.ts +37 -0
  153. package/dist/elements/public/Pagination/Pagination.js +154 -0
  154. package/dist/elements/public/Pagination/Pagination.js.map +1 -0
  155. package/dist/elements/public/Pagination/index.d.ts +6 -0
  156. package/dist/elements/public/Pagination/index.js +8 -0
  157. package/dist/elements/public/Pagination/index.js.map +1 -0
  158. package/dist/elements/public/Table/Table.js +20 -5
  159. package/dist/elements/public/Table/Table.js.map +1 -1
  160. package/dist/elements/public/index.d.ts +6 -0
  161. package/dist/elements/public/index.defined.d.ts +6 -0
  162. package/dist/elements/public/index.defined.js +6 -0
  163. package/dist/elements/public/index.defined.js.map +1 -1
  164. package/dist/elements/public/index.js +6 -0
  165. package/dist/elements/public/index.js.map +1 -1
  166. package/dist/mixins/themeable.js +80 -4
  167. package/dist/mixins/themeable.js.map +1 -1
  168. package/package.json +1 -1
  169. package/dist/cdn/shared-00563cb0.js +0 -1
  170. package/dist/cdn/shared-1f1734cb.js +0 -264
  171. package/dist/cdn/shared-66cb6a36.js +0 -1
  172. package/dist/cdn/shared-9a40309d.js +0 -1
  173. package/dist/cdn/shared-9c099da6.js +0 -1
  174. package/dist/cdn/shared-ce1da35d.js +0 -1
  175. package/dist/cdn/shared-f1dc1c6c.js +0 -1
@@ -0,0 +1,1266 @@
1
+ import { Type } from "../QueryBuilder/types.js";
2
+ import { html } from 'lit-element';
3
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements';
4
+ import { CategoryRestrictionsPage } from "./private/CategoryRestrictionsPage.js";
5
+ import { Checkbox } from "../../private/Checkbox/Checkbox.js";
6
+ import { CheckboxChangeEvent } from "../../private/Checkbox/CheckboxChangeEvent.js";
7
+ import { ConfigurableMixin } from "../../../mixins/configurable.js";
8
+ import { EditableList } from "../../private/EditableList/EditableList.js";
9
+ import { Group } from "../../private/Group/Group.js";
10
+ import { NucleonElement } from "../NucleonElement/NucleonElement.js";
11
+ import { PropertyTable } from "../../private/PropertyTable/PropertyTable.js";
12
+ import { ResponsiveMixin } from "../../../mixins/responsive.js";
13
+ import { ThemeableMixin } from "../../../mixins/themeable.js";
14
+ import { TranslatableMixin } from "../../../mixins/translatable.js";
15
+ import { classMap } from "../../../utils/class-map.js";
16
+ import { ifDefined } from 'lit-html/directives/if-defined';
17
+ import { live } from 'lit-html/directives/live';
18
+ import { operatorGreaterThanOrEqual } from "../QueryBuilder/icons/operatorGreaterThanOrEqual.js";
19
+ import { repeat } from 'lit-html/directives/repeat';
20
+ import { serializeDate } from "../../../utils/serialize-date.js";
21
+ const NS = 'coupon-form';
22
+ const Base = ScopedElementsMixin(ThemeableMixin(ConfigurableMixin(ResponsiveMixin(TranslatableMixin(NucleonElement, NS)))));
23
+ /**
24
+ * Form element for creating or editing coupons (`fx:coupon`).
25
+ *
26
+ * @slot name:before
27
+ * @slot name:after
28
+ *
29
+ * @slot rules:before
30
+ * @slot rules:after
31
+ *
32
+ * @slot codes:before
33
+ * @slot codes:after
34
+ *
35
+ * @slot usage:before
36
+ * @slot usage:after
37
+ *
38
+ * @slot product-restrictions:before
39
+ * @slot product-restrictions:after
40
+ *
41
+ * @slot category-restrictions:before
42
+ * @slot category-restrictions:after
43
+ *
44
+ * @slot options:before
45
+ * @slot options:after
46
+ *
47
+ * @slot timestamps:before
48
+ * @slot timestamps:after
49
+ *
50
+ * @slot delete:before
51
+ * @slot delete:after
52
+ *
53
+ * @slot create:before
54
+ * @slot create:after
55
+ *
56
+ * @element foxy-coupon-form
57
+ * @since 1.15.0
58
+ */
59
+ export class CouponForm extends Base {
60
+ constructor() {
61
+ super(...arguments);
62
+ this.__codesTableColumns = [
63
+ {
64
+ header: ctx => html `<foxy-i18n lang=${ctx.lang} key="code" ns=${ctx.ns}></foxy-i18n>`,
65
+ cell: ctx => html `
66
+ <vaadin-button
67
+ theme="tertiary contrast"
68
+ class="p-0"
69
+ @click=${(evt) => {
70
+ const dialog = this.renderRoot.querySelector('#code-dialog');
71
+ const button = evt.currentTarget;
72
+ dialog.href = ctx.data._links.self.href;
73
+ dialog.show(button);
74
+ }}
75
+ >
76
+ <span class="font-tnum">${ctx.data.code}</span>
77
+ </vaadin-button>
78
+ `,
79
+ },
80
+ {
81
+ header: ctx => html `<foxy-i18n lang=${ctx.lang} key="date_created" ns=${ctx.ns}></foxy-i18n>`,
82
+ cell: ctx => html `
83
+ <foxy-i18n
84
+ options=${JSON.stringify({ value: ctx.data.date_created })}
85
+ class="text-tertiary"
86
+ lang=${ctx.lang}
87
+ key="date"
88
+ ns=${ctx.ns}
89
+ >
90
+ </foxy-i18n>
91
+ `,
92
+ },
93
+ {
94
+ hideBelow: 'sm',
95
+ header: c => html `<foxy-i18n lang=${c.lang} key="date_modified" ns=${c.ns}></foxy-i18n>`,
96
+ cell: ctx => html `
97
+ <foxy-i18n
98
+ options=${JSON.stringify({ value: ctx.data.date_modified })}
99
+ class="text-tertiary"
100
+ lang=${ctx.lang}
101
+ key="date"
102
+ ns=${ctx.ns}
103
+ >
104
+ </foxy-i18n>
105
+ `,
106
+ },
107
+ {
108
+ header: c => html `<foxy-i18n lang=${c.lang} key="used_codes" ns=${c.ns}></foxy-i18n>`,
109
+ cell: ctx => html `${ctx.data.number_of_uses_to_date}`,
110
+ },
111
+ ];
112
+ this.__codesTableQuery = null;
113
+ this.__itemCategories = '';
114
+ }
115
+ static get scopedElements() {
116
+ return {
117
+ 'vaadin-integer-field': customElements.get('vaadin-integer-field'),
118
+ 'vaadin-date-picker': customElements.get('vaadin-date-picker'),
119
+ 'vaadin-text-field': customElements.get('vaadin-text-field'),
120
+ 'vaadin-button': customElements.get('vaadin-button'),
121
+ 'iron-dropdown': customElements.get('iron-dropdown'),
122
+ 'iron-icon': customElements.get('iron-icon'),
123
+ 'foxy-internal-confirm-dialog': customElements.get('foxy-internal-confirm-dialog'),
124
+ 'foxy-internal-sandbox': customElements.get('foxy-internal-sandbox'),
125
+ 'foxy-query-builder': customElements.get('foxy-query-builder'),
126
+ 'foxy-form-dialog': customElements.get('foxy-form-dialog'),
127
+ 'foxy-pagination': customElements.get('foxy-pagination'),
128
+ 'foxy-spinner': customElements.get('foxy-spinner'),
129
+ 'foxy-table': customElements.get('foxy-table'),
130
+ 'foxy-i18n': customElements.get('foxy-i18n'),
131
+ 'x-category-restrictions-page': CategoryRestrictionsPage,
132
+ 'x-property-table': PropertyTable,
133
+ 'x-editable-list': EditableList,
134
+ 'x-checkbox': Checkbox,
135
+ 'x-group': Group,
136
+ };
137
+ }
138
+ static get properties() {
139
+ return {
140
+ ...super.properties,
141
+ __codesTableQuery: { attribute: false },
142
+ __itemCategories: { attribute: false },
143
+ };
144
+ }
145
+ static get v8n() {
146
+ return [
147
+ ({ name: v }) => !!v || 'name_required',
148
+ ({ name: v }) => !v || v.length <= 50 || 'name_too_long',
149
+ ];
150
+ }
151
+ render() {
152
+ var _a, _b;
153
+ const hidden = this.hiddenSelector;
154
+ return html `
155
+ <div class="relative space-y-l">
156
+ ${hidden.matches('name', true) ? '' : this.__renderName()}
157
+ ${hidden.matches('rules', true) ? '' : this.__renderRules()}
158
+ ${hidden.matches('codes', true) || !this.data ? '' : this.__renderCodes()}
159
+ ${hidden.matches('usage', true) ? '' : this.__renderUsage()}
160
+ ${hidden.matches('product-restrictions', true) ? '' : this.__renderProductRestrictions()}
161
+ ${hidden.matches('category-restrictions', true) || !this.data
162
+ ? ''
163
+ : this.__renderCategoryRestrictions()}
164
+ ${hidden.matches('options', true) ? '' : this.__renderOptions()}
165
+ ${hidden.matches('timestamps', true) ? '' : this.__renderTimestamps()}
166
+ ${hidden.matches('create', true) || !!this.data ? '' : this.__renderCreate()}
167
+ ${hidden.matches('delete', true) || !this.data ? '' : this.__renderDelete()}
168
+
169
+ <div
170
+ data-testid="spinner"
171
+ class=${classMap({
172
+ 'transition duration-500 ease-in-out absolute inset-0 flex': true,
173
+ 'opacity-0 pointer-events-none': !this.in('busy') && !this.in('fail'),
174
+ })}
175
+ >
176
+ <foxy-spinner
177
+ layout="vertical"
178
+ class="m-auto p-m bg-base shadow-xs rounded-t-l rounded-b-l"
179
+ state=${this.in('fail') ? 'error' : this.in('busy') ? 'busy' : 'empty'}
180
+ lang=${this.lang}
181
+ ns="${this.ns} ${(_b = (_a = customElements.get('foxy-spinner')) === null || _a === void 0 ? void 0 : _a.defaultNS) !== null && _b !== void 0 ? _b : ''}"
182
+ >
183
+ </foxy-spinner>
184
+ </div>
185
+ </div>
186
+ `;
187
+ }
188
+ async _sendGet() {
189
+ const coupon = await super._sendGet();
190
+ const store = await super._fetch(coupon._links['fx:store'].href);
191
+ const categoriesURL = new URL(store._links['fx:item_categories'].href);
192
+ categoriesURL.searchParams.set('limit', '5');
193
+ this.__itemCategories = categoriesURL.toString();
194
+ return coupon;
195
+ }
196
+ __getErrorMessage(prefix) {
197
+ const error = this.errors.find(err => err.startsWith(prefix));
198
+ return error ? this.t(error.replace(prefix, 'v8n')).toString() : '';
199
+ }
200
+ __getValidator(prefix) {
201
+ return () => !this.errors.some(err => err.startsWith(prefix));
202
+ }
203
+ __renderName() {
204
+ return html `
205
+ <div>
206
+ ${this.renderTemplateOrSlot('name:before')}
207
+
208
+ <vaadin-text-field
209
+ error-message=${this.__getErrorMessage('name')}
210
+ helper-text=${this.t('coupon_name_helper_text')}
211
+ data-testid="name"
212
+ class="w-full"
213
+ label=${this.t('name')}
214
+ .checkValidity=${this.__getValidator('name')}
215
+ .value=${this.form.name}
216
+ ?disabled=${this.in('busy') || this.disabledSelector.matches('name', true)}
217
+ ?readonly=${this.readonlySelector.matches('name', true)}
218
+ required
219
+ @keydown=${(evt) => evt.key === 'Enter' && this.submit()}
220
+ @input=${(evt) => {
221
+ const newName = evt.currentTarget.value;
222
+ this.edit({ name: newName });
223
+ }}
224
+ >
225
+ </vaadin-text-field>
226
+
227
+ ${this.renderTemplateOrSlot('name:after')}
228
+ </div>
229
+ `;
230
+ }
231
+ __renderRulesPreset() {
232
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('rules', true);
233
+ const isReadonly = this.readonlySelector.matches('rules', true);
234
+ const details = this.form.coupon_discount_details;
235
+ const type = this.form.coupon_discount_type;
236
+ const presets = [
237
+ { type: 'quantity_amount', details: 'allunits|2-2' },
238
+ { type: 'quantity_percentage', details: 'allunits|5-10|10-20' },
239
+ { type: 'quantity_amount', details: 'incremental|3-5' },
240
+ { type: 'quantity_percentage', details: 'incremental|11-10|51-15|101-20' },
241
+ { type: 'quantity_percentage', details: 'repeat|2-100' },
242
+ { type: 'quantity_percentage', details: 'repeat|4-50' },
243
+ { type: 'quantity_amount', details: 'single|5-10' },
244
+ { type: 'price_percentage', details: 'single|99.99-10' },
245
+ ];
246
+ const selectedPreset = presets.find(p => p.details === details && p.type === type);
247
+ return html `
248
+ <label
249
+ class=${classMap({
250
+ 'whitespace-nowrap block ring-primary-50 rounded px-xs -mx-xs transition-colors': true,
251
+ 'text-body hover-text-primary focus-within-ring-2': !isDisabled && !isReadonly,
252
+ 'text-disabled': isDisabled,
253
+ 'text-secondary': isReadonly,
254
+ })}
255
+ >
256
+ <foxy-i18n class="sr-only" lang=${this.lang} key="preset" ns=${this.ns}></foxy-i18n>
257
+
258
+ <span class="relative font-medium flex items-center">
259
+ <span class="truncate">
260
+ ${selectedPreset
261
+ ? this.t('discount_summary', { params: selectedPreset })
262
+ : this.t('custom_discount')}
263
+ </span>
264
+
265
+ <iron-icon class="icon-inline text-xl ml-xs -mr-xs" icon="icons:expand-more"></iron-icon>
266
+
267
+ <select
268
+ class="opacity-0 absolute inset-0 focus-outline-none"
269
+ ?disabled=${isDisabled || isReadonly}
270
+ @change=${(evt) => {
271
+ var _a, _b;
272
+ const select = evt.currentTarget;
273
+ const preset = presets[select.selectedIndex];
274
+ this.edit({
275
+ coupon_discount_details: (_a = preset === null || preset === void 0 ? void 0 : preset.details) !== null && _a !== void 0 ? _a : '',
276
+ coupon_discount_type: (_b = preset === null || preset === void 0 ? void 0 : preset.type) !== null && _b !== void 0 ? _b : 'quantity_amount',
277
+ });
278
+ }}
279
+ >
280
+ ${presets.map(option => {
281
+ return html `
282
+ <option value=${option.details} ?selected=${option === selectedPreset}>
283
+ ${this.t('discount_summary', { params: option })}
284
+ </option>
285
+ `;
286
+ })}
287
+
288
+ <option value="custom" ?selected=${!selectedPreset}>
289
+ ${this.t('custom_discount')}
290
+ </option>
291
+ </select>
292
+ </span>
293
+ </label>
294
+ `;
295
+ }
296
+ __renderRulesTierSelect({ label, value, options, onChange }) {
297
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('rules', true);
298
+ const isReadonly = this.readonlySelector.matches('rules', true);
299
+ const isInteractive = !isDisabled && !isReadonly;
300
+ return html `
301
+ <label
302
+ class=${classMap({
303
+ 'h-xs whitespace-nowrap block ring-primary-50 rounded pl-s transition-colors': true,
304
+ 'hover-bg-primary hover-text-primary-contrast focus-within-ring-2': isInteractive,
305
+ 'bg-primary-10 text-primary': isInteractive,
306
+ 'bg-contrast-5 text-disabled': isDisabled,
307
+ 'bg-contrast-5 text-secondary': isReadonly && !isDisabled,
308
+ })}
309
+ >
310
+ <foxy-i18n class="sr-only" lang=${this.lang} key=${label} ns=${this.ns}></foxy-i18n>
311
+
312
+ <span class="relative leading-none font-medium flex items-center h-full">
313
+ <span class="truncate">${this.t(options[value])}</span>
314
+ <iron-icon class="icon-inline text-xl ml-xs" icon="icons:expand-more"></iron-icon>
315
+
316
+ <select
317
+ class="opacity-0 absolute inset-0 focus-outline-none"
318
+ ?disabled=${!isInteractive}
319
+ @change=${(evt) => {
320
+ const select = evt.currentTarget;
321
+ onChange(select.options[select.selectedIndex].value);
322
+ }}
323
+ >
324
+ ${Object.entries(options).map(([optionValue, optionKey]) => {
325
+ return html `
326
+ <option value=${optionValue} ?selected=${optionValue === value}>
327
+ ${this.t(optionKey)}
328
+ </option>
329
+ `;
330
+ })}
331
+ </select>
332
+ </span>
333
+ </label>
334
+ `;
335
+ }
336
+ __renderRulesTierSwitch({ value, options, onChange }) {
337
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('rules', true);
338
+ const isReadonly = this.readonlySelector.matches('rules', true);
339
+ const isInteractive = !isDisabled && !isReadonly;
340
+ const name = `switch-${Math.floor(Math.random() * Math.pow(10, 10))}`;
341
+ const dotStyle = 'width: 0.4rem; height: 0.4rem';
342
+ return html `
343
+ <div
344
+ class=${classMap({
345
+ 'h-xs px-xs space-x-xs flex items-center rounded transition-colors': true,
346
+ 'hover-bg-primary hover-text-primary-contrast focus-within-ring-2': isInteractive,
347
+ 'ring-primary-50 cursor-pointer bg-primary-10 text-primary': isInteractive,
348
+ 'bg-contrast-5 text-disabled': isDisabled,
349
+ 'bg-contrast-5 text-secondary': isReadonly && !isDisabled,
350
+ })}
351
+ @click=${(evt) => {
352
+ if (!isInteractive)
353
+ return;
354
+ const target = evt.currentTarget;
355
+ const firstInput = target.querySelector('input');
356
+ firstInput.focus();
357
+ onChange(value === 0 ? 1 : 0);
358
+ }}
359
+ >
360
+ <div class="leading-none font-medium px-xs pointer-events-none">
361
+ ${options.map((option, optionIndex) => {
362
+ return html `
363
+ <label>
364
+ <foxy-i18n
365
+ class=${classMap({ 'sr-only': optionIndex !== value })}
366
+ lang=${this.lang}
367
+ key=${option}
368
+ ns=${this.ns}
369
+ >
370
+ </foxy-i18n>
371
+
372
+ <input
373
+ class="sr-only"
374
+ value=${option}
375
+ name=${name}
376
+ type="radio"
377
+ ?disabled=${!isInteractive}
378
+ ?checked=${optionIndex === value}
379
+ @change=${(evt) => {
380
+ const input = evt.currentTarget;
381
+ if (input.checked)
382
+ onChange(optionIndex);
383
+ }}
384
+ />
385
+ </label>
386
+ `;
387
+ })}
388
+ </div>
389
+
390
+ <div class="flex justify-evenly h-full ${value ? 'flex-col-reverse' : 'flex-col'}">
391
+ <div style=${dotStyle} class="bg-current rounded-full"></div>
392
+ <div style=${dotStyle} class="border border-current rounded-full"></div>
393
+ </div>
394
+ </div>
395
+ `;
396
+ }
397
+ __renderRulesTierField({ value, label, onChange }) {
398
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('rules', true);
399
+ const isReadonly = this.readonlySelector.matches('rules', true);
400
+ const isInteractive = !isDisabled && !isReadonly;
401
+ return html `
402
+ <label>
403
+ <foxy-i18n class="sr-only" lang=${this.lang} key=${label} ns=${this.ns}></foxy-i18n>
404
+ <input
405
+ class=${classMap({
406
+ 'transition-colors border p-xs h-xs font-medium text-m rounded w-xl': true,
407
+ 'ring-primary-50 text-body bg-contrast-10': isInteractive,
408
+ 'hover-bg-contrast-20': isInteractive,
409
+ 'focus-outline-none focus-ring-2': isInteractive,
410
+ 'text-disabled bg-contrast-5': isDisabled,
411
+ 'text-secondary': isReadonly && !isDisabled,
412
+ 'border-transparent border-solid': !isReadonly,
413
+ 'border-dashed border-contrast-30': isReadonly,
414
+ })}
415
+ type="number"
416
+ min="0"
417
+ ?disabled=${!isInteractive}
418
+ .value=${value}
419
+ @input=${(evt) => {
420
+ const input = evt.currentTarget;
421
+ onChange(input.value);
422
+ }}
423
+ />
424
+ </label>
425
+ `;
426
+ }
427
+ __renderRulesTier(params) {
428
+ var _a;
429
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('rules', true);
430
+ const isReadonly = this.readonlySelector.matches('rules', true);
431
+ const tier = (_a = params.tier) !== null && _a !== void 0 ? _a : '0-0';
432
+ const sign = tier.includes('+') ? '+' : '-';
433
+ const [from, adjustment] = tier.split(/[-+]/).map(v => parseFloat(v));
434
+ return html `
435
+ <div
436
+ aria-label=${this.t('tier')}
437
+ class=${classMap({
438
+ 'flex items-start justify-between rounded-t-l rounded-b-l': true,
439
+ 'border border-contrast-10': true,
440
+ 'border-dashed': !params.tier,
441
+ })}
442
+ >
443
+ <div
444
+ class=${classMap({
445
+ 'transition-colors flex flex-wrap items-center gap-s p-s': true,
446
+ 'text-tertiary': !isDisabled,
447
+ 'text-disabled': isDisabled,
448
+ })}
449
+ >
450
+ <foxy-i18n
451
+ class="uppercase text-s font-semibold"
452
+ lang=${this.lang}
453
+ key="tier_if"
454
+ ns=${this.ns}
455
+ >
456
+ </foxy-i18n>
457
+
458
+ ${this.__renderRulesTierSwitch({
459
+ options: ['total', 'quantity'],
460
+ value: params.source === 'price' ? 0 : 1,
461
+ onChange: i => params.onChange({ source: i ? 'quantity' : 'price' }),
462
+ })}
463
+
464
+ <div class="h-s w-s">${operatorGreaterThanOrEqual}</div>
465
+
466
+ ${this.__renderRulesTierField({
467
+ label: 'from',
468
+ value: String(from),
469
+ onChange: v => params.onChange({ tier: `${v}${sign}${adjustment}` }),
470
+ })}
471
+
472
+ <foxy-i18n
473
+ class="uppercase text-s font-semibold"
474
+ lang=${this.lang}
475
+ key="tier_then"
476
+ ns=${this.ns}
477
+ >
478
+ </foxy-i18n>
479
+
480
+ ${this.__renderRulesTierSwitch({
481
+ options: ['reduce', 'increase'],
482
+ value: sign === '-' ? 0 : 1,
483
+ onChange: i => params.onChange({ tier: `${from}${i ? '+' : '-'}${adjustment}` }),
484
+ })}
485
+
486
+ <!---->
487
+
488
+ ${this.__renderRulesTierSelect({
489
+ options: {
490
+ incremental: 'tier_incremental',
491
+ allunits: 'tier_allunits',
492
+ repeat: 'tier_repeat',
493
+ single: 'tier_single',
494
+ },
495
+ value: params.method,
496
+ label: 'target',
497
+ onChange: v => params.onChange({ method: v }),
498
+ })}
499
+
500
+ <foxy-i18n
501
+ class="uppercase text-s font-semibold"
502
+ lang=${this.lang}
503
+ key="tier_by"
504
+ ns=${this.ns}
505
+ >
506
+ </foxy-i18n>
507
+
508
+ ${this.__renderRulesTierField({
509
+ label: 'adjustment',
510
+ value: String(adjustment),
511
+ onChange: v => params.onChange({ tier: `${from}${sign}${v}` }),
512
+ })}
513
+
514
+ <!---->
515
+
516
+ ${this.__renderRulesTierSwitch({
517
+ value: params.units === 'percentage' ? 0 : 1,
518
+ options: ['%', '¤'],
519
+ onChange: i => params.onChange({ units: i ? 'amount' : 'percentage' }),
520
+ })}
521
+ </div>
522
+
523
+ ${params.tier
524
+ ? html `
525
+ <button
526
+ aria-label=${this.t('delete')}
527
+ class=${classMap({
528
+ 'w-s h-s m-s flex-shrink-0 rounded transition-colors ring-primary-50': true,
529
+ 'text-tertiary hover-text-secondary focus-outline-none focus-ring-2': !isDisabled,
530
+ 'text-disabled cursor-default': isDisabled,
531
+ })}
532
+ ?disabled=${isDisabled}
533
+ ?hidden=${isReadonly}
534
+ @click=${() => params.onDelete()}
535
+ >
536
+ <iron-icon icon="lumo:cross"></iron-icon>
537
+ </button>
538
+ `
539
+ : ''}
540
+ </div>
541
+ `;
542
+ }
543
+ __renderRulesUrlParameter() {
544
+ var _a, _b, _c;
545
+ const name = (_a = this.form.name) !== null && _a !== void 0 ? _a : '';
546
+ const type = (_b = this.form.coupon_discount_type) !== null && _b !== void 0 ? _b : 'quantity_amount';
547
+ const details = (_c = this.form.coupon_discount_details) !== null && _c !== void 0 ? _c : '';
548
+ const urlParameter = `discount_${type}=${encodeURIComponent(`${name}{${details}}`)}`;
549
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('rules', true);
550
+ return html `
551
+ <div class="text-xs flex space-x-xs leading-m">
552
+ <span
553
+ class=${classMap({
554
+ 'flex-shrink-0 transition-colors': true,
555
+ 'text-tertiary': !isDisabled,
556
+ 'text-disabled': isDisabled,
557
+ })}
558
+ >
559
+ <foxy-i18n lang=${this.lang} key="url_parameter" ns=${this.ns}></foxy-i18n>&#58;
560
+ </span>
561
+
562
+ <code
563
+ class=${classMap({
564
+ 'bg-contrast-5 transition-colors monospace truncate rounded px-xs': true,
565
+ 'text-secondary': !isDisabled,
566
+ 'text-disabled': isDisabled,
567
+ })}
568
+ >
569
+ ${urlParameter}
570
+ </code>
571
+
572
+ <button
573
+ class=${classMap({
574
+ 'flex-shrink-0 transition-colors font-medium rounded px-xs': true,
575
+ 'ring-primary-50 bg-primary-10 text-primary': !isDisabled,
576
+ 'text-disabled bg-contrast-5': isDisabled,
577
+ 'focus-outline-none focus-ring-2': !isDisabled,
578
+ 'hover-bg-primary hover-text-primary-contrast': !isDisabled,
579
+ })}
580
+ ?disabled=${isDisabled}
581
+ @click=${({ currentTarget }) => {
582
+ navigator.clipboard
583
+ .writeText(urlParameter)
584
+ .then(() => (currentTarget.textContent = this.t('copied')))
585
+ .catch(() => (currentTarget.textContent = this.t('error')))
586
+ .then(() => setTimeout(() => (currentTarget.textContent = this.t('copy')), 2000));
587
+ }}
588
+ >
589
+ ${this.t('copy')}
590
+ </button>
591
+ </div>
592
+ `;
593
+ }
594
+ __renderRulesDescription() {
595
+ var _a, _b;
596
+ const type = (_a = this.form.coupon_discount_type) !== null && _a !== void 0 ? _a : 'quantity_amount';
597
+ const details = (_b = this.form.coupon_discount_details) !== null && _b !== void 0 ? _b : '';
598
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('rules', true);
599
+ return html `
600
+ <div class="text-xs leading-m">
601
+ <span class="transition-colors ${isDisabled ? 'text-disabled' : 'text-tertiary'}">
602
+ <foxy-i18n lang=${this.lang} key="description" ns=${this.ns}></foxy-i18n>&#58;
603
+ </span>
604
+
605
+ <foxy-i18n
606
+ options=${JSON.stringify({ params: { details, type } })}
607
+ class="transition-colors ${isDisabled ? 'text-disabled' : 'text-secondary'}"
608
+ lang=${this.lang}
609
+ key="discount_summary"
610
+ ns=${this.ns}
611
+ >
612
+ </foxy-i18n>
613
+ </div>
614
+ `;
615
+ }
616
+ __renderRules() {
617
+ var _a, _b, _c;
618
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('rules', true);
619
+ const details = (_a = this.form.coupon_discount_details) !== null && _a !== void 0 ? _a : '';
620
+ const tiers = details.split('|').filter(v => !!v.trim());
621
+ const method = (_b = (/[-+]/.test(tiers[0]) ? null : tiers.shift())) !== null && _b !== void 0 ? _b : 'single';
622
+ const type = (_c = this.form.coupon_discount_type) !== null && _c !== void 0 ? _c : 'quantity_amount';
623
+ const [source, units] = type.split('_');
624
+ return html `
625
+ <div>
626
+ ${this.renderTemplateOrSlot('rules:before')}
627
+
628
+ <div>
629
+ <div class="flex items-center justify-between space-x-m text-s mb-xs">
630
+ <foxy-i18n
631
+ class=${classMap({
632
+ 'transition-colors font-medium flex-1': true,
633
+ 'text-secondary': !isDisabled,
634
+ 'text-disabled': isDisabled,
635
+ })}
636
+ lang=${this.lang}
637
+ key="rule_plural"
638
+ ns=${this.ns}
639
+ >
640
+ </foxy-i18n>
641
+
642
+ <div class="min-w-0">${this.__renderRulesPreset()}</div>
643
+ </div>
644
+
645
+ <div class="space-y-s">
646
+ ${repeat([...tiers, undefined], (tier, tierIndex) => {
647
+ const onChange = (changedParams) => {
648
+ var _a, _b, _c;
649
+ const newMethod = (_a = changedParams.method) !== null && _a !== void 0 ? _a : method;
650
+ const newSource = (_b = changedParams.source) !== null && _b !== void 0 ? _b : source;
651
+ const newUnits = (_c = changedParams.units) !== null && _c !== void 0 ? _c : units;
652
+ const newTier = changedParams.tier;
653
+ const newTiers = [...tiers];
654
+ if (newTier) {
655
+ const newTierIndex = tier ? tierIndex : newTiers.length;
656
+ const oldTiersCount = tier ? 1 : 0;
657
+ newTiers.splice(newTierIndex, oldTiersCount, newTier);
658
+ }
659
+ this.edit({
660
+ coupon_discount_details: `${newMethod}|${newTiers.join('|')}`,
661
+ coupon_discount_type: `${newSource}_${newUnits}`,
662
+ });
663
+ };
664
+ const onDelete = () => {
665
+ const newTiers = tiers.filter((_, i) => i !== tierIndex);
666
+ this.edit({ coupon_discount_details: `${method}|${newTiers.join('|')}` });
667
+ };
668
+ return this.__renderRulesTier({ source, method, units, tier, onChange, onDelete });
669
+ })}
670
+ </div>
671
+
672
+ <div class="space-y-xs mt-m">
673
+ ${this.__renderRulesUrlParameter()} ${this.__renderRulesDescription()}
674
+ </div>
675
+ </div>
676
+
677
+ ${this.renderTemplateOrSlot('rules:after')}
678
+ </div>
679
+ `;
680
+ }
681
+ __renderCodes() {
682
+ var _a;
683
+ const { disabledSelector, group, data, lang, ns } = this;
684
+ const isDisabled = !this.in('idle') || disabledSelector.matches('codes', true);
685
+ const filters = this.__codesTableQuery;
686
+ const url = new URL(data._links['fx:coupon_codes'].href);
687
+ new URLSearchParams(filters !== null && filters !== void 0 ? filters : '').forEach((value, name) => url.searchParams.set(name, value));
688
+ url.searchParams.set('limit', '5');
689
+ const filterButtonLabel = filters === null ? 'filter' : 'clear_filters';
690
+ const filterButtonIcon = `icons:${filters === null ? 'filter-list' : 'clear'}`;
691
+ return html `
692
+ <foxy-form-dialog
693
+ disabledcontrols=${disabledSelector.zoom('codes:generate:form').toString()}
694
+ readonlycontrols=${this.readonlySelector.zoom('codes:generate:form').toString()}
695
+ hiddencontrols="save-button ${this.hiddenSelector.zoom('codes:generate:form').toString()}"
696
+ related=${JSON.stringify([url.toString()])}
697
+ header="generate"
698
+ parent=${(_a = data === null || data === void 0 ? void 0 : data._links['fx:generate_codes'].href) !== null && _a !== void 0 ? _a : ''}
699
+ group=${group}
700
+ lang=${lang}
701
+ form="foxy-generate-codes-form"
702
+ ns=${ns}
703
+ id="generate-codes-dialog"
704
+ alert
705
+ >
706
+ </foxy-form-dialog>
707
+
708
+ <foxy-form-dialog
709
+ disabledcontrols=${disabledSelector.zoom('codes:form').toString()}
710
+ readonlycontrols=${this.readonlySelector.zoom('codes:form').toString()}
711
+ hiddencontrols=${this.hiddenSelector.zoom('codes:form').toString()}
712
+ header="code"
713
+ parent=${url.toString()}
714
+ group=${group}
715
+ lang=${lang}
716
+ form="foxy-coupon-code-form"
717
+ ns=${ns}
718
+ id="code-dialog"
719
+ >
720
+ </foxy-form-dialog>
721
+
722
+ <foxy-form-dialog
723
+ disabledcontrols=${disabledSelector.zoom('codes:import:form').toString()}
724
+ readonlycontrols=${this.readonlySelector.zoom('codes:import:form').toString()}
725
+ hiddencontrols="save-button ${this.hiddenSelector.zoom('codes:generate:form').toString()}"
726
+ header="import"
727
+ parent=${data._links['fx:coupon_codes'].href}
728
+ group=${group}
729
+ lang=${lang}
730
+ form="foxy-coupon-codes-form"
731
+ ns=${ns}
732
+ id="import-dialog"
733
+ >
734
+ </foxy-form-dialog>
735
+
736
+ <div>
737
+ ${this.renderTemplateOrSlot('codes:before')}
738
+
739
+ <div class="flex items-center justify-between mb-xs space-x-s">
740
+ <foxy-i18n
741
+ class="text-s font-medium text-secondary leading-none flex-1"
742
+ lang=${lang}
743
+ key="code_plural"
744
+ ns=${ns}
745
+ >
746
+ </foxy-i18n>
747
+
748
+ <vaadin-button
749
+ theme="success tertiary small"
750
+ ?disabled=${isDisabled}
751
+ @click=${(evt) => {
752
+ const dialog = this.renderRoot.querySelector('#generate-codes-dialog');
753
+ const button = evt.currentTarget;
754
+ dialog === null || dialog === void 0 ? void 0 : dialog.show(button);
755
+ }}
756
+ >
757
+ <foxy-i18n class="text-s" lang=${lang} key="generate" ns=${ns}></foxy-i18n>
758
+ <iron-icon class="icon-inline text-s" icon="icons:add"></iron-icon>
759
+ </vaadin-button>
760
+
761
+ <vaadin-button
762
+ theme="contrast tertiary small"
763
+ ?disabled=${isDisabled}
764
+ @click=${(evt) => {
765
+ const dialog = this.renderRoot.querySelector('#import-dialog');
766
+ const button = evt.currentTarget;
767
+ dialog === null || dialog === void 0 ? void 0 : dialog.show(button);
768
+ }}
769
+ >
770
+ <foxy-i18n class="text-s" lang=${lang} key="import" ns=${ns}></foxy-i18n>
771
+ <iron-icon class="icon-inline text-s" icon="icons:open-in-browser"></iron-icon>
772
+ </vaadin-button>
773
+
774
+ <vaadin-button
775
+ theme="contrast ${filters === null ? 'tertiary' : ''} small"
776
+ ?disabled=${isDisabled}
777
+ @click=${() => (this.__codesTableQuery = filters === null ? '' : null)}
778
+ >
779
+ <foxy-i18n class="text-s" lang=${lang} key=${filterButtonLabel} ns=${ns}></foxy-i18n>
780
+ <iron-icon class="icon-inline text-s" icon=${filterButtonIcon}></iron-icon>
781
+ </vaadin-button>
782
+ </div>
783
+
784
+ <foxy-query-builder
785
+ class="bg-contrast-5 rounded-tl-l rounded-tr-s rounded-b-l p-m mb-s"
786
+ lang=${lang}
787
+ ns=${ns}
788
+ ?disabled=${isDisabled}
789
+ ?hidden=${filters === null}
790
+ .options=${CouponForm.__codesQueryOptions}
791
+ .value=${filters}
792
+ @change=${(evt) => {
793
+ const queryBuilder = evt.currentTarget;
794
+ this.__codesTableQuery = queryBuilder.value;
795
+ }}
796
+ >
797
+ </foxy-query-builder>
798
+
799
+ <foxy-pagination first=${url.toString()} lang=${lang} ns=${ns} ?disabled=${isDisabled}>
800
+ <foxy-table
801
+ class="px-m mb-s border border-contrast-10 rounded-t-l rounded-b-l"
802
+ group=${group}
803
+ lang=${lang}
804
+ ns=${ns}
805
+ .columns=${this.__codesTableColumns}
806
+ >
807
+ </foxy-table>
808
+ </foxy-pagination>
809
+
810
+ ${this.renderTemplateOrSlot('codes:after')}
811
+ </div>
812
+ `;
813
+ }
814
+ __renderUsage() {
815
+ var _a, _b, _c;
816
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('usage', true);
817
+ const isReadonly = this.readonlySelector.matches('usage', true);
818
+ const usesPerCoupon = (_a = this.form.number_of_uses_allowed) !== null && _a !== void 0 ? _a : 0;
819
+ const usesPerCustomer = (_b = this.form.number_of_uses_allowed_per_customer) !== null && _b !== void 0 ? _b : 0;
820
+ const usesPerCouponCode = (_c = this.form.number_of_uses_allowed_per_code) !== null && _c !== void 0 ? _c : 0;
821
+ return html `
822
+ ${this.renderTemplateOrSlot('usage:before')}
823
+
824
+ <div class="space-y-s">
825
+ <div class="grid gap-m grid-cols-3">
826
+ <vaadin-integer-field
827
+ placeholder=${this.t('unlimited')}
828
+ label=${this.t('uses_per_coupon')}
829
+ class="w-full"
830
+ min="0"
831
+ prevent-invalid-input
832
+ has-controls
833
+ .value=${usesPerCoupon || ''}
834
+ ?disabled=${isDisabled}
835
+ ?readonly=${isReadonly}
836
+ @change=${(evt) => {
837
+ const field = evt.currentTarget;
838
+ this.edit({ number_of_uses_allowed: parseInt(field.value) });
839
+ }}
840
+ >
841
+ </vaadin-integer-field>
842
+
843
+ <vaadin-integer-field
844
+ placeholder=${this.t('unlimited')}
845
+ label=${this.t('uses_per_coupon_code')}
846
+ class="w-full"
847
+ min="0"
848
+ prevent-invalid-input
849
+ has-controls
850
+ .value=${usesPerCouponCode || ''}
851
+ ?disabled=${isDisabled}
852
+ ?readonly=${isReadonly}
853
+ @change=${(evt) => {
854
+ const field = evt.currentTarget;
855
+ this.edit({ number_of_uses_allowed_per_code: parseInt(field.value) });
856
+ }}
857
+ >
858
+ </vaadin-integer-field>
859
+
860
+ <vaadin-integer-field
861
+ placeholder=${this.t('unlimited')}
862
+ label=${this.t('uses_per_customer')}
863
+ class="w-full"
864
+ min="0"
865
+ prevent-invalid-input
866
+ has-controls
867
+ .value=${usesPerCustomer || ''}
868
+ ?disabled=${isDisabled}
869
+ ?readonly=${isReadonly}
870
+ @change=${(evt) => {
871
+ const field = evt.currentTarget;
872
+ this.edit({ number_of_uses_allowed_per_customer: parseInt(field.value) });
873
+ }}
874
+ >
875
+ </vaadin-integer-field>
876
+ </div>
877
+
878
+ <div
879
+ class=${classMap({
880
+ 'transition-colors text-xs leading-s': true,
881
+ 'text-secondary': !isDisabled,
882
+ 'text-disabled': isDisabled,
883
+ })}
884
+ >
885
+ <foxy-i18n
886
+ options=${JSON.stringify({ count: usesPerCoupon })}
887
+ lang=${this.lang}
888
+ key="uses_per_coupon_summary${usesPerCoupon ? '' : '_0'}"
889
+ ns=${this.ns}
890
+ >
891
+ </foxy-i18n>
892
+
893
+ <foxy-i18n
894
+ options=${JSON.stringify({ count: usesPerCouponCode })}
895
+ lang=${this.lang}
896
+ key="uses_per_coupon_code_summary${usesPerCouponCode ? '' : '_0'}"
897
+ ns=${this.ns}
898
+ >
899
+ </foxy-i18n>
900
+
901
+ <foxy-i18n
902
+ options=${JSON.stringify({ count: usesPerCustomer })}
903
+ lang=${this.lang}
904
+ key="uses_per_customer_summary${usesPerCustomer ? '' : '_0'}"
905
+ ns=${this.ns}
906
+ >
907
+ </foxy-i18n>
908
+ </div>
909
+ </div>
910
+
911
+ ${this.renderTemplateOrSlot('usage:after')}
912
+ `;
913
+ }
914
+ __renderProductRestrictions() {
915
+ var _a;
916
+ const scope = 'product-restrictions';
917
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches(scope, true);
918
+ const isReadonly = this.readonlySelector.matches(scope, true);
919
+ const restrictions = (_a = this.form.product_code_restrictions) !== null && _a !== void 0 ? _a : '';
920
+ const groups = [
921
+ { header: 'allow', items: [] },
922
+ { header: 'block', items: [] },
923
+ ];
924
+ if (restrictions) {
925
+ restrictions.split(',').forEach(value => {
926
+ const isBlocklistValue = value.startsWith('-');
927
+ const target = isBlocklistValue ? 1 : 0;
928
+ const label = isBlocklistValue ? value.substring(1) : value;
929
+ groups[target].items.push({ label, value });
930
+ });
931
+ }
932
+ return html `
933
+ <div>
934
+ ${this.renderTemplateOrSlot('product-restrictions:before')}
935
+
936
+ <div class="space-y-s">
937
+ <x-group frame>
938
+ <foxy-i18n
939
+ class=${isDisabled ? 'text-disabled' : 'text-secondary'}
940
+ slot="header"
941
+ lang=${this.lang}
942
+ key="product_restrictions"
943
+ ns=${this.ns}
944
+ >
945
+ </foxy-i18n>
946
+
947
+ <div class="grid sm-grid-cols-2 bg-contrast-10" style="gap: 1px">
948
+ ${groups.map((group, index) => {
949
+ return html `
950
+ <x-group class="bg-base pt-m">
951
+ <foxy-i18n
952
+ class=${isDisabled ? 'text-disabled' : 'text-tertiary'}
953
+ slot="header"
954
+ lang=${this.lang}
955
+ key=${group.header}
956
+ ns=${this.ns}
957
+ >
958
+ </foxy-i18n>
959
+
960
+ <x-editable-list
961
+ lang=${this.lang}
962
+ ns=${this.ns}
963
+ ?disabled=${isDisabled}
964
+ ?readonly=${isReadonly}
965
+ .items=${group.items}
966
+ @change=${(evt) => {
967
+ const newItemsByGroup = [
968
+ index === 0 ? evt.currentTarget.items : groups[0].items,
969
+ index === 1 ? evt.currentTarget.items : groups[1].items,
970
+ ];
971
+ const newSanitizedItemsByGroup = newItemsByGroup
972
+ .map(list => list.map(v => v.value.replace(/^[\s-]*/, '').trimEnd()))
973
+ .map(list => list.filter(v => !!v))
974
+ .map(list => Array.from(new Set(list)));
975
+ const newRestrictions = newSanitizedItemsByGroup[0]
976
+ .concat(newSanitizedItemsByGroup[1].map(v => `-${v}`))
977
+ .join(',');
978
+ this.edit({ product_code_restrictions: newRestrictions });
979
+ }}
980
+ >
981
+ </x-editable-list>
982
+ </x-group>
983
+ `;
984
+ })}
985
+ </div>
986
+ </x-group>
987
+
988
+ <foxy-i18n
989
+ class=${classMap({
990
+ 'block text-xs leading-s transition-colors': true,
991
+ 'text-secondary': !isDisabled,
992
+ 'text-disabled': isDisabled,
993
+ })}
994
+ lang=${this.lang}
995
+ key="product_restrictions_explainer"
996
+ ns=${this.ns}
997
+ >
998
+ </foxy-i18n>
999
+ </div>
1000
+
1001
+ ${this.renderTemplateOrSlot('product-restrictions:after')}
1002
+ </div>
1003
+ `;
1004
+ }
1005
+ __renderCategoryRestrictions() {
1006
+ var _a;
1007
+ const scope = 'category-restrictions';
1008
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches(scope, true);
1009
+ const isReadonly = this.readonlySelector.matches(scope, true);
1010
+ return html `
1011
+ ${this.renderTemplateOrSlot('category-restrictions:before')}
1012
+
1013
+ <div class="space-y-xs">
1014
+ <foxy-pagination
1015
+ first=${this.__itemCategories}
1016
+ lang=${this.lang}
1017
+ ns=${this.ns}
1018
+ ?disabled=${isDisabled}
1019
+ >
1020
+ <foxy-i18n
1021
+ class="block text-s font-medium text-secondary leading-none mb-s"
1022
+ lang=${this.lang}
1023
+ key="category_restrictions"
1024
+ ns=${this.ns}
1025
+ >
1026
+ </foxy-i18n>
1027
+
1028
+ <x-category-restrictions-page
1029
+ coupon-item-categories=${ifDefined((_a = this.data) === null || _a === void 0 ? void 0 : _a._links['fx:coupon_item_categories'].href)}
1030
+ coupon=${this.href}
1031
+ class="border border-contrast-10 rounded-t-l rounded-b-l mb-s"
1032
+ group=${this.group}
1033
+ lang=${this.lang}
1034
+ ns=${this.ns}
1035
+ ?disabled=${isDisabled}
1036
+ ?readonly=${isReadonly}
1037
+ >
1038
+ </x-category-restrictions-page>
1039
+ </foxy-pagination>
1040
+
1041
+ <foxy-i18n
1042
+ class="block text-xs leading-s text-tertiary"
1043
+ lang=${this.lang}
1044
+ key="category_restrictions_helper_text"
1045
+ ns=${this.ns}
1046
+ >
1047
+ </foxy-i18n>
1048
+ </div>
1049
+
1050
+ ${this.renderTemplateOrSlot('category-restrictions:after')}
1051
+ `;
1052
+ }
1053
+ __renderOptions() {
1054
+ const isDisabled = !this.in('idle') || this.disabledSelector.matches('options', true);
1055
+ const isReadonly = this.readonlySelector.matches('options', true);
1056
+ const options = [
1057
+ { param: 'multiple_codes_allowed' },
1058
+ { param: 'combinable' },
1059
+ { param: 'exclude_category_discounts', label: 'combine_with_category_discounts', flip: true },
1060
+ { param: 'exclude_line_item_discounts', label: 'combine_with_line_discounts', flip: true },
1061
+ { param: 'is_taxable', label: 'apply_taxes_before_coupon' },
1062
+ ];
1063
+ return html `
1064
+ <div>
1065
+ ${this.renderTemplateOrSlot('options:before')}
1066
+
1067
+ <x-group frame>
1068
+ <foxy-i18n
1069
+ class="transition-colors ${isDisabled ? 'text-disabled' : 'text-secondary'}"
1070
+ slot="header"
1071
+ lang=${this.lang}
1072
+ key="option_plural"
1073
+ ns=${this.ns}
1074
+ >
1075
+ </foxy-i18n>
1076
+
1077
+ ${options.map(option => {
1078
+ var _a;
1079
+ const value = this.form[option.param];
1080
+ const label = (_a = option.label) !== null && _a !== void 0 ? _a : option.param;
1081
+ const color = isDisabled ? 'text-disabled' : 'text-secondary';
1082
+ return html `
1083
+ <x-checkbox
1084
+ ?disabled=${isDisabled}
1085
+ ?readonly=${isReadonly}
1086
+ ?checked=${option.flip ? !value : value}
1087
+ class="m-m"
1088
+ @change=${(evt) => {
1089
+ this.edit({ [option.param]: option.flip ? !evt.detail : evt.detail });
1090
+ }}
1091
+ >
1092
+ <div class="flex flex-col">
1093
+ <foxy-i18n lang=${this.lang} key=${label} ns=${this.ns}></foxy-i18n>
1094
+ <foxy-i18n
1095
+ class="transition-colors text-xs leading-s ${color}"
1096
+ lang=${this.lang}
1097
+ key="${label}_explainer"
1098
+ ns=${this.ns}
1099
+ >
1100
+ </foxy-i18n>
1101
+ </div>
1102
+ </x-checkbox>
1103
+
1104
+ <div style="margin-left: calc(1.125rem + (var(--lumo-space-m) * 2))">
1105
+ <div class="border-b border-contrast-10"></div>
1106
+ </div>
1107
+ `;
1108
+ })}
1109
+
1110
+ <x-checkbox
1111
+ ?disabled=${isDisabled}
1112
+ ?readonly=${isReadonly}
1113
+ ?checked=${this.form.start_date || this.form.end_date}
1114
+ class="m-m"
1115
+ @change=${(evt) => {
1116
+ if (evt instanceof CheckboxChangeEvent) {
1117
+ let startDate = null;
1118
+ let endDate = null;
1119
+ if (evt.detail) {
1120
+ const today = Date.now();
1121
+ const oneMonthFromToday = new Date(today).setMonth(new Date().getMonth() + 1);
1122
+ startDate = serializeDate(new Date(today));
1123
+ endDate = serializeDate(new Date(oneMonthFromToday));
1124
+ }
1125
+ // TODO: remove ts directive when sdk types are fixed
1126
+ // @ts-expect-error sdk types don't include null
1127
+ this.edit({ start_date: startDate, end_date: endDate });
1128
+ }
1129
+ }}
1130
+ >
1131
+ <div class="flex flex-col">
1132
+ <foxy-i18n lang=${this.lang} key="set_time_constraints" ns=${this.ns}></foxy-i18n>
1133
+ <foxy-i18n
1134
+ class="text-xs leading-s ${isDisabled ? 'text-disabled' : 'text-secondary'}"
1135
+ lang=${this.lang}
1136
+ key="set_time_constraints_explainer"
1137
+ ns=${this.ns}
1138
+ >
1139
+ </foxy-i18n>
1140
+ </div>
1141
+
1142
+ ${this.form.start_date || this.form.end_date
1143
+ ? html `
1144
+ <div class="grid grid-cols-2 gap-m mt-m" slot="content">
1145
+ ${['start_date', 'end_date'].map(property => {
1146
+ const formValue = this.form[property];
1147
+ const pickerValue = formValue ? serializeDate(new Date(formValue)) : '';
1148
+ return html `
1149
+ <vaadin-date-picker
1150
+ placeholder=${this.t('select')}
1151
+ label=${this.t(property)}
1152
+ clear-button-visible
1153
+ ?disabled=${isDisabled}
1154
+ ?readonly=${isReadonly}
1155
+ .value=${live(pickerValue)}
1156
+ @change=${(evt) => {
1157
+ const field = evt.currentTarget;
1158
+ this.edit({ [property]: field.value });
1159
+ }}
1160
+ >
1161
+ </vaadin-date-picker>
1162
+ `;
1163
+ })}
1164
+ </div>
1165
+ `
1166
+ : ''}
1167
+ </x-checkbox>
1168
+ </x-group>
1169
+
1170
+ ${this.renderTemplateOrSlot('options:after')}
1171
+ </div>
1172
+ `;
1173
+ }
1174
+ __renderTimestamps() {
1175
+ return html `
1176
+ <div>
1177
+ ${this.renderTemplateOrSlot('timestamps:before')}
1178
+
1179
+ <x-property-table
1180
+ data-testid="timestamps"
1181
+ .items=${['date_modified', 'date_created'].map(field => {
1182
+ var _a;
1183
+ return ({
1184
+ name: this.t(field),
1185
+ value: ((_a = this.data) === null || _a === void 0 ? void 0 : _a[field]) ? this.t('date', { value: new Date(this.data[field]) })
1186
+ : '',
1187
+ });
1188
+ })}
1189
+ >
1190
+ </x-property-table>
1191
+
1192
+ ${this.renderTemplateOrSlot('timestamps:after')}
1193
+ </div>
1194
+ `;
1195
+ }
1196
+ __renderCreate() {
1197
+ const isCleanTemplateInvalid = this.in({ idle: { template: { clean: 'invalid' } } });
1198
+ const isDirtyTemplateInvalid = this.in({ idle: { template: { dirty: 'invalid' } } });
1199
+ const isCleanSnapshotInvalid = this.in({ idle: { snapshot: { clean: 'invalid' } } });
1200
+ const isDirtySnapshotInvalid = this.in({ idle: { snapshot: { dirty: 'invalid' } } });
1201
+ const isTemplateInvalid = isCleanTemplateInvalid || isDirtyTemplateInvalid;
1202
+ const isSnaphotInvalid = isCleanSnapshotInvalid || isDirtySnapshotInvalid;
1203
+ const isInvalid = isTemplateInvalid || isSnaphotInvalid;
1204
+ const isBusy = this.in('busy');
1205
+ return html `
1206
+ <div>
1207
+ ${this.renderTemplateOrSlot('create:before')}
1208
+
1209
+ <vaadin-button
1210
+ data-testid="create"
1211
+ class="w-full"
1212
+ theme="primary success"
1213
+ ?disabled=${isBusy || isInvalid || this.disabledSelector.matches('create', true)}
1214
+ @click=${this.submit}
1215
+ >
1216
+ <foxy-i18n ns=${this.ns} key="create" lang=${this.lang}></foxy-i18n>
1217
+ </vaadin-button>
1218
+
1219
+ ${this.renderTemplateOrSlot('create:after')}
1220
+ </div>
1221
+ `;
1222
+ }
1223
+ __renderDelete() {
1224
+ return html `
1225
+ <div>
1226
+ <foxy-internal-confirm-dialog
1227
+ data-testid="confirm"
1228
+ message="delete_prompt"
1229
+ confirm="delete"
1230
+ cancel="cancel"
1231
+ header="delete"
1232
+ theme="primary error"
1233
+ lang=${this.lang}
1234
+ ns=${this.ns}
1235
+ id="confirm"
1236
+ @hide=${(evt) => !evt.detail.cancelled && this.delete()}
1237
+ >
1238
+ </foxy-internal-confirm-dialog>
1239
+
1240
+ ${this.renderTemplateOrSlot('delete:before')}
1241
+
1242
+ <vaadin-button
1243
+ data-testid="delete"
1244
+ theme="primary error"
1245
+ class="w-full"
1246
+ ?disabled=${this.in('busy') || this.disabledSelector.matches('delete', true)}
1247
+ @click=${(evt) => {
1248
+ const confirm = this.renderRoot.querySelector('#confirm');
1249
+ confirm.show(evt.currentTarget);
1250
+ }}
1251
+ >
1252
+ <foxy-i18n ns=${this.ns} key="delete" lang=${this.lang}></foxy-i18n>
1253
+ </vaadin-button>
1254
+
1255
+ ${this.renderTemplateOrSlot('delete:after')}
1256
+ </div>
1257
+ `;
1258
+ }
1259
+ }
1260
+ CouponForm.__codesQueryOptions = [
1261
+ { label: 'code', path: 'code', type: Type.String },
1262
+ { label: 'used_codes', path: 'number_of_uses_to_date', type: Type.Number },
1263
+ { label: 'date_created', path: 'date_created', type: Type.Date },
1264
+ { label: 'date_modified', path: 'date_modified', type: Type.Date },
1265
+ ];
1266
+ //# sourceMappingURL=CouponForm.js.map