@webitel/ui-sdk 24.10.31 → 24.10.33

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-sdk",
3
- "version": "24.10.31",
3
+ "version": "24.10.33",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "dev": "vite",
@@ -0,0 +1,12 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import WtIntersectionObserver from '../wt-intersection-observer.vue';
3
+
4
+ describe('WtIntersectionObserver', () => {
5
+ const next = () => true;
6
+ it('renders a component', () => {
7
+ const wrapper = shallowMount(WtIntersectionObserver, {
8
+ props: { next }
9
+ });
10
+ expect(wrapper.exists()).toBe(true);
11
+ });
12
+ });
@@ -0,0 +1,56 @@
1
+ <template>
2
+ <wt-loader
3
+ v-if="loading"
4
+ size="sm"
5
+ />
6
+ <div ref="intersectionTarget" />
7
+ </template>
8
+
9
+ <script setup>
10
+ import { useIntersectionObserver } from '@vueuse/core';
11
+ import { onMounted, onUnmounted, ref } from 'vue';
12
+
13
+ const props = defineProps({
14
+ next: {
15
+ type: Function,
16
+ required: true,
17
+ },
18
+ loading: {
19
+ type: Boolean,
20
+ default: false,
21
+ },
22
+ });
23
+
24
+ const emit = defineEmits([
25
+ 'next',
26
+ ]);
27
+
28
+ const intersectionTarget = ref(null);
29
+
30
+ let stopObs;
31
+
32
+ onMounted(() => {
33
+ /**
34
+ *
35
+ * Note, observer triggers at init, so it should be used also as init function
36
+ * however, current filters module version is initializing list by itself, so we need to refactor filters ASAP
37
+ */
38
+ const { stop } = useIntersectionObserver(intersectionTarget.value, ([{ isIntersecting }]) => {
39
+ if (isIntersecting && props.next) {
40
+ emit('next');
41
+ }
42
+ });
43
+
44
+ stopObs = stop;
45
+ });
46
+
47
+ onUnmounted(() => {
48
+ stopObs();
49
+ });
50
+ </script>
51
+
52
+ <style scoped lang="scss">
53
+ .wt-loader {
54
+ margin: var(--spacing-lg) auto;
55
+ }
56
+ </style>
@@ -1,6 +1,17 @@
1
- import { localStorageGetter, queryGetter, valueGetter } from '../scripts/getters/index.js';
2
- import { localStorageRestore, queryRestore } from '../scripts/restores/index.js';
3
- import { localStorageSetter, querySetter, valueSetter } from '../scripts/setters/index.js';
1
+ import {
2
+ localStorageGetter,
3
+ queryGetter,
4
+ valueGetter,
5
+ } from '../scripts/getters/index.js';
6
+ import {
7
+ localStorageRestore,
8
+ queryRestore,
9
+ } from '../scripts/restores/index.js';
10
+ import {
11
+ localStorageSetter,
12
+ querySetter,
13
+ valueSetter,
14
+ } from '../scripts/setters/index.js';
4
15
 
5
16
  const convertGetterArray = (context) => (getters) => {
6
17
  const availableGetters = ['value', 'query', 'localStorage'];
@@ -88,8 +99,8 @@ export default class BaseFilterSchema {
88
99
  {
89
100
  name,
90
101
  value,
91
- defaultValue,
92
102
  multiple,
103
+ defaultValue: defaultValue || value,
93
104
  },
94
105
  rest,
95
106
  );
@@ -97,8 +108,6 @@ export default class BaseFilterSchema {
97
108
  this.setupGetters(get);
98
109
  this.setupSetters(set);
99
110
  this.setupRestores(restore);
100
-
101
- return this;
102
111
  }
103
112
 
104
113
  setupGetters(getters) {
@@ -0,0 +1,118 @@
1
+ <template>
2
+ <wt-select
3
+ :close-on-select="!filterSchema.multiple"
4
+ :multiple="filterSchema.multiple"
5
+ :options="options"
6
+ :search-method="search"
7
+ :track-by="trackBy"
8
+ :value="value"
9
+ v-bind="attrs"
10
+ @input="setValue"
11
+ />
12
+ </template>
13
+
14
+ <script setup>
15
+
16
+ import { computed, reactive, useAttrs } from 'vue';
17
+ import { useI18n } from 'vue-i18n';
18
+ import { useStore } from 'vuex';
19
+ import isEmpty from '../../../scripts/isEmpty.js';
20
+ import getNamespacedState from '../../../store/helpers/getNamespacedState.js';
21
+
22
+ const props = defineProps({
23
+ namespace: {
24
+ type: String,
25
+ required: true,
26
+ },
27
+ filterQuery: {
28
+ type: String,
29
+ required: true,
30
+ },
31
+ });
32
+
33
+ const attrs = useAttrs();
34
+ const store = useStore();
35
+ const { t } = useI18n();
36
+
37
+ const filterSchema = computed(() => getNamespacedState(store.state, props.namespace)[props.filterQuery]);
38
+
39
+ const trackBy = computed(() => {
40
+ if (filterSchema.value.storedProp !== undefined) {
41
+ return filterSchema.value.storedProp;
42
+ }
43
+
44
+ if (filterSchema.value.search) {
45
+ return 'id';
46
+ }
47
+
48
+ if (filterSchema.value.options) {
49
+ return 'value';
50
+ }
51
+
52
+ return 'id';
53
+ });
54
+
55
+ const rawValue = computed(() => store.getters[`${props.namespace}/FILTER_${props.filterQuery}`]);
56
+
57
+ const cachedSearchOpts = reactive({});
58
+
59
+ const search = filterSchema.value.search && (async (selectParams) => {
60
+ const params = {
61
+ ...selectParams,
62
+ };
63
+
64
+ if (trackBy.value === 'id') {
65
+ params.ids = Array.isArray(rawValue.value) ? rawValue.value : [rawValue.value];
66
+ }
67
+
68
+ const { items, ...rest } = await filterSchema.value.search(params);
69
+
70
+ items.forEach((item) => {
71
+ cachedSearchOpts[item.id] = item;
72
+ });
73
+
74
+ return {
75
+ items,
76
+ ...rest,
77
+ };
78
+ });
79
+
80
+ const options = computed(() => {
81
+ const options = filterSchema.value.options;
82
+
83
+ return options;
84
+ });
85
+
86
+ const value = computed(() => {
87
+ if (options.value) {
88
+ if (filterSchema.value.multiple) {
89
+ return options.value.filter((option) => rawValue.value.includes(option[trackBy.value]));
90
+ }
91
+
92
+ return options.value.find((option) => option[trackBy.value] === rawValue.value);
93
+ }
94
+
95
+ if (filterSchema.value.search) {
96
+ if (filterSchema.value.multiple) {
97
+ return rawValue.value.map((value) => cachedSearchOpts[value]);
98
+ }
99
+
100
+ return cachedSearchOpts[rawValue.value];
101
+ }
102
+
103
+ return rawValue.value;
104
+ });
105
+
106
+ const setValue = (value) => {
107
+ const payload = {
108
+ value: isEmpty(value) ? value : value[trackBy.value],
109
+ name: props.filterQuery,
110
+ };
111
+
112
+ return store.dispatch(`${props.namespace}/SET_FILTER`, payload);
113
+ };
114
+ </script>
115
+
116
+ <style scoped>
117
+
118
+ </style>
@@ -8,14 +8,12 @@ import FilterEvent from '../enums/FilterEvent.enum.js';
8
8
  export default class FiltersStoreModule extends BaseStoreModule {
9
9
  state = {
10
10
  _emitter: mitt(),
11
- _requireRouter: false,
12
11
  };
13
12
 
14
13
  getters = {
15
14
  ROUTER: (state, g, rootState) => {
16
- if (!state._requireRouter) return null;
17
15
  if (rootState.router === undefined) {
18
- throw new Error(
16
+ console.warn(
19
17
  '"rootState.router" is needed for filters to work properly.' +
20
18
  ' Please, provide to root state, or setup it in filters module as getter "ROUTER"',
21
19
  );
@@ -36,10 +34,6 @@ export default class FiltersStoreModule extends BaseStoreModule {
36
34
 
37
35
  if (!filter) throw new Error(`Unknown filter: ${filterName}`);
38
36
 
39
- if (state._requireRouter && !getters.ROUTER) {
40
- throw new Error(`Router is required for filter: ${filterName}`);
41
- }
42
-
43
37
  return filter.get({
44
38
  router: getters.ROUTER,
45
39
  });
@@ -137,13 +131,15 @@ export default class FiltersStoreModule extends BaseStoreModule {
137
131
 
138
132
  // clean up query params
139
133
  const router = context.getters.ROUTER;
140
- const query = Object.entries(router.currentRoute.query)
141
- .reduce((filteredQuery, [qKey, qValue]) => {
142
- if (context.state[qKey]) {
143
- return filteredQuery;
144
- }
145
- return { ...filteredQuery, [qKey]: qValue };
146
- }, {});
134
+ const query = Object.entries(router.currentRoute.query).reduce(
135
+ (filteredQuery, [qKey, qValue]) => {
136
+ if (context.state[qKey]) {
137
+ return filteredQuery;
138
+ }
139
+ return { ...filteredQuery, [qKey]: qValue };
140
+ },
141
+ {},
142
+ );
147
143
 
148
144
  await router.push({
149
145
  ...router.currentRoute,
@@ -167,26 +163,22 @@ export default class FiltersStoreModule extends BaseStoreModule {
167
163
  },
168
164
 
169
165
  EMIT: async (context, { event, payload }) => {
170
- return new Promise(async (resolve, reject) => {
171
- const wildcardListeners = context.state._emitter.all.get('*');
172
- const eventListeners = context.state._emitter.all.get(event);
166
+ const wildcardListeners = context.state._emitter.all.get('*');
167
+ const eventListeners = context.state._emitter.all.get(event);
173
168
 
174
- const listeners = [...(wildcardListeners || []), ...(eventListeners || [])];
169
+ const listeners = [
170
+ ...(wildcardListeners || []),
171
+ ...(eventListeners || []),
172
+ ];
175
173
 
176
- if (!listeners) {
177
- console.info(`No listeners for ${event} event`);
178
- resolve();
179
- }
174
+ if (!listeners) {
175
+ console.info(`No listeners for ${event} event`);
176
+ return;
177
+ }
180
178
 
181
- try {
182
- for (const listener of listeners) {
183
- await listener({ event, payload });
184
- }
185
- resolve();
186
- } catch (err) {
187
- reject(err);
188
- }
189
- });
179
+ for (const listener of listeners) {
180
+ await listener({ event, payload });
181
+ }
190
182
  },
191
183
  };
192
184
 
@@ -198,13 +190,13 @@ export default class FiltersStoreModule extends BaseStoreModule {
198
190
 
199
191
  addFilter(filter) {
200
192
  const setup = (filter) => {
201
- const stateFilter = new BaseFilterSchema(filter);
202
- if (stateFilter.requireRouter) this.state._requireRouter = true;
203
- this.state[filter.name] = stateFilter;
193
+ this.state[filter.name] = new BaseFilterSchema(filter);
194
+
204
195
  this.getters[`FILTER_${filter.name}`] = (state, getters) => {
205
196
  // if is used as watcher for getter to recompute,
206
197
  // because GET_FILTER is function ==> it's not reactive
207
- if (state[filter.name].value) {}
198
+ if (state[filter.name].value) {
199
+ }
208
200
  return getters.GET_FILTER(filter.name);
209
201
  };
210
202
  };