0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-20 21:32:31 -05:00
logto/packages/ui/src/hooks/use-api.ts
simeng-li ab7a35267a
refactor(ui): useSocial hooks refactor (#956)
* refactor(ui): useSocial hooks refactor

useSOcial hooks refactor

* fix(ui): remove unnecsessary loading on setting query

remove unnecessary loading
2022-05-26 18:15:41 +08:00

98 lines
2.4 KiB
TypeScript

import { LogtoErrorCode } from '@logto/phrases';
import { RequestErrorBody } from '@logto/schemas';
import { HTTPError } from 'ky';
import { useState, useCallback, useContext, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { PageContext } from '@/hooks/use-page-context';
type UseApi<T extends any[], U> = {
result?: U;
error: RequestErrorBody | undefined;
run: (...args: T) => Promise<U | undefined>;
};
export type ErrorHandlers = {
[key in LogtoErrorCode]?: (error: RequestErrorBody) => void;
} & {
global?: (error: RequestErrorBody) => void; // Overwrite default global error handle logic
callback?: (error: RequestErrorBody) => void; // Callback method
};
function useApi<Args extends any[], Response>(
api: (...args: Args) => Promise<Response>,
errorHandlers?: ErrorHandlers
): UseApi<Args, Response> {
const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' });
const [error, setError] = useState<RequestErrorBody>();
const [result, setResult] = useState<Response>();
const { setLoading, setToast } = useContext(PageContext);
const parseError = useCallback(
async (error: unknown) => {
if (error instanceof HTTPError) {
try {
const kyError = await error.response.json<RequestErrorBody>();
setError(kyError);
} catch {
setToast(t('error.unknown'));
console.log(error);
}
return;
}
setToast(t('error.unknown'));
console.log(error);
},
[setToast, t]
);
const run = useCallback(
async (...args: Args) => {
setLoading(true);
// eslint-disable-next-line unicorn/no-useless-undefined
setError(undefined);
try {
const result = await api(...args);
setResult(result);
return result;
} catch (error: unknown) {
void parseError(error);
} finally {
setLoading(false);
}
},
[api, parseError, setLoading]
);
useEffect(() => {
if (!error) {
return;
}
const { code } = error;
const handler = errorHandlers?.[code] ?? errorHandlers?.global;
errorHandlers?.callback?.(error);
if (handler) {
handler(error);
return;
}
setToast(t('error.request', { ...error }));
}, [error, errorHandlers, setToast, t]);
return {
error,
result,
run,
};
}
export default useApi;