From 2a6717d0595cffd275455f920f06077fe50ae36f Mon Sep 17 00:00:00 2001 From: jorgep Date: Wed, 11 Dec 2024 15:04:31 +0100 Subject: [PATCH] feat: refs #8113 add mapKey prop to VnPaginate and integrate into useArrayData for enhanced data mapping --- src/components/ui/VnPaginate.vue | 5 +++ src/composables/useArrayData.js | 37 ++++++++++++---- src/pages/Ticket/TicketAdvance.vue | 1 + src/stores/useArrayDataStore.js | 2 + .../__tests__/components/Paginate.spec.js | 43 ++++++++----------- 5 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/components/ui/VnPaginate.vue b/src/components/ui/VnPaginate.vue index 3649ba8f5..920836a93 100644 --- a/src/components/ui/VnPaginate.vue +++ b/src/components/ui/VnPaginate.vue @@ -74,6 +74,10 @@ const props = defineProps({ type: Boolean, default: false, }, + mapKey: { + type: String, + default: '', + }, }); const emit = defineEmits(['onFetch', 'onPaginate', 'onChange']); @@ -96,6 +100,7 @@ const arrayData = useArrayData(props.dataKey, { exprBuilder: props.exprBuilder, keepOpts: props.keepOpts, searchUrl: props.searchUrl, + mapKey: props.mapKey, }); const store = arrayData.store; diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js index da62eee3e..6e685ee20 100644 --- a/src/composables/useArrayData.js +++ b/src/composables/useArrayData.js @@ -49,6 +49,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) { 'exprBuilder', 'searchUrl', 'navigate', + 'mapKey', ]; if (typeof userOptions === 'object') { for (const option in userOptions) { @@ -119,17 +120,12 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) { const { limit } = filter; store.hasMoreData = limit && response.data.length >= limit; - if (append) { - if (!store.data) store.data = []; - for (const row of response.data) store.data.push(row); - } else { - store.data = response.data; - if (!isDialogOpened()) updateRouter && updateStateParams(); - } + processData(response.data, { map: !!store.mapKey, append }); + if (!append && !isDialogOpened()) updateRouter && updateStateParams(); store.isLoading = false; - canceller = null; + return response; } @@ -288,6 +284,31 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) { router.replace(newUrl); } + function processData(data, { map = true, append = true }) { + if (!append) { + store.data = []; + store.map = new Map(); + } + + if (!Array.isArray(data)) store.data = data; + else if (!map && append) for (const row of data) store.data.push(row); + else + for (const row of data) { + const key = row[store.mapKey]; + const val = { ...row, key }; + if (store.map.has(key)) { + const { position } = store.map.get(key); + val.position = position; + store.map.set(key, val); + store.data[position] = val; + } else { + val.position = store.map.size; + store.map.set(key, val); + store.data.push(val); + } + } + } + const totalRows = computed(() => (store.data && store.data.length) || 0); const isLoading = computed(() => store.isLoading || false); diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue index 8de602b37..a867285e7 100644 --- a/src/pages/Ticket/TicketAdvance.vue +++ b/src/pages/Ticket/TicketAdvance.vue @@ -441,6 +441,7 @@ watch( { searchUrl: 'params', navigate: null, page: 1, + mapKey: 'id', }; function get(key) { @@ -46,6 +47,7 @@ export const useArrayDataStore = defineStore('arrayDataStore', () => { function getDefaultState() { return Object.assign(JSON.parse(JSON.stringify(defaultOpts)), { data: ref(), + map: ref(new Map()), }); } diff --git a/test/vitest/__tests__/components/Paginate.spec.js b/test/vitest/__tests__/components/Paginate.spec.js index 345903c1a..a67dfcdc6 100644 --- a/test/vitest/__tests__/components/Paginate.spec.js +++ b/test/vitest/__tests__/components/Paginate.spec.js @@ -4,7 +4,11 @@ import VnPaginate from 'src/components/ui/VnPaginate.vue'; describe('VnPaginate', () => { const expectedUrl = '/api/customers'; - + const defaultData = [ + { id: 1, name: 'Tony Stark' }, + { id: 2, name: 'Jessica Jones' }, + { id: 3, name: 'Bruce Wayne' }, + ]; let vm; beforeAll(() => { const options = { @@ -28,11 +32,7 @@ describe('VnPaginate', () => { describe('paginate()', () => { it('should call to the paginate() method and set the data on the rows property', async () => { vi.spyOn(vm.arrayData, 'loadMore'); - vm.store.data = [ - { id: 1, name: 'Tony Stark' }, - { id: 2, name: 'Jessica Jones' }, - { id: 3, name: 'Bruce Wayne' }, - ]; + vm.store.data = defaultData; await vm.paginate(); @@ -42,26 +42,25 @@ describe('VnPaginate', () => { it('should call to the paginate() method and then call it again to paginate', async () => { vi.spyOn(axios, 'get').mockResolvedValue({ - data: [ - { id: 1, name: 'Tony Stark' }, - { id: 2, name: 'Jessica Jones' }, - { id: 3, name: 'Bruce Wayne' }, - ], + data: defaultData, }); vm.store.hasMoreData = true; await vm.$nextTick(); - vm.store.data = [ - { id: 1, name: 'Tony Stark' }, - { id: 2, name: 'Jessica Jones' }, - { id: 3, name: 'Bruce Wayne' }, - ]; + vm.store.data = defaultData; await vm.paginate(); expect(vm.store.skip).toEqual(3); expect(vm.store.data.length).toEqual(6); + vi.spyOn(axios, 'get').mockResolvedValue({ + data: [ + { id: 4, name: 'Peter Parker' }, + { id: 5, name: 'Clark Kent' }, + { id: 6, name: 'Barry Allen' }, + ], + }); await vm.paginate(); expect(vm.store.skip).toEqual(6); @@ -85,11 +84,7 @@ describe('VnPaginate', () => { const index = 1; const done = vi.fn(); - vm.store.data = [ - { id: 1, name: 'Tony Stark' }, - { id: 2, name: 'Jessica Jones' }, - { id: 3, name: 'Bruce Wayne' }, - ]; + vm.store.data = defaultData; await vm.onLoad(index, done); @@ -105,11 +100,7 @@ describe('VnPaginate', () => { ], }); - vm.store.data = [ - { id: 1, name: 'Tony Stark' }, - { id: 2, name: 'Jessica Jones' }, - { id: 3, name: 'Bruce Wayne' }, - ]; + vm.store.data = defaultData; expect(vm.pagination.page).toEqual(1); -- 2.40.1