UNPKG

@mythpe/js-helpers

Version:

Library of plugins & shortcuts that use JavaScript, also includes the Vue3 plugin with quasar apps

253 lines (244 loc) 7.32 kB
/* * MyTh Ahmed Faiz Copyright © 2016-2024 All rights reserved. * Email: mythpe@gmail.com * Mobile: +966590470092 * Website: https://www.4myth.com * Github: https://github.com/mythpe */ import { computed, ComputedRef, MaybeRefOrGetter, nextTick, onMounted, onUnmounted, ref, toValue, watch } from 'vue' import { AxiosRequestConfig, AxiosResponse } from 'axios' import { useMyth } from '../vue3' import { ApiFulfilledResponse, ApiInterface, ApiMetaInterface, ApiModel, ConfigType, UseModelsOptionsArg } from '../types' import { extend } from 'quasar' const itemsPerPage = 1 const defMeta = { per_page: 0, total: 0, current_page: 0, last_page: 0 } type Item = ApiModel & object export function useModels<T extends Partial<Item> = Item> (Name: MaybeRefOrGetter<string>, opts: MaybeRefOrGetter<UseModelsOptionsArg> = {}, axiosRequestConfig: MaybeRefOrGetter<AxiosRequestConfig> = {}) { const name = toValue(Name) const options = toValue<UseModelsOptionsArg>(opts) // console.log(name, options) const { search, filter } = options const meta = ref<ApiMetaInterface>({ ...defMeta }) const requestConfig = computed<AxiosRequestConfig>(() => extend(!0, { itemsPerPage, page: meta.value.current_page }, toValue(axiosRequestConfig), { params: { search: search?.value || undefined, filter: filter?.value || undefined } })) const models = ref<T[]>([]) const fetching = ref(!1) const fetched = ref(!1) const page = computed({ get: () => meta.value.current_page, set: (v) => { meta.value.current_page = v } }) const canLoadMore = computed(() => { if (!fetched.value) { return !0 } return (meta.value.current_page || 0) < (meta.value.last_page || 0) }) const myth = useMyth() const fetch = (config: AxiosRequestConfig = {}) => new Promise<Record<string, any>>((resolve, reject) => { if (fetching.value || !canLoadMore.value) { resolve({}) return } fetching.value = !0 const def = {} extend(!0, def, requestConfig.value, config) let action: ((config?: ConfigType | undefined) => Promise<ApiInterface>) if (options?.method) { if (typeof options.method === 'function') { action = options.method } else { action = myth.services[name][options.method] } } else { action = myth.services[name][options?.isPanel ? 'index' : 'staticIndex'] } return action(def) .then((res: ApiInterface) => { const { _data, _meta } = res models.value = [ ...models.value, ...(_data || []) as any ] meta.value = _meta || { ...defMeta } resolve(res) options?.onSuccess?.(res) return res }) .catch((e: any) => { reject(e) options?.onError?.(e) return e }) .finally(() => { if (fetching.value) { fetching.value = !1 } if (!fetched.value) { fetched.value = !0 } }) }) const reset = () => { models.value = [] meta.value = { ...defMeta } if (fetched.value) { fetched.value = !1 } } const nextPage = (config: AxiosRequestConfig = {}) => { if (!canLoadMore.value) { return new Promise(resolve => resolve({})) } if (!page.value) { page.value = 1 } else { ++page.value } return fetch(config) } const prevPage = (config: AxiosRequestConfig = {}) => { if ((meta.value.current_page || 0) < 1) { return new Promise(resolve => resolve({})) } if (!page.value) { page.value = 1 } else { --page.value } return fetch(config) } const beginningFetch = (config: AxiosRequestConfig = {}) => { reset() if (options.qInfiniteScroll?.value) { return new Promise(resolve => { options.qInfiniteScroll?.value?.reset() nextTick(() => { options.qInfiniteScroll?.value?.trigger() }) resolve({}) }) } return nextPage(config) } const onRefresh = (done?: (() => void)) => beginningFetch().finally(() => done?.()) const onLoad = (index: any, done: any) => { return new Promise<{ index: number }>(resolve => { if (!canLoadMore.value) { done() resolve({ index }) return } nextPage().finally(() => { done() resolve({ index }) }) }) } const onSearch = () => beginningFetch() const removeItem = (item: Item) => { models.value = models.value.filter(e => e.value !== item.value) } const watchers = [] if (filter) { watchers.push(filter) } if (search) { watchers.push(search) } const stopWatch = watch(watchers, () => onSearch(), { deep: !0 }) onUnmounted(() => stopWatch?.()) onMounted(() => !options.lazy && nextPage()) return { models, meta, fetch, beginningFetch, fetching, fetched, canLoadMore, reset, nextPage, prevPage, onRefresh, onSearch, onLoad, removeItem } } type ItemModel<T extends object = any> = ApiModel<T>; export function useModel<T extends Partial<ItemModel<T>> = ItemModel> (Name: string, Id: MaybeRefOrGetter<string | number> | ComputedRef<string | number>, Options: MaybeRefOrGetter<UseModelsOptionsArg> = {}, axiosRequestConfig: MaybeRefOrGetter<AxiosRequestConfig> = {}) { const api = useMyth() const model = ref<T>({} as T) const fetching = ref(!0) const fetched = ref(!1) const name = toValue(Name) const id = toValue(Id) const options = toValue<UseModelsOptionsArg>(Options) const fetch = (config: AxiosRequestConfig = {}) => new Promise<AxiosResponse<T> | ApiFulfilledResponse>((resolve, reject) => { if ((fetching.value && fetched.value) || !id) { resolve({} as any) return } if (!fetching.value) { fetching.value = !0 } const _config = extend<AxiosRequestConfig>(!0, {}, config, toValue(axiosRequestConfig)) let action: ((id: any, config?: ConfigType | undefined) => Promise<ApiInterface>) if (options?.method) { if (typeof options.method === 'function') { action = options.method } else { action = api.services[name][options.method] } } else { action = api.services[name][options?.isPanel ? 'show' : 'staticShow'] } return action(id, _config) .then((r: any) => { const { _data } = r model.value = (_data as any) resolve(r) options?.onSuccess?.(r as any) return r }) .catch(e => { options?.onError?.(e) reject(e) return e }) .finally(() => { if (!fetched.value) { fetched.value = !0 } setTimeout(() => { if (fetching.value) { fetching.value = !1 } }, options?.timeout !== undefined ? options?.timeout : 100) }) }) !options?.lazy && onMounted(() => fetch()) const { search, filter } = options const watchers: any[] = [() => toValue(Name), () => toValue(Id), () => toValue(axiosRequestConfig)] if (filter) { watchers.push(filter) } if (search) { watchers.push(search) } const stopWatch = watch(watchers, () => fetch(), { deep: !0 }) onUnmounted(() => stopWatch()) return { model, fetching, fetch, fetched } }