salix-front/src/composables/useArrayData.js

303 lines
9.1 KiB
JavaScript
Raw Normal View History

import { onMounted, computed } from 'vue';
import { useRouter, useRoute } from 'vue-router';
2023-01-05 13:57:47 +00:00
import axios from 'axios';
import { useArrayDataStore } from 'stores/useArrayDataStore';
import { buildFilter } from 'filters/filterPanel';
2024-10-29 01:15:21 +00:00
import { isDialogOpened } from 'src/filters';
2023-01-05 13:57:47 +00:00
const arrayDataStore = useArrayDataStore();
export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
2023-01-05 13:57:47 +00:00
if (!key) throw new Error('ArrayData: A key is required to use this composable');
2024-04-22 11:17:05 +00:00
if (!arrayDataStore.get(key)) arrayDataStore.set(key);
2023-01-05 13:57:47 +00:00
2023-01-10 13:58:24 +00:00
const store = arrayDataStore.get(key);
2023-01-14 12:48:57 +00:00
const route = useRoute();
const router = useRouter();
2023-02-23 14:01:40 +00:00
let canceller = null;
2023-01-14 12:48:57 +00:00
onMounted(() => {
setOptions();
2024-07-15 12:55:06 +00:00
reset(['skip']);
2024-07-03 15:53:37 +00:00
const query = route.query;
2024-06-10 07:19:42 +00:00
const searchUrl = store.searchUrl;
if (query[searchUrl]) {
const params = JSON.parse(query[searchUrl]);
2024-07-11 08:22:02 +00:00
const filter = params?.filter && JSON.parse(params?.filter ?? '{}');
2024-06-10 07:19:42 +00:00
delete params.filter;
2024-09-24 07:57:05 +00:00
store.userParams = { ...store.userParams, ...params };
2024-07-11 08:22:02 +00:00
store.userFilter = { ...filter, ...store.userFilter };
if (filter?.order) store.order = filter.order;
}
});
2024-04-22 11:17:05 +00:00
if (key && userOptions) setOptions();
2023-11-23 14:50:42 +00:00
2023-03-13 09:07:52 +00:00
function setOptions() {
2023-03-21 08:49:47 +00:00
const allowedOptions = [
'url',
'filter',
'where',
'order',
'limit',
'skip',
'userParams',
2023-09-27 11:41:50 +00:00
'userFilter',
'exprBuilder',
2024-06-10 07:19:42 +00:00
'searchUrl',
'navigate',
2023-03-21 08:49:47 +00:00
];
if (typeof userOptions === 'object') {
2023-03-13 09:07:52 +00:00
for (const option in userOptions) {
2023-11-17 13:06:43 +00:00
const isEmpty = userOptions[option] == null || userOptions[option] === '';
2023-03-21 08:49:47 +00:00
if (isEmpty || !allowedOptions.includes(option)) continue;
2024-06-10 07:19:42 +00:00
if (Object.hasOwn(store, option)) {
2024-05-08 10:30:44 +00:00
const defaultOpts = userOptions[option];
store[option] = userOptions.keepOpts?.includes(option)
? Object.assign(defaultOpts, store[option])
: defaultOpts;
2023-03-13 09:07:52 +00:00
}
}
}
}
async function fetch({ append = false, updateRouter = true }) {
2023-01-14 12:48:57 +00:00
if (!store.url) return;
2023-01-10 13:58:24 +00:00
2023-02-23 14:01:40 +00:00
cancelRequest();
canceller = new AbortController();
2023-01-14 12:48:57 +00:00
const filter = {
limit: store.limit,
2023-01-05 13:57:47 +00:00
};
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;
}
2023-01-10 13:58:24 +00:00
Object.assign(filter, store.userFilter, exprFilter);
2024-07-04 11:17:58 +00:00
let where;
if (filter?.where || store.filter?.where)
where = Object.assign(filter?.where ?? {}, store.filter?.where ?? {});
2024-07-04 10:51:46 +00:00
Object.assign(filter, store.filter);
filter.where = where;
const params = { filter };
2023-01-17 13:57:12 +00:00
Object.assign(params, userParams);
params.filter.skip = store.skip;
2024-07-11 08:22:02 +00:00
if (store.order && store.order.length) params.filter.order = store.order;
else delete params.filter.order;
2023-01-17 13:57:12 +00:00
params.filter = JSON.stringify(params.filter);
store.currentFilter = params;
2024-06-10 07:19:42 +00:00
store.isLoading = true;
2023-02-23 14:01:40 +00:00
const response = await axios.get(store.url, {
signal: canceller.signal,
params,
});
2023-01-14 12:48:57 +00:00
const { limit } = filter;
2024-04-22 14:35:34 +00:00
store.hasMoreData = limit && response.data.length >= limit;
2024-01-16 11:14:48 +00:00
if (append) {
2023-03-01 15:20:28 +00:00
if (!store.data) store.data = [];
2023-01-10 13:58:24 +00:00
for (const row of response.data) store.data.push(row);
} else {
2023-01-10 13:58:24 +00:00
store.data = response.data;
2024-10-29 01:15:21 +00:00
if (!isDialogOpened()) updateRouter && updateStateParams();
2023-01-27 08:43:10 +00:00
}
2023-02-23 14:01:40 +00:00
2023-09-27 11:41:50 +00:00
store.isLoading = false;
2023-03-21 08:49:47 +00:00
2023-02-23 14:01:40 +00:00
canceller = null;
2023-11-23 14:50:42 +00:00
return response;
2023-01-14 12:48:57 +00:00
}
2023-03-01 15:20:28 +00:00
function destroy() {
2023-02-24 10:04:02 +00:00
if (arrayDataStore.get(key)) {
arrayDataStore.clear(key);
}
}
2024-06-10 07:19:42 +00:00
function deleteOption(option) {
delete store[option];
}
function reset(opts = []) {
if (arrayDataStore.get(key)) arrayDataStore.reset(key, opts);
}
2023-02-23 14:01:40 +00:00
function cancelRequest() {
if (canceller) {
canceller.abort();
canceller = null;
}
}
2023-01-14 12:48:57 +00:00
2023-02-15 14:51:31 +00:00
async function applyFilter({ filter, params }) {
2023-01-14 12:48:57 +00:00
if (filter) store.userFilter = filter;
2023-12-15 13:23:57 +00:00
store.filter = {};
2024-06-10 07:19:42 +00:00
if (params) store.userParams = { ...params };
2023-01-10 13:58:24 +00:00
const response = await fetch({});
2024-05-15 12:39:15 +00:00
return response;
2023-01-10 13:58:24 +00:00
}
2023-01-05 13:57:47 +00:00
2023-02-15 14:51:31 +00:00
async function addFilter({ filter, params }) {
2024-07-04 10:51:46 +00:00
if (filter) store.filter = filter;
2024-06-10 07:19:42 +00:00
let userParams = { ...store.userParams, ...params };
userParams = sanitizerParams(userParams, store?.exprBuilder);
store.userParams = userParams;
2024-07-15 12:55:06 +00:00
reset(['skip', 'filter.skip', 'page']);
2024-07-03 15:53:37 +00:00
await fetch({});
2024-01-16 06:24:41 +00:00
return { filter, params };
}
async function addFilterWhere(where) {
2024-07-04 10:51:46 +00:00
const storedFilter = { ...store.filter };
if (!storedFilter?.where) storedFilter.where = {};
where = { ...storedFilter.where, ...where };
await addFilter({ filter: { where } });
}
2024-07-11 08:22:02 +00:00
async function addOrder(field, direction = 'ASC') {
const newOrder = field + ' ' + direction;
2024-07-12 11:03:49 +00:00
let order = store.order || [];
2024-07-11 08:22:02 +00:00
if (typeof order == 'string') order = [order];
let index = order.findIndex((o) => o.split(' ')[0] === field);
if (index > -1) {
order[index] = newOrder;
} else {
index = order.length;
order.push(newOrder);
}
store.order = order;
2024-07-15 12:55:06 +00:00
reset(['skip', 'filter.skip', 'page']);
fetch({});
2024-07-11 08:22:02 +00:00
index++;
return { index, order };
}
async function deleteOrder(field) {
let order = store.order ?? [];
if (typeof order == 'string') order = [order];
const index = order.findIndex((o) => o.split(' ')[0] === field);
if (index > -1) order.splice(index, 1);
store.order = order;
fetch({});
2024-07-11 08:22:02 +00:00
}
2023-12-13 13:19:42 +00:00
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) {
2024-07-05 14:29:06 +00:00
let key;
if (exprBuilder) {
const result = exprBuilder(param);
if (result !== undefined && result !== null)
key = Object.keys(result);
} else {
if (typeof param === 'object' && param !== null)
key = Object.keys(param);
}
if (key && key[0]) {
delete store.filter.where[key[0]];
if (Object.keys(store.filter.where).length === 0) {
delete store.filter.where;
}
}
}
}
}
return params;
2023-02-15 14:51:31 +00:00
}
2023-01-10 13:58:24 +00:00
async function loadMore() {
2024-04-22 14:35:34 +00:00
if (!store.hasMoreData) return;
2023-01-05 13:57:47 +00:00
store.skip = store.limit * store.page;
store.page += 1;
2023-01-05 13:57:47 +00:00
2023-01-10 13:58:24 +00:00
await fetch({ append: true });
2023-01-05 13:57:47 +00:00
}
2023-10-11 08:40:13 +00:00
async function refresh() {
if (Object.values(store.userParams).length) await fetch({});
2023-01-14 12:48:57 +00:00
}
function updateStateParams() {
2024-09-17 13:03:30 +00:00
if (!route) return;
2024-06-10 07:19:42 +00:00
const newUrl = { path: route.path, query: { ...(route.query ?? {}) } };
2024-10-29 01:15:21 +00:00
if (store.appendParams)
newUrl.query[store.searchUrl] = JSON.stringify(store.currentFilter);
2024-06-10 07:19:42 +00:00
if (store.navigate) {
const { customRouteRedirectName, searchText } = store.navigate;
if (customRouteRedirectName)
return router.push({
name: customRouteRedirectName,
params: { id: searchText },
});
const { matched: matches } = router.currentRoute.value;
const { path } = matches.at(-1);
const to =
store?.data?.length === 1
? path.replace(/\/(list|:id)|-list/, `/${store.data[0].id}`)
: path.replace(/:id.*/, '');
if (route.path != to) {
2024-06-10 11:14:24 +00:00
const pushUrl = { path: to };
if (to.endsWith('/list') || to.endsWith('/'))
pushUrl.query = newUrl.query;
2024-06-17 09:29:36 +00:00
destroy();
2024-06-10 11:14:24 +00:00
return router.push(pushUrl);
2024-06-10 07:19:42 +00:00
}
}
2024-01-16 11:14:48 +00:00
2024-06-10 07:19:42 +00:00
router.replace(newUrl);
2023-01-05 13:57:47 +00:00
}
2023-09-27 11:41:50 +00:00
const totalRows = computed(() => (store.data && store.data.length) || 0);
const isLoading = computed(() => store.isLoading || false);
2023-03-01 15:20:28 +00:00
2023-01-05 13:57:47 +00:00
return {
fetch,
2023-02-15 14:51:31 +00:00
applyFilter,
addFilter,
addFilterWhere,
2024-07-11 08:22:02 +00:00
addOrder,
deleteOrder,
2023-01-05 13:57:47 +00:00
refresh,
2023-03-01 15:20:28 +00:00
destroy,
2023-01-10 13:58:24 +00:00
loadMore,
store,
2023-03-01 15:20:28 +00:00
totalRows,
2023-01-14 12:48:57 +00:00
updateStateParams,
2023-09-27 11:41:50 +00:00
isLoading,
2024-06-10 07:19:42 +00:00
deleteOption,
reset,
2023-01-05 13:57:47 +00:00
};
}