@webitel/ui-sdk 24.4.39 → 24.6.1

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.
Files changed (46) hide show
  1. package/dist/ui-sdk.css +1 -1
  2. package/dist/ui-sdk.mjs +3439 -3353
  3. package/dist/ui-sdk.umd.js +11 -11
  4. package/package.json +4 -6
  5. package/src/components/transitions/wt-expand-transition.vue +63 -4
  6. package/src/components/wt-button/wt-button.vue +42 -6
  7. package/src/components/wt-expansion-panel/wt-expansion-panel.vue +0 -1
  8. package/src/components/wt-item-link/wt-item-link.vue +39 -9
  9. package/src/components/wt-player/wt-player.vue +8 -20
  10. package/src/components/wt-popup/__tests__/WtPopup.spec.js +5 -9
  11. package/src/components/wt-popup/_variables.scss +5 -0
  12. package/src/components/wt-popup/wt-popup.vue +88 -39
  13. package/src/components/wt-table/wt-table.vue +41 -6
  14. package/src/locale/en/en.js +0 -1
  15. package/src/locale/ru/ru.js +0 -1
  16. package/src/locale/ua/ua.js +0 -1
  17. package/src/modules/AuditForm/components/questions/options/__tests__/audit-form-question-options-write-row.spec.js +1 -1
  18. package/src/modules/AuditForm/components/questions/options/audit-form-question-options-write-row.vue +3 -15
  19. package/src/modules/AuditForm/components/questions/score/audit-form-question-score.vue +3 -6
  20. package/src/modules/Filters/classes/BaseFilterSchema.js +140 -7
  21. package/src/modules/Filters/components/__tests__/filter-pagination.spec.js +94 -0
  22. package/src/modules/Filters/components/__tests__/filter-table-fields.spec.js +71 -0
  23. package/src/modules/Filters/components/filter-pagination.vue +8 -8
  24. package/src/modules/Filters/components/filter-table-fields.vue +4 -11
  25. package/src/modules/Filters/composables/useTableFilters.js +2 -3
  26. package/src/modules/Filters/enums/FilterEvent.enum.js +6 -0
  27. package/src/modules/Filters/scripts/getters/index.js +9 -0
  28. package/src/modules/Filters/scripts/getters/localStorageGetter.js +17 -0
  29. package/src/modules/Filters/scripts/getters/queryGetter.js +10 -0
  30. package/src/modules/Filters/scripts/getters/valueGetter.js +9 -0
  31. package/src/modules/Filters/scripts/restores/index.js +7 -0
  32. package/src/modules/Filters/scripts/restores/localStorageRestore.js +7 -0
  33. package/src/modules/Filters/scripts/restores/queryRestore.js +7 -0
  34. package/src/modules/Filters/scripts/setters/index.js +9 -0
  35. package/src/modules/Filters/scripts/setters/localStorageSetter.js +16 -0
  36. package/src/modules/Filters/scripts/setters/querySetter.js +41 -0
  37. package/src/modules/Filters/scripts/setters/valueSetter.js +6 -0
  38. package/src/modules/Filters/scripts/utils/changeRouteQuery.js +17 -0
  39. package/src/modules/Filters/store/FiltersStoreModule.js +88 -139
  40. package/src/modules/Filters/store/__tests__/FiltersStoreModule.spec.js +157 -0
  41. package/src/modules/Notifications/store/__tests__/NotificationsStoreModule.actions.spec.js +1 -1
  42. package/src/modules/TableStoreModule/composables/useTableStore.js +13 -9
  43. package/src/modules/TableStoreModule/store/TableStoreModule.js +124 -106
  44. package/src/modules/TableStoreModule/store/__tests__/TableStoreModule.spec.js +241 -0
  45. package/src/modules/Filters/restores/filterFieldsRestore.js +0 -9
  46. package/src/modules/Filters/restores/readme.md +0 -1
@@ -16,7 +16,7 @@ describe('AuditFormQuestionOptionsWriteRow', () => {
16
16
  option: {},
17
17
  },
18
18
  });
19
- const deleteBtn = wrapper.findComponent('.audit-form-question-options-write-row__tooltip .wt-icon-btn');
19
+ const deleteBtn = wrapper.findComponent({ name: 'wt-icon-btn' });
20
20
  expect(deleteBtn.attributes().icon).toBe('bucket');
21
21
  deleteBtn.vm.$emit('click');
22
22
  expect(wrapper.emitted().delete).toBeTruthy();
@@ -9,13 +9,10 @@
9
9
  />
10
10
  <wt-input
11
11
  :label="$t('webitelUI.auditForm.score', 1)"
12
- :label-props="{ hint: $t('webitelUI.auditForm.scoreInputTooltip', { min: minScore, max: maxScore}), hintPosition: 'right' }"
13
12
  :value="option.score"
14
13
  :v="v$.option.score"
15
- :number-min="minScore"
16
- :number-max="maxScore"
17
14
  type="number"
18
- @input="changeScore"
15
+ @input="emit('update:option', { name: option.name, score: $event })"
19
16
  />
20
17
  <wt-tooltip class="audit-form-question-options-write-row__tooltip">
21
18
  <template #activator>
@@ -58,9 +55,6 @@ const emit = defineEmits([
58
55
  // is needed for useVuelidate, because props.question/props.result isn't reactive
59
56
  const { option } = toRefs(props);
60
57
 
61
- const minScore = 0;
62
- const maxScore = 10;
63
-
64
58
  const v$ = useVuelidate(
65
59
  computed(() => (
66
60
  {
@@ -68,8 +62,8 @@ const v$ = useVuelidate(
68
62
  name: { required },
69
63
  score: {
70
64
  required,
71
- minValue: minValue(minScore),
72
- maxValue: maxValue(maxScore),
65
+ minValue: minValue(0),
66
+ maxValue: maxValue(10),
73
67
  decimalValidator: decimalValidator(2),
74
68
  },
75
69
  },
@@ -78,12 +72,6 @@ const v$ = useVuelidate(
78
72
  { $autoDirty: true },
79
73
  );
80
74
 
81
-
82
- function changeScore(value) {
83
- const score = value > maxScore ? maxScore : Number(Math.abs(value)); // to prevent -1, 000 or string value because of this task https://webitel.atlassian.net/browse/WTEL-4505
84
- emit('update:option', { name: props.option.name, score });
85
- }
86
-
87
75
  // init validation
88
76
  onMounted(() => v$.value.$touch());
89
77
  </script>
@@ -8,9 +8,8 @@
8
8
  :value="question.min"
9
9
  :v="v$.question.min"
10
10
  :number-min="0"
11
- :number-max="9"
11
+ :number-max="19"
12
12
  :label="$t('reusable.from')"
13
- :label-props="{ hint: $t('webitelUI.auditForm.scoreInputTooltip', { min: '0', max: '9'}), hintPosition: 'right' }"
14
13
  type="number"
15
14
  required
16
15
  @input="updateQuestion({ path: 'min', value: $event })"
@@ -19,9 +18,8 @@
19
18
  :value="question.max"
20
19
  :v="v$.question.max"
21
20
  :number-min="1"
22
- :number-max="10"
21
+ :number-max="20"
23
22
  :label="$t('reusable.to')"
24
- :label-props="{ hint: $t('webitelUI.auditForm.scoreInputTooltip', { min: '1', max: '10'}), hintPosition: 'right' }"
25
23
  type="number"
26
24
  required
27
25
  @input="updateQuestion({ path: 'max', value: $event })"
@@ -111,8 +109,7 @@ const scoreRange = computed(() => {
111
109
  const isResult = computed(() => !isEmpty(props.result));
112
110
 
113
111
  function updateQuestion({ path, value }) {
114
- const number = value > 10 ? 10 : Number(Math.abs(value)); // to prevent -1, 000 or string value because of this task https://webitel.atlassian.net/browse/WTEL-4505
115
- emit('change:question', updateObject({ obj: props.question, path, value: number }));
112
+ emit('change:question', updateObject({ obj: props.question, path, value }));
116
113
  }
117
114
 
118
115
  // init validation
@@ -1,13 +1,146 @@
1
+ import { valueSetter, querySetter, localStorageSetter } from '../scripts/setters';
2
+ import { queryRestore, localStorageRestore } from '../scripts/restores';
3
+ import { valueGetter, queryGetter, localStorageGetter } from '../scripts/getters';
4
+
5
+ const convertGetterArray = (context) => (router) => (getters) => {
6
+ const availableGetters = ['value', 'query', 'localStorage'];
7
+
8
+ getters.forEach((getter) => {
9
+ if (!availableGetters.includes(getter)) throw new Error(`Unknown getter: ${getter}`);
10
+ });
11
+
12
+ const getter = () => {
13
+ if (getters.includes('value')) {
14
+ const value = valueGetter(context)();
15
+ if (value) return value;
16
+ }
17
+ if (getters.includes('query')) {
18
+ const value = queryGetter(context)(router)();
19
+ if (value) return value;
20
+ }
21
+ if (getters.includes('localStorage')) {
22
+ const value = localStorageGetter(context)();
23
+ if (value) return value;
24
+ }
25
+
26
+ console.error(`No value found for ${context.name} filter!`);
27
+
28
+ return undefined;
29
+ };
30
+
31
+ return getter;
32
+ };
33
+
34
+ const convertSetterArray = (context) => (router) => (setters) => {
35
+ const availableSetters = ['value', 'query', 'localStorage'];
36
+ setters.forEach((setter) => {
37
+ if (!availableSetters.includes(setter)) throw new Error(`Unknown setter: ${setter}`);
38
+ });
39
+
40
+ const setter = async (value) => {
41
+ if (setters.includes('value')) valueSetter(context)(value);
42
+ if (setters.includes('query')) await querySetter(context)(router)(value);
43
+ if (setters.includes('localStorage')) localStorageSetter(context)(value);
44
+
45
+ return context;
46
+ };
47
+
48
+ return setter;
49
+ };
50
+
51
+ const convertRestoreArray = (context) => (router) => (restores) => {
52
+ const availableRestores = ['query', 'localStorage'];
53
+
54
+ restores.forEach((restore) => {
55
+ if (!availableRestores.includes(restore)) throw new Error(`Unknown restore: ${restore}`);
56
+ });
57
+
58
+ const restore = () => {
59
+ if (restores.includes('query')) {
60
+ const restoredValue = queryRestore(context)(router)();
61
+ if (restoredValue) return restoredValue;
62
+ }
63
+
64
+ if (restores.includes('localStorage')) {
65
+ const restoredValue = localStorageRestore(context)();
66
+ if (restoredValue) return restoredValue;
67
+ }
68
+ };
69
+
70
+ return restore;
71
+ };
72
+
1
73
  export default class BaseFilterSchema {
2
74
  constructor({
3
- value = '',
4
- defaultValue = '',
75
+ name,
76
+ value,
77
+ get,
78
+ set,
5
79
  restore,
6
- localStorageKey,
80
+ router, // is required for query get/set, if getters/setters are passed as strings
81
+ ...rest
7
82
  } = {}) {
8
- this.value = value;
9
- this.defaultValue = defaultValue;
10
- if (restore) this.restore = restore;
11
- if (localStorageKey) this.localStorageKey = localStorageKey;
83
+ if (!name) throw new Error('Filter name is required');
84
+ if (value === undefined) throw new Error(`Filter value is required: ${name}`);
85
+
86
+ if (!get) throw new Error(`Filter getter is required: ${name}`);
87
+ if (!set) throw new Error(`Filter setter is required: ${name}`);
88
+ if (!restore) throw new Error(`Filter restore is required: ${name}`);
89
+
90
+ Object.assign(this, {
91
+ name,
92
+ value,
93
+ get,
94
+ set,
95
+ restore,
96
+ }, rest);
97
+
98
+ this.setupGetters(get, { router });
99
+ this.setupSetters(set, { router });
100
+ this.setupRestores(restore, { router });
101
+
102
+ return this;
103
+ }
104
+
105
+ setupGetters(getters, { router }) {
106
+ let getter;
107
+
108
+ if (Array.isArray(getters)) {
109
+ getter = convertGetterArray(this)(router)(getters);
110
+ } else if (typeof getters === 'function') {
111
+ getter = getters(this);
112
+ } else {
113
+ throw new Error('Getter should be a function or an array of available getters');
114
+ }
115
+
116
+ this.get = getter;
117
+ }
118
+
119
+ setupSetters(setters, { router }) {
120
+ let setter;
121
+
122
+ if (Array.isArray(setters)) {
123
+ setter = convertSetterArray(this)(router)(setters);
124
+ } else if (typeof setters === 'function') {
125
+ setter = setters(this);
126
+ } else {
127
+ throw new Error('Setter should be a function or an array of available setters');
128
+ }
129
+
130
+ this.set = setter;
131
+ }
132
+
133
+ setupRestores(restores, { router }) {
134
+ let restore;
135
+
136
+ if (Array.isArray(restores)) {
137
+ restore = convertRestoreArray(this)(router)(restores);
138
+ } else if (typeof restores === 'function') {
139
+ restore = restores(this);
140
+ } else {
141
+ throw new Error('Restore should be a function or an array of available restores');
142
+ }
143
+
144
+ this.restore = restore;
12
145
  }
13
146
  }
@@ -0,0 +1,94 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { createStore } from 'vuex';
3
+ import FiltersStoreModule from '../../store/FiltersStoreModule';
4
+ import FilterPagination from '../filter-pagination.vue';
5
+
6
+ const filtersSchema = [
7
+ {
8
+ name: 'page',
9
+ value: 1,
10
+ get: ['value'],
11
+ set: ['value'],
12
+ restore: () => {},
13
+ },
14
+ {
15
+ name: 'size',
16
+ value: 11,
17
+ get: ['value'],
18
+ set: ['value'],
19
+ restore: () => {},
20
+ },
21
+ ];
22
+
23
+ describe('FilterPagination', () => {
24
+ it('renders a component', () => {
25
+ const store = createStore({
26
+ modules: {
27
+ filters: new FiltersStoreModule().addFilter(filtersSchema).getModule(),
28
+ },
29
+ });
30
+
31
+ const wrapper = mount(FilterPagination, {
32
+ props: {
33
+ namespace: 'filters',
34
+ },
35
+ global: {
36
+ plugins: [store],
37
+ },
38
+ });
39
+ expect(wrapper.exists()).toBe(true);
40
+ });
41
+
42
+ it('size change dispatches SET_FILTER action', async () => {
43
+ const store = createStore({
44
+ modules: {
45
+ filters: new FiltersStoreModule().addFilter(filtersSchema).getModule(),
46
+ },
47
+ });
48
+
49
+ const wrapper = mount(FilterPagination, {
50
+ shallow: true,
51
+ props: {
52
+ namespace: 'filters',
53
+ },
54
+ global: {
55
+ plugins: [store],
56
+ stubs: {
57
+ WtPagination: false,
58
+ },
59
+ },
60
+ });
61
+
62
+ const pagination = wrapper.findComponent('.wt-pagination');
63
+ pagination.vm.$emit('input', 321);
64
+ pagination.vm.$emit('change');
65
+ await wrapper.vm.$nextTick();
66
+ expect(store.getters['filters/GET_FILTER']('size')).toBe(321);
67
+ });
68
+
69
+ it('page change dispatches SET_FILTER action', async () => {
70
+ const store = createStore({
71
+ modules: {
72
+ filters: new FiltersStoreModule().addFilter(filtersSchema).getModule(),
73
+ },
74
+ });
75
+
76
+ const wrapper = mount(FilterPagination, {
77
+ shallow: true,
78
+ props: {
79
+ namespace: 'filters',
80
+ },
81
+ global: {
82
+ plugins: [store],
83
+ stubs: {
84
+ WtPagination: false,
85
+ },
86
+ },
87
+ });
88
+
89
+ const pagination = wrapper.findComponent('.wt-pagination');
90
+ pagination.vm.$emit('next');
91
+ await wrapper.vm.$nextTick();
92
+ expect(store.getters['filters/GET_FILTER']('page')).toBe(2);
93
+ });
94
+ });
@@ -0,0 +1,71 @@
1
+ import { createStore } from 'vuex';
2
+ import { mount } from '@vue/test-utils';
3
+ import FiltersStoreModule from '../../store/FiltersStoreModule';
4
+ import FilterTableFields from '../filter-table-fields.vue';
5
+
6
+ const filterSchema = {
7
+ name: 'fields',
8
+ value: ['field2'],
9
+ get: ['value'],
10
+ set: ['value'],
11
+ restore: () => {},
12
+ };
13
+
14
+ describe('FilterTableFields', () => {
15
+ it('renders a component', () => {
16
+ const store = createStore({
17
+ modules: {
18
+ filters: new FiltersStoreModule().addFilter(filterSchema).getModule(),
19
+ },
20
+ });
21
+
22
+ const headers = [
23
+ { value: 'f1', field: 'field1', show: false },
24
+ { value: 'f2', field: 'field2', show: true },
25
+ ];
26
+
27
+ const wrapper = mount(FilterTableFields, {
28
+ props: {
29
+ namespace: 'filters',
30
+ headers,
31
+ },
32
+ global: {
33
+ plugins: [store],
34
+ },
35
+ });
36
+ expect(wrapper.exists()).toBe(true);
37
+ });
38
+
39
+ it('fields change dispatches SET_FILTER action', async () => {
40
+ const store = createStore({
41
+ modules: {
42
+ filters: new FiltersStoreModule().addFilter(filterSchema).getModule(),
43
+ },
44
+ });
45
+
46
+ const headers = [
47
+ { value: 'f1', field: 'field1', show: false },
48
+ { value: 'f2', field: 'field2', show: true },
49
+ ];
50
+
51
+ const wrapper = mount(FilterTableFields, {
52
+ shallow: true,
53
+ props: {
54
+ namespace: 'filters',
55
+ headers,
56
+ },
57
+ global: {
58
+ plugins: [store],
59
+ },
60
+ });
61
+
62
+ wrapper.findComponent({ name: 'WtTableColumnSelect' }).vm.$emit('change', [
63
+ { value: 'f1', field: 'field1', show: true },
64
+ { value: 'f2', field: 'field2', show: false },
65
+ ]);
66
+
67
+ await wrapper.vm.$nextTick();
68
+
69
+ expect(store.getters['filters/GET_FILTER']('fields')).toEqual(['f1']);
70
+ });
71
+ });
@@ -34,26 +34,26 @@ const store = useStore();
34
34
 
35
35
  const localSize = ref(0);
36
36
 
37
- const page = computed(() => getNamespacedState(store.state, props.namespace)[pageFilterName].value);
38
- const size = computed(() => getNamespacedState(store.state, props.namespace)[sizeFilterName].value);
37
+ const page = computed(() => store.getters[`${props.namespace}/GET_FILTER`](pageFilterName));
38
+ const size = computed(() => store.getters[`${props.namespace}/GET_FILTER`](sizeFilterName));
39
39
 
40
40
  function setFilter(payload) {
41
41
  return store.dispatch(`${props.namespace}/SET_FILTER`, payload);
42
42
  }
43
43
 
44
44
  function setPage(value) {
45
- return setFilter({ value, filter: pageFilterName });
45
+ return setFilter({ value, name: pageFilterName });
46
46
  }
47
47
 
48
48
  function setSize(value) {
49
49
  if (value === size.value) return;
50
- // eslint-disable-next-line consistent-return
51
- return setFilter({ value, filter: sizeFilterName });
50
+ return setFilter({ value, name: sizeFilterName });
52
51
  }
53
52
 
54
- watch(size, () => {
55
- localSize.value = size.value;
56
- }, { immediate: true });
53
+ // TF?
54
+ // watch(size, () => {
55
+ // localSize.value = size.value;
56
+ // }, { immediate: true });
57
57
  </script>
58
58
 
59
59
  <style lang="scss" scoped>
@@ -22,35 +22,28 @@ const props = defineProps({
22
22
  },
23
23
  staticHeaders: {
24
24
  type: Array,
25
+ default: () => [],
25
26
  },
26
27
  });
27
28
 
28
- const emit = defineEmits(
29
+ const emit = defineEmits([
29
30
  'change',
30
- );
31
+ ]);
31
32
 
32
- // const storedProp = 'value';
33
33
  const filterQuery = 'fields';
34
34
 
35
35
  const store = useStore();
36
36
 
37
- const filterSchema = computed(() => getNamespacedState(store.state, props.namespace)[filterQuery]);
38
-
39
37
  function setValue(payload) {
40
38
  return store.dispatch(`${props.namespace}/SET_FILTER`, payload);
41
39
  }
42
40
 
43
- function setToLocalStorage({ value }) {
44
- localStorage.setItem(filterSchema.value.localStorageKey, value);
45
- }
46
-
47
41
  function handleChange(headers) {
48
42
  const value = headers.filter((item) => item.show).map(({ value }) => value);
49
43
  const params = {
50
- filter: filterQuery,
44
+ name: filterQuery,
51
45
  value,
52
46
  };
53
- setToLocalStorage(params);
54
47
  setValue(params);
55
48
  emit('change', headers);
56
49
  }
@@ -9,9 +9,8 @@ export const useTableFilters = (namespace) => {
9
9
  return store.dispatch(`${filtersNamespace}/RESTORE_FILTERS`, payload);
10
10
  }
11
11
 
12
- restoreFilters();
13
-
14
12
  return {
15
- filtersNamespace,
13
+ namespace: filtersNamespace,
14
+ restoreFilters,
16
15
  };
17
16
  };
@@ -0,0 +1,6 @@
1
+ const FilterEvent = Object.freeze({
2
+ FILTER_SET: 'FILTER_SET',
3
+ RESTORED: 'RESTORED',
4
+ });
5
+
6
+ export default FilterEvent;
@@ -0,0 +1,9 @@
1
+ import localStorageGetter from './localStorageGetter';
2
+ import queryGetter from './queryGetter';
3
+ import valueGetter from './valueGetter';
4
+
5
+ export {
6
+ localStorageGetter,
7
+ queryGetter,
8
+ valueGetter,
9
+ };
@@ -0,0 +1,17 @@
1
+ // context === filter "this"
2
+ const localStorageGetter = (context) => () => {
3
+ if (!context) throw new Error('Filter context is required for localStorageGetter!');
4
+
5
+ const key = context.localStorageKey;
6
+
7
+ if (!key) throw new Error(`Please provide "localStorageKey" for ${context.name} filter!`);
8
+
9
+ const value = localStorage.getItem(key);
10
+ if (!value) return null;
11
+
12
+ const splitted = value.split(',');
13
+ if (splitted.length === 1) return splitted[0];
14
+ return splitted;
15
+ }
16
+
17
+ export default localStorageGetter;
@@ -0,0 +1,10 @@
1
+
2
+ // context === filter "this"
3
+ const queryGetter = (context) => (router) => () => {
4
+ if (!router) throw new Error('Router is required for queryGetter!');
5
+ if (!router) throw new Error('Router is required for queryGetter!');
6
+
7
+ return router.currentRoute.value.query[context.name];
8
+ };
9
+
10
+ export default queryGetter;
@@ -0,0 +1,9 @@
1
+ // context === filter "this"
2
+ const valueGetter = (context) => () => {
3
+ const { value, storedProp, multiple } = context;
4
+ if (multiple) return value.map((item) => item[storedProp]); // if arr, map
5
+ if (storedProp) return value[storedProp]; // if object and has specific prop, return this prop
6
+ return value; // else return val
7
+ }
8
+
9
+ export default valueGetter;
@@ -0,0 +1,7 @@
1
+ import localStorageRestore from './localStorageRestore';
2
+ import queryRestore from './queryRestore';
3
+
4
+ export {
5
+ localStorageRestore,
6
+ queryRestore,
7
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * restore copies getter logic
3
+ */
4
+
5
+ import localStorageGetter from '../getters/localStorageGetter';
6
+
7
+ export default localStorageGetter;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * restore copies getter logic
3
+ */
4
+
5
+ import queryGetter from '../getters/queryGetter';
6
+
7
+ export default queryGetter;
@@ -0,0 +1,9 @@
1
+ import localStorageSetter from './localStorageSetter';
2
+ import querySetter from './querySetter';
3
+ import valueSetter from './valueSetter';
4
+
5
+ export {
6
+ localStorageSetter,
7
+ querySetter,
8
+ valueSetter,
9
+ };
@@ -0,0 +1,16 @@
1
+ // context === filter "this"
2
+
3
+ const localStorageSetter = (context) => (rawValue) => {
4
+ if (!context) throw new Error('Filter context is required for localStorageSetter!');
5
+
6
+ const key = context.localStorageKey;
7
+
8
+ if (!key) throw new Error(`Please provide "localStorageKey" for ${context.name} filter!`);
9
+
10
+ const value = Array.isArray(rawValue) ? rawValue.join(',') : rawValue;
11
+ localStorage.setItem(key, value);
12
+
13
+ return context;
14
+ }
15
+
16
+ export default localStorageSetter;
@@ -0,0 +1,41 @@
1
+ import changeRouteQuery from '../utils/changeRouteQuery';
2
+
3
+ const isObject = (value) => typeof value === 'object' &&
4
+ !Array.isArray(value) && value !== null;
5
+
6
+ const handlePrimitive = ({ value }) => value;
7
+
8
+ const handleObject = ({ value, storedProp }) => value[storedProp];
9
+
10
+ const handleArray = ({ value, storedProp }) => {
11
+ if (!value.length) return [];
12
+
13
+ if (isObject(value[0])) {
14
+ value.map((item) => item[storedProp]);
15
+ } else {
16
+ return value;
17
+ }
18
+ };
19
+
20
+ const querySetter = (context) => (router) => async (rawValue = context.value) => {
21
+ const { name: filterQuery, storedProp } = this;
22
+
23
+ let value = '';
24
+
25
+ if (Array.isArray(rawValue)) {
26
+ value = handleArray({ value: rawValue, storedProp });
27
+ } else if (isObject(rawValue)) {
28
+ value = handleObject({ value: rawValue, storedProp });
29
+ } else {
30
+ value = handlePrimitive({ value });
31
+ }
32
+
33
+ await changeRouteQuery(router)({
34
+ filterQuery,
35
+ value,
36
+ });
37
+
38
+ return context;
39
+ };
40
+
41
+ export default querySetter;
@@ -0,0 +1,6 @@
1
+ const valueSetter = (context) => (newValue) => {
2
+ context.value = newValue;
3
+ return context;
4
+ }
5
+
6
+ export default valueSetter;
@@ -0,0 +1,17 @@
1
+ import deepEqual from 'deep-equal';
2
+
3
+ const changeRouteQuery = (router) => ({ filterQuery, value }) => {
4
+ if (deepEqual(router.currentRoute.value.query[filterQuery], value)) return;
5
+
6
+ const newQuery = {
7
+ ...router.currentRoute.value.query,
8
+ [filterQuery]: value,
9
+ };
10
+
11
+ return router.replace({
12
+ name: router.currentRoute.value.name,
13
+ query: newQuery,
14
+ });
15
+ };
16
+
17
+ export default changeRouteQuery;