import { onMounted, ref, computed } from 'vue'; import { useRouter, useRoute } from 'vue-router'; import axios from 'axios'; import { useArrayDataStore } from 'stores/useArrayDataStore'; import { buildFilter } from 'filters/filterPanel'; const arrayDataStore = useArrayDataStore(); export function useArrayData(key, userOptions) { if (!key) throw new Error('ArrayData: A key is required to use this composable'); if (!arrayDataStore.get(key)) { arrayDataStore.set(key); } const store = arrayDataStore.get(key); const hasMoreData = ref(false); const router = useRouter(); const route = useRoute(); let canceller = null; const page = ref(1); onMounted(() => { setOptions(); const query = route.query; if (query.params) { store.userParams = JSON.parse(query.params); } }); if (key && userOptions) { setOptions(); } function setOptions() { const allowedOptions = [ 'url', 'filter', 'where', 'order', 'limit', 'skip', 'userParams', 'userFilter', 'exprBuilder', ]; if (typeof userOptions === 'object') { for (const option in userOptions) { const isEmpty = userOptions[option] == null || userOptions[option] === ''; if (isEmpty || !allowedOptions.includes(option)) continue; if (Object.prototype.hasOwnProperty.call(store, option)) { store[option] = userOptions[option]; } } } } async function fetch({ append = false, updateRouter = true }) { if (!store.url) return; cancelRequest(); canceller = new AbortController(); const filter = { order: store.order, limit: store.limit, skip: store.skip, }; let exprFilter; let userParams = { ...store.userParams }; if (store?.exprBuilder) { const where = buildFilter(userParams, (param, value) => { const res = store.exprBuilder(param, value); if (res) delete userParams[param]; return res; }); exprFilter = where ? { where } : null; } Object.assign(filter, store.userFilter, exprFilter); Object.assign(store.filter, filter); const params = { filter: JSON.stringify(store.filter), }; Object.assign(params, userParams); store.isLoading = true; store.currentFilter = params; const response = await axios.get(store.url, { signal: canceller.signal, params, }); const { limit } = filter; hasMoreData.value = response.data.length === limit; if (store.pagination) { // await loadMore(); store.pagination = false; } if (append) { if (!store.data) store.data = []; for (const row of response.data) store.data.push(row); } else { store.data = response.data; updateRouter && updateStateParams(); } store.isLoading = false; canceller = null; return response; } function destroy() { if (arrayDataStore.get(key)) { arrayDataStore.clear(key); } } function cancelRequest() { if (canceller) { canceller.abort(); canceller = null; } } async function applyFilter({ filter, params }) { if (filter) store.userFilter = filter; store.filter = {}; if (params) store.userParams = Object.assign({}, params); await fetch({ append: false }); } async function addFilter({ filter, params }) { if (filter) store.userFilter = Object.assign(store.userFilter, filter); let userParams = Object.assign({}, store.userParams, params); userParams = sanitizerParams(userParams, store?.exprBuilder); store.userParams = userParams; store.skip = 0; store.filter.skip = 0; await fetch({ append: false, loadMore: true }); return { filter, params }; } async function removeFilter({ filter, params }) { if (filter) store.userFilter = Object.assign(store.userFilter, filter); let userParams = Object.assign({}, store.userParams, params); userParams = sanitizerParams(userParams, store?.exprBuilder); store.userParams = userParams; store.skip = 0; await loadMore({ append: false }); return { filter, params }; } function sanitizerParams(params, exprBuilder) { for (const param in params) { if (params[param] === '' || params[param] === null) { delete store.userParams[param]; delete params[param]; if (store.filter?.where) { delete store.filter.where[ Object.keys(exprBuilder ? exprBuilder(param) : param)[0] ]; if (Object.keys(store.filter.where).length === 0) { delete store.filter.where; } } } } return params; } async function loadMore() { if (!hasMoreData.value) return; store.skip = store.limit * page.value; page.value += 1; await fetch({ append: true }); } async function refresh() { if (Object.values(store.userParams).length) await fetch({ append: false }); } function updateStateParams() { const query = {}; if (store.order) query.order = store.order; if (store.limit) query.limit = store.limit; if (store.skip) query.skip = store.skip; if (store.userParams && Object.keys(store.userParams).length !== 0) query.params = JSON.stringify(store.userParams); if (router) router.replace({ path: route.path, query: query, }); } const totalRows = computed(() => (store.data && store.data.length) || 0); const isLoading = computed(() => store.isLoading || false); return { fetch, applyFilter, addFilter, removeFilter, refresh, destroy, loadMore, store, hasMoreData, totalRows, updateStateParams, isLoading, }; }