Passed
Push — trunk ( c1976e...a42427 )
by Christian
12:40 queued 13s
created

index.ts ➔ addNewLineAt   B

Complexity

Conditions 6

Size

Total Lines 10
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 9
c 0
b 0
f 0
dl 0
loc 10
rs 8.6666
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