karusic/front2/src/utils/data-store.ts

137 lines
3.9 KiB
TypeScript

/** @file
* @author Edouard DUPIN
* @copyright 2024, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { DependencyList, useCallback, useEffect, useState } from 'react';
import { RestErrorResponse } from '@/back-api';
import { useToastAPIError } from '@/utils/toastHook';
import { isNullOrUndefined } from '@/utils/validator';
export type DataStoreType<TYPE> = {
isLoading: boolean;
error: RestErrorResponse | undefined;
data: TYPE[];
get: <MODEL>(value: MODEL, key?: string) => TYPE | undefined;
gets: <MODEL>(value: MODEL[] | undefined, key?: string) => TYPE[];
update: (request: Promise<TYPE>, key?: string) => void;
remove: (id: number | string, request: Promise<void>, key?: string) => void;
};
export const useDataStore = <TYPE>(
{
primaryKey = 'id',
restApiName,
available = true,
getsCall,
}: {
restApiName?: string;
primaryKey?: string;
available?: boolean;
getsCall: () => Promise<TYPE[]>;
},
deps: DependencyList = []
): DataStoreType<TYPE> => {
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<RestErrorResponse | undefined>(undefined);
const [data, setData] = useState<TYPE[]>([]);
const toastAPIError = useToastAPIError();
// on instantiation ==> call the request of the data...
useEffect(() => {
setError(undefined);
setIsLoading(true);
if (!available) {
console.log(`[${restApiName}] NOT call data. service not available`);
return;
}
console.log(`[${restApiName}] call data ...`);
getsCall()
.then((response: TYPE[]) => {
/*console.log(
`[${restApiName}] getData Response: ${JSON.stringify(response, null, 2)}`
);*/
setData(response);
setError(undefined);
setIsLoading(false);
})
.catch((error: RestErrorResponse) => {
toastAPIError(error);
console.log(
`[${restApiName}] catch error: ${JSON.stringify(error, null, 2)}`
);
setError(error);
setIsLoading(false);
});
}, [setIsLoading, setData, ...deps]);
const get = useCallback(
<MODEL>(value: MODEL, key?: string): TYPE | undefined => {
const keyValue = key ?? primaryKey;
for (let iii = 0; iii < data.length; iii++) {
if (data[iii][keyValue] === value) {
return data[iii];
}
}
return undefined;
},
[data]
);
const gets = useCallback(
<MODEL>(value: MODEL[] | undefined, key?: string): TYPE[] => {
const keyValue = key ?? primaryKey;
const out: TYPE[] = [];
if (isNullOrUndefined(value)) {
return out;
}
for (let iii = 0; iii < data.length; iii++) {
if (value.includes(data[iii][keyValue])) {
out.push(data[iii]);
}
}
return out;
},
[data]
);
const update = useCallback(
(request: Promise<TYPE>, key?: string) => {
const keyValue = key ?? primaryKey;
request
.then((responseData: TYPE) => {
const filterData = data.filter(
(localData: TYPE) => localData[keyValue] !== responseData[keyValue]
);
filterData.push(responseData);
setData(filterData);
})
.catch((error: RestErrorResponse) => {
toastAPIError(error);
});
},
[data, setData]
);
const remove = useCallback(
(id: number | string, request: Promise<void>, key?: string) => {
const keyValue = key ?? primaryKey;
request
.then(() => {
const filterData = data.filter(
(localData: TYPE) => localData[keyValue] !== id
);
setData(filterData);
})
.catch((error) => {
toastAPIError(error);
console.log(
`catch an error on delete: ... ${JSON.stringify(error, null, 2)}`
);
});
},
[data, setData]
);
return { isLoading, error, data, get, gets, update, remove };
};