import {Fetch, Func, useFetcher, useMap, useSetState} from '..' import {useState} from 'react' type ReadAction = (...args: any[]) => Promise; type CreateAction = (...args: any[]) => Promise; type UpdateAction = (pk: E[PK], ...args: any[]) => Promise type DeleteAction = (pk: E[PK], ...args: any[]) => Promise interface CreateActionParams { preventInsert?: boolean, insertBefore?: boolean } export interface Create { creating: boolean create: (conf?: CreateActionParams, ...args: Parameters) => ReturnType createError?: ERR } export interface Read>, ERR = any> { list?: E[] fetching: boolean fetch: Fetch find: (pk: E[PK]) => E | undefined clearCache: () => void fetchError?: ERR } export interface Update>, ERR> { updating: (pk: E[PK]) => boolean update: F updateError: (pk: E[PK]) => ERR | undefined } export interface Delete>, ERR> { removing: (id: E[PK]) => boolean remove: F removeError: (pk: E[PK]) => ERR | undefined } export type CrudListR, ERR = any> = Read export type CrudListCR, ERR = any> = Create, ERR> & Read export type CrudListRU, ERR = any> = Read & Update, ERR> export type CrudListCRU, ERR = any> = Create, ERR> & Read & Update, ERR> export type CrudListRD, ERR = any> = Read & Delete, ERR> export type CrudListRUD, ERR = any> = Read & Update, ERR> & Delete, ERR> export type CrudListCRD, ERR = any> = Create, ERR> & Read & Delete, ERR> export type CrudListCRUD, ERR = any> = Create, ERR> & Read & Delete, ERR> & Update, ERR> export interface UseCrudList { , ERR = any>(pk: PK, _: {r: ReadAction}): CrudListR , ERR = any>(pk: PK, _: {r: ReadAction, c: CreateAction}): CrudListCR , ERR = any>(pk: PK, _: {r: ReadAction, u: UpdateAction}): CrudListRU , ERR = any>(pk: PK, _: {c: CreateAction, r: ReadAction, u: UpdateAction}): CrudListCRU , ERR = any>(pk: PK, _: {r: ReadAction, d: DeleteAction}): CrudListRD , ERR = any>(pk: PK, _: {r: ReadAction, u: UpdateAction, d: DeleteAction}): CrudListRUD , ERR = any>(pk: PK, _: {r: ReadAction, c: CreateAction, u: UpdateAction, d: DeleteAction}): CrudListCRUD , ERR = any>(pk: PK, _: {r: ReadAction, c: CreateAction, d: DeleteAction}): CrudListCRD } interface CrudParams { c?: CreateAction r: ReadAction u?: UpdateAction d?: DeleteAction } interface UseCrudParams | undefined, R extends ReadAction, U extends UpdateAction | undefined, D extends DeleteAction | undefined > { c?: C, r: R, u?: U, d?: D, } export const useCrudList: UseCrudList = , ERR = any> ( pk: keyof E, {c, r, u, d}: UseCrudParams ) => { const {entity: list, loading: fetching, fetch, setEntity: set, clearCache, error: fetchError} = useFetcher>(r!) const [creating, setCreating] = useState(false) const [createError, setCreateError] = useState(undefined) const removingList = useSetState() const removeListError = useMap() const updatingList = useSetState() const updatingListError = useMap() const create = async ({preventInsert, insertBefore}: CreateActionParams = {}, ...args: any[]): Promise => { try { setCreating(true) const entity = await c!(...args) if (!preventInsert) { set((prev: E[] | undefined) => { if (insertBefore) return [entity, ...(prev ?? [])] else return [...(prev ?? []), entity] }) } setCreating(false) setCreateError(undefined) return entity } catch (e: any) { setCreateError(e) setCreating(false) throw e } } const remove = async (primaryKey: E[PK]) => { try { removingList.add(primaryKey) await d!(primaryKey) set(n => n!.filter(x => x[pk] !== primaryKey)) removeListError.delete(primaryKey) removingList.delete(primaryKey) } catch (e: any) { removeListError.set(primaryKey, e) removingList.delete(primaryKey) throw e } } const update: UpdateAction = async (primaryKey, ...args: any[]) => { try { updatingList.add(primaryKey) const updatedEntity = await u!(primaryKey, ...args) set(n => n!.map(x => (x[pk] === primaryKey) ? {...x, ...updatedEntity} : x)) updatingListError.set(primaryKey, undefined) return updatedEntity } catch (e: any) { updatingListError.set(primaryKey, e) throw e } finally { updatingList.delete(primaryKey) } } const find = (primaryKey: E[PK]): E | undefined => { if (list) { return list.find(t => t[pk] === primaryKey) } } const removing = (primaryKey: E[PK]): boolean => removingList.has(primaryKey) const updating = (primaryKey: E[PK]): boolean => updatingList.has(primaryKey) const removeError = (primaryKey: E[PK]): ERR | undefined => removeListError.get(primaryKey) const updateError = (primaryKey: E[PK]): ERR | undefined => updatingListError.get(primaryKey) return { list, fetching, fetch, fetchError, clearCache, find, ...(c && { createError, creating, create, }), ...(d && { removing, remove, removeError, }), ...(u && { updating, update, updateError, }), } as any }