import axios, { type CancelToken } from 'axios'; import { defaultTo, includes, or, path, pathOr } from 'ramda'; import { useEffect, useState } from 'react'; import type { JsonDecoder } from 'ts.data.json'; import useSnackbar from '../../Snackbar/useSnackbar'; import { errorLog, warnLog } from '../logger'; import useCancelTokenSource from '../useCancelTokenSource'; export interface RequestParams { decoder?: JsonDecoder.Decoder; defaultFailureMessage?: string; getErrorMessage?: (error: unknown) => string; httpCodesBypassErrorSnackbar?: Array; request: (token: CancelToken) => (params?: unknown) => Promise; } export interface RequestResult { sendRequest: (params?: unknown) => Promise; sending: boolean; } const useRequest = ({ request, decoder, getErrorMessage, defaultFailureMessage = 'Oops, something went wrong', httpCodesBypassErrorSnackbar = [] }: RequestParams): RequestResult => { const { token, cancel } = useCancelTokenSource(); const { showErrorMessage } = useSnackbar(); const [sending, setSending] = useState(false); useEffect(() => { return (): void => cancel(); }, [cancel]); const showRequestErrorMessage = (error: { message?: string }): void => { errorLog(error.message ?? ''); const message = or( pathOr(undefined, ['response', 'data', 'message'], error), pathOr(defaultFailureMessage, ['response', 'data'], error) ); const errorMessage = defaultTo(message, getErrorMessage?.(error)); showErrorMessage(errorMessage as string); }; const sendRequest = (params?: unknown): Promise => { setSending(true); return request(token)(params) .then((data) => { setSending(false); if (decoder) { return decoder.decodeToPromise(data); } return data; }) .catch((error) => { setSending(false); if (axios.isCancel(error)) { warnLog(error as unknown as string); throw error; } const hasACorrespondingHttpCode = includes( path(['response', 'status'], error) as number, httpCodesBypassErrorSnackbar ); if (hasACorrespondingHttpCode) { throw error; } showRequestErrorMessage(error); throw error; }); }; return { sending, sendRequest }; }; export default useRequest;