import { useEffect, useState } from 'react'; import { useAsync, UseAsyncResult, UseDeleteResult } from './use-async'; import { useSDKModel, useSDKEventBus } from './use-models'; import { // Count, Id, HasId, } from '../types'; import { EventTopic, CHANGE_EVENT_TYPE, BaseModel } from '../models'; export type UseBaseModelType = { model: BaseModel; // count: UseAsyncResult; // patchAll: UseAsyncResult; getAll: () => UseAsyncResult; getById: (id: Id) => UseAsyncResult; create: () => UseAsyncResult; updateById: (id: Id) => UseAsyncResult; replaceById: (id: Id) => UseAsyncResult; deleteById: (id: Id) => UseDeleteResult; }; export const useBaseModel = ( classProp: string, ): UseBaseModelType => { const eventBus = useSDKEventBus(); const model = useSDKModel(classProp); return { model, getAll: useGetAll(model, eventBus), getById: useGetById(model, eventBus), create: useCreate(model, eventBus), updateById: useUpdateById(model, eventBus), replaceById: useReplaceById(model, eventBus), deleteById: useDeleteById(model, eventBus), }; }; const useGetById = ( model: BaseModel, eventBus: EventTopic, ) => (id: Id): UseAsyncResult => { const [data, setData] = useState(); const [gotten, fetch, loading, error] = useAsync(model.getById.bind(model)); async function handleChange() { const d = await model.getLocalById(id); setData(d); } useEffect(() => { handleChange(); }, []); useEffect(() => { eventBus.addEventListener(CHANGE_EVENT_TYPE, handleChange); return () => eventBus.removeEventListener(CHANGE_EVENT_TYPE, handleChange); }); useEffect(() => { setData(gotten); }, [gotten]); const exec = (...args: any[]) => fetch(id, ...args); return [data, exec, loading, error]; }; const useGetAll = ( model: BaseModel, eventBus: EventTopic, ) => (): UseAsyncResult => { const [data, setData] = useState(); const [gotten, fetch, loading, error] = useAsync(model.getAll.bind(model)); useEffect(() => { function handleChange() { if (gotten && gotten.length) { const ids = gotten.map((g: HasId) => g.id).filter(Boolean); setData(model.getLocalFilter((item: HasId) => ids.includes(item.id))); } } eventBus.addEventListener(CHANGE_EVENT_TYPE, handleChange); return () => eventBus.removeEventListener(CHANGE_EVENT_TYPE, handleChange); }); useEffect(() => { setData(gotten); }, [gotten]); const exec = (...args: any[]) => { return fetch(...args); }; return [data, exec, loading, error]; }; const useCreate = ( model: BaseModel, eventBus: EventTopic, ) => (): UseAsyncResult => { const [data, setData] = useState(); const [gotten, fetch, loading, error] = useAsync(model.create.bind(model)); useEffect(() => { function handleChange() { if (gotten && gotten.id) { setData(model.getLocalById(gotten.id)); } } eventBus.addEventListener(CHANGE_EVENT_TYPE, handleChange); return () => eventBus.removeEventListener(CHANGE_EVENT_TYPE, handleChange); }, [gotten]); useEffect(() => { setData(gotten); }, [gotten]); return [data, fetch, loading, error]; }; const useUpdateById = ( model: BaseModel, eventBus: EventTopic, ) => (id: Id): UseAsyncResult => { const [data, setData] = useState(); const [gotten, fetch, loading, error] = useAsync(model.update.bind(model)); async function handleChange() { const d = await model.getLocalById(id); setData(d); } useEffect(() => { handleChange(); }, []); useEffect(() => { eventBus.addEventListener(CHANGE_EVENT_TYPE, handleChange); return () => eventBus.removeEventListener(CHANGE_EVENT_TYPE, handleChange); }); useEffect(() => { setData(gotten); }, [gotten]); const exec = (...args: any[]) => fetch(id, ...args); return [data, exec, loading, error]; }; const useReplaceById = ( model: BaseModel, eventBus: EventTopic, ) => (id: Id): UseAsyncResult => { const [data, setData] = useState(); const [gotten, fetch, loading, error] = useAsync(model.replace.bind(model)); async function handleChange() { const d = await model.getLocalById(id); setData(d); } useEffect(() => { handleChange(); }, []); useEffect(() => { eventBus.addEventListener(CHANGE_EVENT_TYPE, handleChange); return () => eventBus.removeEventListener(CHANGE_EVENT_TYPE, handleChange); }); useEffect(() => { setData(gotten); }, [gotten]); const exec = (...args: any[]) => fetch(id, ...args); return [data, exec, loading, error]; }; const useDeleteById = ( model: BaseModel, eventBus: EventTopic, ) => (id: Id): UseDeleteResult => { const [ // @ts-ignore gotten, fetch, loading, error, ] = useAsync(model.del.bind(model)); const exec = (...args: any[]) => fetch(id, ...args); return [exec, loading, error]; };