Passed
Push — 6.4 ( a2ab34...70d76f )
by Christian
13:23 queued 14s
created

index.ts ➔ createdComponent   C

Complexity

Conditions 10

Size

Total Lines 15
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 13
dl 0
loc 15
rs 5.9999
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like index.ts ➔ createdComponent often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import template from './sw-order-create-details.html.twig';
2
// eslint-disable-next-line max-len
3
import type {
4
    Cart,
5
    Currency,
6
    Customer,
7
    LineItem,
8
    SalesChannelContext,
9
    PromotionCodeTag,
10
    ContextSwitchParameters, CartDelivery,
11
} from '../../order.types';
12
import type CriteriaType from '../../../../core/data/criteria.data';
13
import { LineItemType } from '../../order.types';
14
import type Repository from '../../../../core/data/repository.data';
15
import { get } from '../../../../core/service/utils/object.utils';
16
17
const { Component, Mixin, State } = Shopware;
18
const { Criteria } = Shopware.Data;
19
20
// eslint-disable-next-line sw-deprecation-rules/private-feature-declarations
21
Component.register('sw-order-create-details', {
22
    template,
23
24
    inject: [
25
        'repositoryFactory',
26
        'cartStoreService',
27
    ],
28
29
    mixins: [
30
        Mixin.getByName('notification'),
31
        Mixin.getByName('cart-notification'),
32
    ],
33
34
    data(): {
35
        isLoading: boolean,
36
        showPromotionModal: boolean,
37
        promotionError: ShopwareHttpError|null,
38
        context: ContextSwitchParameters,
39
        } {
40
        return {
41
            showPromotionModal: false,
42
            promotionError: null,
43
            isLoading: false,
44
            context: {
45
                currencyId: '',
46
                paymentMethodId: '',
47
                shippingMethodId: '',
48
                languageId: '',
49
                billingAddressId: '',
50
                shippingAddressId: '',
51
            },
52
        };
53
    },
54
55
    computed: {
56
        salesChannelId(): string {
57
            return this.salesChannelContext?.salesChannel.id || '';
58
        },
59
60
        customer(): Customer | null {
61
            return State.get('swOrder').customer;
62
        },
63
64
        cart(): Cart {
65
            return State.get('swOrder').cart;
66
        },
67
68
        currency(): Currency {
69
            return State.get('swOrder').context.currency;
70
        },
71
72
        salesChannelContext(): SalesChannelContext {
73
            return State.get('swOrder').context;
74
        },
75
76
        email(): string {
77
            return this.customer?.email || '';
78
        },
79
80
        phoneNumber(): string {
81
            return this.customer?.defaultBillingAddress?.phoneNumber || '';
82
        },
83
84
        cartDelivery(): CartDelivery | null {
85
            return get(this.cart, 'deliveries[0]', null) as CartDelivery | null;
86
        },
87
88
        shippingCosts: {
89
            get(): number {
90
                return this.cartDelivery?.shippingCosts.totalPrice || 0.0;
91
            },
92
            set(value: number): void {
93
                this.modifyShippingCosts(value);
94
            },
95
        },
96
97
        deliveryDate(): string {
98
            return this.cartDelivery?.deliveryDate.earliest || '';
99
        },
100
101
        shippingMethodCriteria(): CriteriaType {
102
            const criteria = new Criteria(1, 25);
103
            criteria.addFilter(Criteria.equals('salesChannels.id', this.salesChannelId));
104
105
            return criteria;
106
        },
107
108
        paymentMethodCriteria(): CriteriaType {
109
            const criteria = new Criteria(1, 25);
110
            criteria.addFilter(Criteria.equals('salesChannels.id', this.salesChannelId));
111
            criteria.addFilter(Criteria.equals('afterOrderEnabled', 1));
112
113
            return criteria;
114
        },
115
116
        languageCriteria(): CriteriaType {
117
            const criteria = new Criteria(1, 25);
118
            criteria.addFilter(Criteria.equals('salesChannels.id', this.salesChannelId));
119
120
            return criteria;
121
        },
122
123
        currencyCriteria(): CriteriaType {
124
            const criteria = new Criteria(1, 25);
125
            criteria.addFilter(Criteria.equals('salesChannels.id', this.salesChannelId));
126
127
            return criteria;
128
        },
129
130
        currencyRepository(): Repository {
131
            return this.repositoryFactory.create('currency');
132
        },
133
134
        isCartTokenAvailable(): boolean {
135
            // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
136
            return State.getters['swOrder/isCartTokenAvailable'] as boolean;
137
        },
138
139
        hasLineItem(): boolean {
140
            return this.cart?.lineItems.filter((item: LineItem) => item.hasOwnProperty('id')).length > 0;
141
        },
142
143
        promotionCodeLineItems(): LineItem[] {
144
            return this.cart?.lineItems.filter((item: LineItem) => {
145
                return item.type === LineItemType.PROMOTION && item?.payload?.code;
146
            });
147
        },
148
149
        disabledAutoPromotion(): boolean {
150
            return State.get('swOrder').disabledAutoPromotion;
151
        },
152
153
        promotionCodeTags: {
154
            get(): PromotionCodeTag[] {
155
                return State.get('swOrder').promotionCodes;
156
            },
157
158
            set(promotionCodeTags: PromotionCodeTag[]) {
159
                State.commit('swOrder/setPromotionCodes', promotionCodeTags);
160
            },
161
        },
162
    },
163
164
    watch: {
165
        context: {
166
            deep: true,
167
            handler(): void {
168
                if (!this.customer || !this.isCartTokenAvailable) {
169
                    return;
170
                }
171
172
                this.isLoading = true;
173
                this.updateContext().finally(() => {
174
                    this.isLoading = false;
175
                });
176
            },
177
        },
178
179
        cart: {
180
            deep: true,
181
            immediate: true,
182
            handler: 'updatePromotionList',
183
        },
184
185
        promotionCodeTags: {
186
            handler: 'handlePromotionCodeTags',
187
        },
188
    },
189
190
    created() {
191
        this.createdComponent();
192
    },
193
194
    methods: {
195
        createdComponent(): void {
196
            if (!this.customer) {
197
                this.$nextTick(() => {
198
                    this.$router.push({ name: 'sw.order.create.initial' });
199
                });
200
            }
201
202
            this.context = {
203
                ...this.context,
204
                currencyId: this.salesChannelContext.context.currencyId,
205
                languageId: this.salesChannelContext.context.languageIdChain[0],
206
                shippingMethodId: this.salesChannelContext.shippingMethod.id,
207
                paymentMethodId: this.salesChannelContext.paymentMethod.id,
208
                billingAddressId: this.salesChannelContext.customer?.activeBillingAddress?.id ?? '',
209
                shippingAddressId: this.salesChannelContext.customer?.activeShippingAddress?.id ?? '',
210
            };
211
        },
212
213
        updateContext(): Promise<void> {
214
            // eslint-disable-next-line @typescript-eslint/no-unsafe-return
215
            return State.dispatch('swOrder/updateOrderContext', {
216
                context: this.context,
217
                salesChannelId: this.customer?.salesChannelId,
218
                contextToken: this.cart.token,
219
            }).then(() => {
220
                return this.loadCart();
221
            });
222
        },
223
224
        loadCart() {
225
            return State.dispatch('swOrder/getCart', {
226
                salesChannelId: this.customer?.salesChannelId,
227
                contextToken: this.cart.token,
228
            });
229
        },
230
231
        onRemoveExistingCode(item: PromotionCodeTag) {
232
            if (item.isInvalid) {
233
                this.promotionCodeTags = this.promotionCodeTags.filter((tag: PromotionCodeTag) => tag.code !== item.code);
234
235
                return Promise.resolve();
236
            }
237
238
            return this.onRemoveItems([item.discountId]);
239
        },
240
241
        onRemoveItems(lineItemKeys: string[]): Promise<void> {
242
            this.isLoading = true;
243
244
            return State.dispatch('swOrder/removeLineItems', {
245
                salesChannelId: this.customer?.salesChannelId,
246
                contextToken: this.cart.token,
247
                lineItemKeys: lineItemKeys,
248
            })
249
                .then(() => {
250
                    // Remove promotion code tag if corresponding line item removed
251
                    lineItemKeys.forEach(key => {
252
                        const removedTag = this.promotionCodeTags.find((tag: PromotionCodeTag) => tag.discountId === key);
253
254
                        if (removedTag) {
255
                            this.promotionCodeTags = this.promotionCodeTags.filter((item: PromotionCodeTag) => {
256
                                return item.discountId !== removedTag.discountId;
257
                            });
258
                        }
259
                    });
260
                }).finally(() => {
261
                    this.isLoading = false;
262
                });
263
        },
264
265
        updatePromotionList() {
266
            // Update data and isInvalid flag for each item in promotionCodeTags
267
            this.promotionCodeTags = this.promotionCodeTags.map((tag: PromotionCodeTag): PromotionCodeTag => {
268
                const matchedItem = this.promotionCodeLineItems
269
                    .find((lineItem: LineItem): boolean => lineItem.payload?.code === tag.code);
270
271
                if (matchedItem) {
272
                    return { ...matchedItem.payload, isInvalid: false } as PromotionCodeTag;
273
                }
274
275
                return { ...tag, isInvalid: true } as PromotionCodeTag;
276
            });
277
278
            // Add new items from promotionCodeLineItems which promotionCodeTags doesn't contain
279
            this.promotionCodeLineItems.forEach((lineItem: LineItem): void => {
280
                const matchedItem = this.promotionCodeTags
281
                    .find((tag: PromotionCodeTag): boolean => tag.code === lineItem.payload?.code);
282
283
                if (!matchedItem) {
284
                    this.promotionCodeTags = [
285
                        ...this.promotionCodeTags,
286
                        { ...lineItem.payload, isInvalid: false } as PromotionCodeTag,
287
                    ];
288
                }
289
            });
290
        },
291
292
        toggleAutomaticPromotions(visibility: boolean): void {
293
            this.showPromotionModal = visibility;
294
            if (visibility) {
295
                State.commit('swOrder/setDisabledAutoPromotion', true);
296
                return;
297
            }
298
299
            this.isLoading = true;
300
            void this.cartStoreService.enableAutomaticPromotions(
301
                this.cart.token,
302
                { salesChannelId: this.salesChannelId },
303
            ).then(() => {
304
                State.commit('swOrder/setDisabledAutoPromotion', false);
305
306
                return this.loadCart();
307
            }).finally(() => {
308
                this.isLoading = false;
309
            });
310
        },
311
312
        onClosePromotionModal() {
313
            this.showPromotionModal = false;
314
            State.commit('swOrder/setDisabledAutoPromotion', false);
315
        },
316
317
        onSavePromotionModal() {
318
            this.showPromotionModal = false;
319
            State.commit('swOrder/setDisabledAutoPromotion', true);
320
321
            return this.loadCart().finally(() => {
322
                this.isLoading = false;
323
            });
324
        },
325
326
        modifyShippingCosts(amount: number) {
327
            const positiveAmount = Math.abs(amount);
328
            if (!this.cartDelivery) {
329
                return;
330
            }
331
            this.cartDelivery.shippingCosts.unitPrice = positiveAmount;
332
            this.cartDelivery.shippingCosts.totalPrice = positiveAmount;
333
            this.isLoading = true;
334
335
            State.dispatch('swOrder/modifyShippingCosts', {
336
                salesChannelId: this.salesChannelId,
337
                contextToken: this.cart.token,
338
                shippingCosts: this.cartDelivery.shippingCosts,
339
            }).catch((error) => {
340
                this.$emit('error', error);
341
            }).finally(() => {
342
                this.isLoading = false;
343
            });
344
        },
345
346
        handlePromotionCodeTags(newValue: PromotionCodeTag[], oldValue: PromotionCodeTag[]) {
347
            this.promotionError = null;
348
349
            if (newValue.length < oldValue.length) {
350
                return;
351
            }
352
353
            const promotionCodeLength = this.promotionCodeTags.length;
354
            const latestTag = this.promotionCodeTags[promotionCodeLength - 1];
355
356
            if (newValue.length > oldValue.length) {
357
                void this.onSubmitCode(latestTag.code);
358
            }
359
360
            if (promotionCodeLength > 0 && latestTag.isInvalid) {
361
                this.promotionError = {
362
                    detail: this.$tc('sw-order.createBase.textInvalidPromotionCode'),
363
                } as ShopwareHttpError;
364
            }
365
        },
366
367
        onSubmitCode(code: string): Promise<void> {
368
            this.isLoading = true;
369
370
            // eslint-disable-next-line @typescript-eslint/no-unsafe-return
371
            return State.dispatch('swOrder/addPromotionCode', {
372
                salesChannelId: this.customer?.salesChannelId,
373
                contextToken: this.cart.token,
374
                code,
375
            }).finally(() => {
376
                this.isLoading = false;
377
            });
378
        },
379
    },
380
});
381