forked from verdnatura/salix-front
Compare commits
4 Commits
dev
...
7632-useSt
Author | SHA1 | Date |
---|---|---|
|
689adbc30d | |
|
b48cba686e | |
|
0897c6c39c | |
|
59f812e6d7 |
|
@ -1,6 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { useStateQuery } from 'src/composables/useStateQuery';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
autoLoad: {
|
autoLoad: {
|
||||||
|
@ -32,7 +33,7 @@ const $props = defineProps({
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const stateQuery = useStateQuery();
|
||||||
const emit = defineEmits(['onFetch']);
|
const emit = defineEmits(['onFetch']);
|
||||||
defineExpose({ fetch });
|
defineExpose({ fetch });
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ onMounted(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
async function fetch(fetchFilter = {}) {
|
async function fetch(fetchFilter = {}) {
|
||||||
|
const hash = stateQuery.add();
|
||||||
try {
|
try {
|
||||||
const filter = { ...fetchFilter, ...$props.filter }; // eslint-disable-line vue/no-dupe-keys
|
const filter = { ...fetchFilter, ...$props.filter }; // eslint-disable-line vue/no-dupe-keys
|
||||||
if ($props.where && !fetchFilter.where) filter.where = $props.where;
|
if ($props.where && !fetchFilter.where) filter.where = $props.where;
|
||||||
|
@ -55,8 +57,8 @@ async function fetch(fetchFilter = {}) {
|
||||||
|
|
||||||
emit('onFetch', data);
|
emit('onFetch', data);
|
||||||
return data;
|
return data;
|
||||||
} catch (e) {
|
} finally {
|
||||||
//
|
stateQuery.remove(hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { onMounted, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useState } from 'src/composables/useState';
|
import { useState } from 'src/composables/useState';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
import { useStateQuery } from 'src/composables/useStateQuery';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
import PinnedModules from './PinnedModules.vue';
|
import PinnedModules from './PinnedModules.vue';
|
||||||
import UserPanel from 'components/UserPanel.vue';
|
import UserPanel from 'components/UserPanel.vue';
|
||||||
|
@ -12,6 +13,7 @@ import VnAvatar from './ui/VnAvatar.vue';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
|
const stateQuery = useStateQuery();
|
||||||
const state = useState();
|
const state = useState();
|
||||||
const user = state.getUser();
|
const user = state.getUser();
|
||||||
const appName = 'Lilium';
|
const appName = 'Lilium';
|
||||||
|
@ -50,6 +52,14 @@ const pinnedModulesRef = ref();
|
||||||
</QBtn>
|
</QBtn>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
<VnBreadcrumbs v-if="$q.screen.gt.sm" />
|
<VnBreadcrumbs v-if="$q.screen.gt.sm" />
|
||||||
|
<QSpinner
|
||||||
|
color="primary"
|
||||||
|
class="q-ml-md"
|
||||||
|
:class="{
|
||||||
|
'no-visible': !stateQuery.isLoading().value,
|
||||||
|
}"
|
||||||
|
size="xs"
|
||||||
|
/>
|
||||||
<QSpace />
|
<QSpace />
|
||||||
<div id="searchbar" class="searchbar"></div>
|
<div id="searchbar" class="searchbar"></div>
|
||||||
<QSpace />
|
<QSpace />
|
||||||
|
@ -104,6 +114,9 @@ const pinnedModulesRef = ref();
|
||||||
.q-header {
|
.q-header {
|
||||||
background-color: var(--vn-section-color);
|
background-color: var(--vn-section-color);
|
||||||
}
|
}
|
||||||
|
.no-visible {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<i18n>
|
<i18n>
|
||||||
en:
|
en:
|
||||||
|
|
|
@ -3,8 +3,10 @@ import { useRouter, useRoute } from 'vue-router';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useArrayDataStore } from 'stores/useArrayDataStore';
|
import { useArrayDataStore } from 'stores/useArrayDataStore';
|
||||||
import { buildFilter } from 'filters/filterPanel';
|
import { buildFilter } from 'filters/filterPanel';
|
||||||
|
import { useStateQuery } from 'src/composables/useStateQuery';
|
||||||
|
|
||||||
const arrayDataStore = useArrayDataStore();
|
const arrayDataStore = useArrayDataStore();
|
||||||
|
const stateQuery = useStateQuery();
|
||||||
|
|
||||||
export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
|
export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
|
||||||
if (!key) throw new Error('ArrayData: A key is required to use this composable');
|
if (!key) throw new Error('ArrayData: A key is required to use this composable');
|
||||||
|
@ -99,11 +101,18 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
|
||||||
|
|
||||||
params.filter = JSON.stringify(params.filter);
|
params.filter = JSON.stringify(params.filter);
|
||||||
store.currentFilter = params;
|
store.currentFilter = params;
|
||||||
|
|
||||||
store.isLoading = true;
|
store.isLoading = true;
|
||||||
const response = await axios.get(store.url, {
|
const hash = stateQuery.add();
|
||||||
signal: canceller.signal,
|
let response;
|
||||||
params,
|
try {
|
||||||
});
|
response = await axios.get(store.url, {
|
||||||
|
signal: canceller.signal,
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
stateQuery.remove(hash);
|
||||||
|
}
|
||||||
|
|
||||||
const { limit } = filter;
|
const { limit } = filter;
|
||||||
store.hasMoreData = limit && response.data.length >= limit;
|
store.hasMoreData = limit && response.data.length >= limit;
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
|
||||||
|
const queries = ref(new Set());
|
||||||
|
|
||||||
|
export function useStateQuery() {
|
||||||
|
function add() {
|
||||||
|
const min = 100000;
|
||||||
|
const max = 999999;
|
||||||
|
const hash = String(Math.floor(Math.random() * (max - min + 1)) + min);
|
||||||
|
queries.value.add(hash);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLoading() {
|
||||||
|
return computed(() => queries.value.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove(hash) {
|
||||||
|
queries.value.delete(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
queries.value = new Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
add,
|
||||||
|
isLoading,
|
||||||
|
remove,
|
||||||
|
queries,
|
||||||
|
reset,
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { describe, expect, it, beforeEach } from 'vitest';
|
||||||
|
import { useStateQuery } from 'src/composables/useStateQuery';
|
||||||
|
|
||||||
|
describe('useStateQuery', () => {
|
||||||
|
const { add, isLoading, remove, reset, queries } = useStateQuery();
|
||||||
|
beforeEach(() => {
|
||||||
|
reset();
|
||||||
|
expect(queries.value.size).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add two queries', async () => {
|
||||||
|
expect(queries.value.size).toBeFalsy();
|
||||||
|
const hash = add();
|
||||||
|
expect(queries.value.size).toBeTruthy();
|
||||||
|
expect(queries.value.has(hash)).toBeTruthy();
|
||||||
|
|
||||||
|
add();
|
||||||
|
expect(queries.value.size).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add and remove loading state', async () => {
|
||||||
|
expect(isLoading().value).toBeFalsy();
|
||||||
|
const hash = add();
|
||||||
|
expect(isLoading().value).toBeTruthy();
|
||||||
|
remove(hash);
|
||||||
|
expect(isLoading().value).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add and remove hash', async () => {
|
||||||
|
add();
|
||||||
|
add();
|
||||||
|
add();
|
||||||
|
|
||||||
|
const beforeCount = queries.value.size;
|
||||||
|
const hash = add();
|
||||||
|
expect(queries.value.has(hash)).toBeTruthy();
|
||||||
|
|
||||||
|
remove(hash);
|
||||||
|
expect(queries.value.has(hash)).toBeFalsy();
|
||||||
|
expect(queries.value.size).toBe(beforeCount);
|
||||||
|
});
|
||||||
|
});
|
|
@ -6,6 +6,7 @@ describe('InvoiceInIntrastat', () => {
|
||||||
let vm;
|
let vm;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
|
vi.spyOn(axios, 'get').mockResolvedValue({ data: [{}] });
|
||||||
vm = createWrapper(InvoiceInIntrastat, {
|
vm = createWrapper(InvoiceInIntrastat, {
|
||||||
global: {
|
global: {
|
||||||
stubs: ['vnPaginate'],
|
stubs: ['vnPaginate'],
|
||||||
|
@ -14,7 +15,6 @@ describe('InvoiceInIntrastat', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).vm;
|
}).vm;
|
||||||
vi.spyOn(axios, 'get').mockResolvedValue({ data: [{}] });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getTotal()', () => {
|
describe('getTotal()', () => {
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import { vi, describe, expect, it, beforeAll } from 'vitest';
|
import { vi, describe, expect, it, beforeAll } from 'vitest';
|
||||||
import { createWrapper } from 'app/test/vitest/helper';
|
import { createWrapper, axios } from 'app/test/vitest/helper';
|
||||||
import InvoiceInVat from 'src/pages/InvoiceIn/Card/InvoiceInVat.vue';
|
import InvoiceInVat from 'src/pages/InvoiceIn/Card/InvoiceInVat.vue';
|
||||||
|
|
||||||
describe('InvoiceInVat', () => {
|
describe('InvoiceInVat', () => {
|
||||||
let vm;
|
let vm;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
|
vi.spyOn(axios, 'get').mockResolvedValue({ data: [{}] });
|
||||||
vm = createWrapper(InvoiceInVat, {
|
vm = createWrapper(InvoiceInVat, {
|
||||||
global: {
|
global: {
|
||||||
stubs: [],
|
stubs: [],
|
||||||
|
|
Loading…
Reference in New Issue