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

index.ts ➔ getSnippetsTree   C

Complexity

Conditions 8

Size

Total Lines 73
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 60
c 0
b 0
f 0
dl 0
loc 73
rs 6.4424

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
import type { PropType } from 'vue';
2
import template from './sw-settings-country-new-snippet-modal.html.twig';
3
import './sw-settings-country-new-snippet-modal.scss';
4
5
const { Component } = Shopware;
6
const utils = Shopware.Utils;
7
8
interface Selection {
9
    id: string,
10
    name: string,
11
    parentId?: string | null,
12
}
13
14
interface TreeItem {
15
    id: string,
16
    name: string,
17
    parentId?: string | null,
18
    childCount?: number,
19
    children: {
20
        [key: string]: TreeItem
21
    }
22
}
23
24
/**
25
 * @private
26
 */
27
Component.register('sw-settings-country-new-snippet-modal', {
28
    template,
29
30
    props: {
31
        selections: {
32
            type: Array as PropType<Selection[]>,
33
            required: false,
34
            default: () => [],
35
        },
36
37
        currentPosition: {
38
            type: Number,
39
            required: true,
40
        },
41
42
        addressFormat: {
43
            type: Array as PropType<Array<string[]>>,
44
            required: true,
45
        },
46
47
        disabled: {
48
            type: Boolean,
49
            required: false,
50
            default: false,
51
        },
52
53
        getLabelProperty: {
54
            type: Function,
55
            required: false,
56
            default: (value: string) => value,
57
        },
58
    },
59
60
    data(): {
61
        searchTerm: string,
62
        isLoading: boolean,
63
        searchResults: TreeItem[] | null,
64
        activeFocusId: string | null,
65
        } {
66
        return {
67
            searchTerm: '',
68
            isLoading: false,
69
            searchResults: null,
70
            activeFocusId: null,
71
        };
72
    },
73
74
    computed: {
75
        selection(): string[] {
76
            return this.addressFormat[this.currentPosition];
77
        },
78
    },
79
80
    watch: {
81
        activeFocusId: {
82
            immediate: true,
83
            handler(value) {
84
                // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
85
                this.$route.params.snippet = value;
86
            },
87
        },
88
    },
89
90
    created() {
91
        this.createdComponent();
92
    },
93
94
    methods: {
95
        createdComponent() {
96
            this.getSnippetsTree(this.selections);
97
        },
98
99
        onCloseModal() {
100
            this.$emit('modal-close');
101
        },
102
103
        addElement(data: Selection) {
104
            this.addressFormat[this.currentPosition].push(data.id.replace('.', '/'));
105
106
            this.$emit('change', this.currentPosition, this.addressFormat[this.currentPosition]);
107
        },
108
109
        debouncedSearch: utils.debounce(function updateSnippets(this: $TSFixMe): void {
110
            // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
111
            if (!this.searchTerm) {
112
                // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
113
                this.getSnippetsTree(this.selections);
114
                return;
115
            }
116
117
            // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
118
            this.search();
119
        }, 750),
120
121
        search(): void {
122
            this.activeFocusId = null;
123
124
            const keyWords = this.searchTerm.split(/[\W_]+/ig);
125
126
            if (!keyWords) {
127
                return;
128
            }
129
130
            const results = this.selections.filter(
131
                item => keyWords.every(key => item.name.toLowerCase().includes(key.toLowerCase())),
132
            );
133
134
            if (results.length === 0) {
135
                return;
136
            }
137
138
            this.activeFocusId = results[0].id;
139
            this.getSnippetsTree(results);
140
        },
141
142
        getSnippetsTree(selections: Selection[]): void {
143
            const mappedObj = {};
144
145
            const generate = (
146
                currentIndex: number,
147
                argument: { keyWords: string[], name: string },
148
                result: { [key: string]: TreeItem },
149
            ) => {
150
                const { keyWords, name } = argument;
151
                const currentKey = keyWords[currentIndex];
152
153
                // next key is child of current key
154
                const nextKey = keyWords[currentIndex + 1];
155
156
                result[currentKey] = result[currentKey] || {
157
                    id: currentKey,
158
                    name,
159
                    parentId: null,
160
                    children: {},
161
                };
162
163
                if (!nextKey) {
164
                    return;
165
                }
166
167
                // Put next key into children of current key
168
                result[currentKey].children[nextKey] = result[currentKey]?.children[nextKey] || {
169
                    id: `${result[currentKey].id}.${nextKey}`,
170
                    name,
171
                    parentId: result[currentKey].id,
172
                    children: {},
173
                };
174
175
                generate(currentIndex + 1, { keyWords, name }, result[currentKey].children);
176
            };
177
178
            const convertTreeToArray = (nodes: TreeItem[], output: TreeItem[] = []) => {
179
                const getName = ({ parentId = null, id, children, name }: TreeItem): string => {
180
                    const [eventName] = parentId ? id.split('.').reverse() : [id];
181
182
                    // Replace '_' or '-' to blank space.
183
                    return !Object.values(children).length ? name : eventName.replace(/_|-/g, ' ');
184
                };
185
186
                nodes.forEach(node => {
187
                    const children = node.children ? Object.values(node.children) : [];
188
                    output.push({
189
                        id: node.id,
190
                        name: getName(node),
191
                        childCount: children.length,
192
                        parentId: node.parentId,
193
                        children: {},
194
                    });
195
196
                    if (children.length > 0) {
197
                        output = convertTreeToArray(children, output);
198
                    }
199
                });
200
201
                return output;
202
            };
203
204
            selections.forEach(snippet => {
205
                const keyWords = snippet.id.split('/');
206
                if (keyWords.length === 0) {
207
                    return;
208
                }
209
210
                generate(0, { keyWords, ...snippet }, mappedObj);
211
            });
212
213
            this.searchResults = convertTreeToArray(Object.values(mappedObj));
214
        },
215
216
        onClickDismiss(index: number) {
217
            this.$emit(
218
                'change',
219
                this.currentPosition,
220
                this.addressFormat[this.currentPosition].filter((_, key) => key !== index),
221
            );
222
        },
223
    },
224
});
225