|
1
|
|
|
import camelCase from 'lodash/camelCase'; |
|
2
|
|
|
import type CriteriaType from 'src/core/data/criteria.data'; |
|
3
|
|
|
import type { Address } from 'src/core/service/api/custom-snippet.api.service'; |
|
4
|
|
|
import type { PropType } from 'vue'; |
|
5
|
|
|
import type { Entity } from '@shopware-ag/admin-extension-sdk/es/data/_internals/Entity'; |
|
6
|
|
|
import type { DragConfig } from 'src/app/directive/dragdrop.directive'; |
|
7
|
|
|
import template from './sw-settings-country-address-handling.html.twig'; |
|
8
|
|
|
import './sw-settings-country-address-handling.scss'; |
|
9
|
|
|
|
|
10
|
|
|
const { Component } = Shopware; |
|
11
|
|
|
const { Criteria } = Shopware.Data; |
|
12
|
|
|
const { cloneDeep } = Shopware.Utils.object; |
|
13
|
|
|
|
|
14
|
|
|
interface CustomerEntity extends Entity { |
|
15
|
|
|
firstName: string, |
|
16
|
|
|
lastName: string, |
|
17
|
|
|
defaultBillingAddress: Address |
|
18
|
|
|
} |
|
19
|
|
|
|
|
20
|
|
|
interface TreeItem { |
|
21
|
|
|
id: string, |
|
22
|
|
|
name: string, |
|
23
|
|
|
parentId?: string | null, |
|
24
|
|
|
} |
|
25
|
|
|
|
|
26
|
|
|
interface DragItem { |
|
27
|
|
|
index: number, |
|
28
|
|
|
linePosition?: number | null, |
|
29
|
|
|
snippet: string[] |
|
30
|
|
|
} |
|
31
|
|
|
|
|
32
|
|
|
interface CountryEntity extends Entity { |
|
33
|
|
|
forceStateInRegistration: boolean, |
|
34
|
|
|
postalCodeRequired: boolean, |
|
35
|
|
|
checkPostalCodePattern: boolean, |
|
36
|
|
|
checkAdvancedPostalCodePattern: boolean, |
|
37
|
|
|
advancedPostalCodePattern: string|null, |
|
38
|
|
|
addressFormat: Array<string[]> | [], |
|
39
|
|
|
defaultPostalCodePattern: string|null, |
|
40
|
|
|
} |
|
41
|
|
|
|
|
42
|
|
|
const DefaultAddressFormat = [ |
|
43
|
|
|
['address/company', 'symbol/dash', 'address/department'], |
|
44
|
|
|
['address/first_name', 'address/last_name'], |
|
45
|
|
|
['address/street'], |
|
46
|
|
|
['address/zipcode', 'address/city'], |
|
47
|
|
|
['address/country'], |
|
48
|
|
|
] as string[][]; |
|
49
|
|
|
|
|
50
|
|
|
/** |
|
51
|
|
|
* @private |
|
52
|
|
|
*/ |
|
53
|
|
|
Component.register('sw-settings-country-address-handling', { |
|
54
|
|
|
template, |
|
55
|
|
|
|
|
56
|
|
|
inject: ['acl', 'customSnippetApiService'], |
|
57
|
|
|
|
|
58
|
|
|
props: { |
|
59
|
|
|
country: { |
|
60
|
|
|
type: Object as PropType<CountryEntity>, |
|
61
|
|
|
required: true, |
|
62
|
|
|
}, |
|
63
|
|
|
|
|
64
|
|
|
isLoading: { |
|
65
|
|
|
type: Boolean, |
|
66
|
|
|
required: true, |
|
67
|
|
|
}, |
|
68
|
|
|
}, |
|
69
|
|
|
|
|
70
|
|
|
data(): { |
|
71
|
|
|
advancedPostalCodePattern: string | null, |
|
72
|
|
|
draggedItem: DragItem | null, |
|
73
|
|
|
droppedItem: DragItem | null, |
|
74
|
|
|
snippets: TreeItem[] | [], |
|
75
|
|
|
customerId: string | null, |
|
76
|
|
|
customer: CustomerEntity | null, |
|
77
|
|
|
isOpenModal: boolean, |
|
78
|
|
|
currentPosition: number | null, |
|
79
|
|
|
formattingAddress: string, |
|
80
|
|
|
} { |
|
81
|
|
|
return { |
|
82
|
|
|
advancedPostalCodePattern: null, |
|
83
|
|
|
draggedItem: null, |
|
84
|
|
|
droppedItem: null, |
|
85
|
|
|
snippets: [], |
|
86
|
|
|
customerId: null, |
|
87
|
|
|
customer: null, |
|
88
|
|
|
isOpenModal: false, |
|
89
|
|
|
currentPosition: null, |
|
90
|
|
|
formattingAddress: '', |
|
91
|
|
|
}; |
|
92
|
|
|
}, |
|
93
|
|
|
|
|
94
|
|
|
computed: { |
|
95
|
|
|
customerCriteria(): CriteriaType { |
|
96
|
|
|
const criteria = new Criteria(1, null); |
|
97
|
|
|
criteria |
|
98
|
|
|
.addAssociation('salutation') |
|
99
|
|
|
.addAssociation('defaultBillingAddress.country') |
|
100
|
|
|
.addAssociation('defaultBillingAddress.countryState') |
|
101
|
|
|
.addAssociation('defaultBillingAddress.salutation'); |
|
102
|
|
|
|
|
103
|
|
|
return criteria; |
|
104
|
|
|
}, |
|
105
|
|
|
|
|
106
|
|
|
dragConf(): DragConfig<DragItem> { |
|
107
|
|
|
return { |
|
108
|
|
|
delay: 200, |
|
109
|
|
|
dragGroup: 'sw-multi-snippet', |
|
110
|
|
|
validDragCls: 'is--valid-drag', |
|
111
|
|
|
// eslint-disable-next-line @typescript-eslint/unbound-method |
|
112
|
|
|
onDragStart: this.onDragStart, |
|
113
|
|
|
// eslint-disable-next-line @typescript-eslint/unbound-method |
|
114
|
|
|
onDragEnter: this.onDragEnter, |
|
115
|
|
|
// eslint-disable-next-line @typescript-eslint/unbound-method |
|
116
|
|
|
onDrop: this.onDrop, |
|
117
|
|
|
preventEvent: false, |
|
118
|
|
|
} as DragConfig<DragItem>; |
|
119
|
|
|
}, |
|
120
|
|
|
|
|
121
|
|
|
addressFormat(): Array<string[]> { |
|
122
|
|
|
return this.country.addressFormat; |
|
123
|
|
|
}, |
|
124
|
|
|
|
|
125
|
|
|
hasDefaultPostalCodePattern(): boolean { |
|
126
|
|
|
return !!this.country.defaultPostalCodePattern; |
|
127
|
|
|
}, |
|
128
|
|
|
|
|
129
|
|
|
disabledAdvancedPostalCodePattern(): boolean { |
|
130
|
|
|
if (!this.hasDefaultPostalCodePattern) { |
|
131
|
|
|
return false; |
|
132
|
|
|
} |
|
133
|
|
|
|
|
134
|
|
|
return !this.country.checkPostalCodePattern; |
|
135
|
|
|
}, |
|
136
|
|
|
}, |
|
137
|
|
|
|
|
138
|
|
|
watch: { |
|
139
|
|
|
'country.checkPostalCodePattern'(value) { |
|
140
|
|
|
if (value) { |
|
141
|
|
|
return; |
|
142
|
|
|
} |
|
143
|
|
|
|
|
144
|
|
|
this.$set(this.country, 'checkAdvancedPostalCodePattern', false); |
|
145
|
|
|
}, |
|
146
|
|
|
|
|
147
|
|
|
'country.checkAdvancedPostalCodePattern'(value) { |
|
148
|
|
|
if (value) { |
|
149
|
|
|
if (this.country.advancedPostalCodePattern && !this.advancedPostalCodePattern) { |
|
150
|
|
|
return; |
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
|
|
this.$set( |
|
154
|
|
|
this.country, 'advancedPostalCodePattern', |
|
155
|
|
|
this.advancedPostalCodePattern || this.country.defaultPostalCodePattern, |
|
156
|
|
|
); |
|
157
|
|
|
return; |
|
158
|
|
|
} |
|
159
|
|
|
|
|
160
|
|
|
if (!this.hasDefaultPostalCodePattern) { |
|
161
|
|
|
this.$set(this.country, 'checkPostalCodePattern', value); |
|
162
|
|
|
} |
|
163
|
|
|
|
|
164
|
|
|
this.advancedPostalCodePattern = this.country?.advancedPostalCodePattern ?? null; |
|
165
|
|
|
this.$set(this.country, 'advancedPostalCodePattern', null); |
|
166
|
|
|
}, |
|
167
|
|
|
|
|
168
|
|
|
'country.addressFormat'(address) { |
|
169
|
|
|
if (!address) { |
|
170
|
|
|
return; |
|
171
|
|
|
} |
|
172
|
|
|
|
|
173
|
|
|
void this.renderFormattingAddress(this.customer?.defaultBillingAddress as Address); |
|
174
|
|
|
}, |
|
175
|
|
|
}, |
|
176
|
|
|
|
|
177
|
|
|
created() { |
|
178
|
|
|
this.createdComponent(); |
|
179
|
|
|
}, |
|
180
|
|
|
|
|
181
|
|
|
methods: { |
|
182
|
|
|
createdComponent(): void { |
|
183
|
|
|
this.advancedPostalCodePattern = cloneDeep(this.country.advancedPostalCodePattern); |
|
184
|
|
|
|
|
185
|
|
|
void this.getSnippets(); |
|
186
|
|
|
}, |
|
187
|
|
|
|
|
188
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars |
|
189
|
|
|
onDragStart(dragConfig: DragConfig<DragItem>, draggedElement: Element, dragElement: Element): void { |
|
190
|
|
|
this.draggedItem = dragConfig.data; |
|
191
|
|
|
}, |
|
192
|
|
|
|
|
193
|
|
|
onDragEnter(dragData: DragItem, dropData: DragItem): void { |
|
194
|
|
|
if (!this.draggedItem) { |
|
195
|
|
|
return; |
|
196
|
|
|
} |
|
197
|
|
|
|
|
198
|
|
|
if (!dragData || !dropData) { |
|
199
|
|
|
return; |
|
200
|
|
|
} |
|
201
|
|
|
|
|
202
|
|
|
this.droppedItem = dropData; |
|
203
|
|
|
}, |
|
204
|
|
|
|
|
205
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars |
|
206
|
|
|
onDrop(dragData: DragItem, dropData: DragItem): void { |
|
207
|
|
|
if (!this.addressFormat?.length || !this.droppedItem || !this.draggedItem) { |
|
208
|
|
|
return; |
|
209
|
|
|
} |
|
210
|
|
|
|
|
211
|
|
|
if (![this.draggedItem?.index, this.droppedItem?.index] |
|
212
|
|
|
.every(position => typeof position === 'number') |
|
213
|
|
|
) { |
|
214
|
|
|
return; |
|
215
|
|
|
} |
|
216
|
|
|
|
|
217
|
|
|
this.country.addressFormat = Object.assign( |
|
218
|
|
|
[], |
|
219
|
|
|
this.country.addressFormat, |
|
220
|
|
|
{ |
|
221
|
|
|
[this.draggedItem.index]: this.country.addressFormat[this.droppedItem.index], |
|
222
|
|
|
[this.droppedItem.index]: this.country.addressFormat[this.draggedItem.index], |
|
223
|
|
|
}, |
|
224
|
|
|
); |
|
225
|
|
|
|
|
226
|
|
|
this.draggedItem = null; |
|
227
|
|
|
this.droppedItem = null; |
|
228
|
|
|
}, |
|
229
|
|
|
|
|
230
|
|
|
onDropEnd(dragPosition: number, { dragData, dropData }: { dragData: DragItem, dropData: DragItem }): void { |
|
231
|
|
|
// swap positions in different lines |
|
232
|
|
|
if ( |
|
233
|
|
|
typeof dropData?.linePosition === 'number' && |
|
234
|
|
|
typeof dragData?.linePosition === 'number' && |
|
235
|
|
|
dragData.linePosition !== dropData.linePosition |
|
236
|
|
|
) { |
|
237
|
|
|
this.$set(this.country.addressFormat[dragData.linePosition], dragData.index, dropData.snippet); |
|
238
|
|
|
this.$set(this.country.addressFormat[dropData.linePosition], dropData.index, dragData.snippet); |
|
239
|
|
|
return; |
|
240
|
|
|
} |
|
241
|
|
|
|
|
242
|
|
|
// move to another line |
|
243
|
|
|
this.$set( |
|
244
|
|
|
this.country.addressFormat, |
|
245
|
|
|
`${dropData.index}`, |
|
246
|
|
|
[...this.country.addressFormat[dropData.index], dragData.snippet], |
|
247
|
|
|
); |
|
248
|
|
|
|
|
249
|
|
|
this.country.addressFormat[dragPosition].splice(dragData.index, 1); |
|
250
|
|
|
this.$set( |
|
251
|
|
|
this.country.addressFormat, |
|
252
|
|
|
dragPosition, |
|
253
|
|
|
this.country.addressFormat[dragPosition], |
|
254
|
|
|
); |
|
255
|
|
|
}, |
|
256
|
|
|
|
|
257
|
|
|
moveToNewPosition(source: number, dest: number | null): void { |
|
258
|
|
|
if (!this.addressFormat) { |
|
259
|
|
|
return; |
|
260
|
|
|
} |
|
261
|
|
|
|
|
262
|
|
|
dest = typeof dest !== 'number' ? this.addressFormat.length - 1 : dest; |
|
263
|
|
|
const snippet = this.country.addressFormat[source]; |
|
264
|
|
|
|
|
265
|
|
|
this.$set(this.country, 'addressFormat', this.swapPosition(source, dest, [snippet]) ?? []); |
|
266
|
|
|
}, |
|
267
|
|
|
|
|
268
|
|
|
addNewLineAt(source: number, dest: string | null): void { |
|
269
|
|
|
if (!this.addressFormat?.length) { |
|
270
|
|
|
return; |
|
271
|
|
|
} |
|
272
|
|
|
|
|
273
|
|
|
const snippet = this.addressFormat[source]; |
|
274
|
|
|
const swag = dest === 'above' ? [[], snippet] : [snippet, []]; |
|
275
|
|
|
|
|
276
|
|
|
this.$set(this.country, 'addressFormat', this.swapPosition(source, source, swag) ?? []); |
|
277
|
|
|
}, |
|
278
|
|
|
|
|
279
|
|
|
swapPosition(source: number, dest: number, swag: Array<string[]>): Array<string[]>|null { |
|
280
|
|
|
if (!this.addressFormat?.length) { |
|
281
|
|
|
return null; |
|
282
|
|
|
} |
|
283
|
|
|
|
|
284
|
|
|
const newSnippets = [ |
|
285
|
|
|
...this.country.addressFormat.filter((_, key) => key !== source), |
|
286
|
|
|
]; |
|
287
|
|
|
|
|
288
|
|
|
newSnippets.splice(dest, 0, ...swag); |
|
289
|
|
|
|
|
290
|
|
|
return newSnippets; |
|
291
|
|
|
}, |
|
292
|
|
|
|
|
293
|
|
|
change(index: number, newSnippet?: string): void { |
|
294
|
|
|
if (!newSnippet) { |
|
295
|
|
|
this.$set(this.country, 'addressFormat', this.addressFormat.filter((_, key) => index !== key)); |
|
296
|
|
|
return; |
|
297
|
|
|
} |
|
298
|
|
|
|
|
299
|
|
|
this.$set(this.country.addressFormat, index, newSnippet); |
|
300
|
|
|
}, |
|
301
|
|
|
|
|
302
|
|
|
customerLabel(item: CustomerEntity): string { |
|
303
|
|
|
if (!item) { |
|
304
|
|
|
return ''; |
|
305
|
|
|
} |
|
306
|
|
|
|
|
307
|
|
|
return `${item.firstName}, ${item.lastName}`; |
|
308
|
|
|
}, |
|
309
|
|
|
|
|
310
|
|
|
onChangeCustomer(customerId: string, customer: CustomerEntity): void { |
|
311
|
|
|
this.customer = null; |
|
312
|
|
|
if (!customerId || !customer) { |
|
313
|
|
|
return; |
|
314
|
|
|
} |
|
315
|
|
|
|
|
316
|
|
|
this.customer = customer; |
|
317
|
|
|
|
|
318
|
|
|
void this.renderFormattingAddress(this.customer.defaultBillingAddress); |
|
319
|
|
|
}, |
|
320
|
|
|
|
|
321
|
|
|
resetMarkup(): void { |
|
322
|
|
|
this.$set(this.country, 'addressFormat', cloneDeep(DefaultAddressFormat)); |
|
323
|
|
|
}, |
|
324
|
|
|
|
|
325
|
|
|
openSnippetModal(position: number) { |
|
326
|
|
|
this.isOpenModal = true; |
|
327
|
|
|
this.currentPosition = position; |
|
328
|
|
|
}, |
|
329
|
|
|
|
|
330
|
|
|
onCloseModal() { |
|
331
|
|
|
this.currentPosition = null; |
|
332
|
|
|
this.isOpenModal = false; |
|
333
|
|
|
}, |
|
334
|
|
|
|
|
335
|
|
|
getSnippets(): Promise<unknown> { |
|
336
|
|
|
return this.customSnippetApiService.snippets().then((response) => { |
|
337
|
|
|
const snippets = (response as { data: string[] }).data; |
|
338
|
|
|
|
|
339
|
|
|
this.snippets = snippets?.map((snippet: string) => { |
|
340
|
|
|
return { |
|
341
|
|
|
id: snippet, |
|
342
|
|
|
name: this.getLabelProperty(snippet), |
|
343
|
|
|
}; |
|
344
|
|
|
}); |
|
345
|
|
|
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
346
|
|
|
}).catch(() => {}); |
|
347
|
|
|
}, |
|
348
|
|
|
|
|
349
|
|
|
renderFormattingAddress(address?: Address): Promise<unknown> { |
|
350
|
|
|
if (!address) { |
|
351
|
|
|
this.formattingAddress = ''; |
|
352
|
|
|
return Promise.resolve(); |
|
353
|
|
|
} |
|
354
|
|
|
|
|
355
|
|
|
return this.customSnippetApiService |
|
356
|
|
|
.render(address, this.country.addressFormat) |
|
357
|
|
|
.then((res) => { |
|
358
|
|
|
const { rendered } = (res as { rendered: string}); |
|
359
|
|
|
|
|
360
|
|
|
this.formattingAddress = rendered; |
|
361
|
|
|
}); |
|
362
|
|
|
}, |
|
363
|
|
|
|
|
364
|
|
|
getLabelProperty(value: string): string { |
|
365
|
|
|
const string = value.split('/').map((item: string) => camelCase(item)).join('.'); |
|
366
|
|
|
|
|
367
|
|
|
return this.$te(`sw-custom-snippet.${string}`) ? this.$tc(`sw-custom-snippet.${string}`) : value; |
|
368
|
|
|
}, |
|
369
|
|
|
}, |
|
370
|
|
|
}); |
|
371
|
|
|
|