Files
YANPM/apps/frontend/app/hooks/ResponseHelper.tsx
2025-12-20 14:32:42 +08:00

74 lines
2.4 KiB
TypeScript

import { AxiosError } from 'axios';
import { useLocation, useNavigate } from 'react-router';
import { SearchParamKeys } from '../lib/constants';
import { useQueryMessage } from './useQueryMessage';
import { QueryMessageCode, QueryMessageType } from '../lib/QueryMessages';
import { useCallback } from 'react';
import { displayForbiddenErrorToast, displayNetworkErrorToast, displayUnexpectedErrorToast } from '../lib/toasts';
export enum ResponseErrorToastId {
NetworkError = 'network-error',
}
export type DefaultResponseErrorHandlerOptions = {
disableUnauthorizedHandling?: boolean;
disableHandleUnexpectedErrors?: boolean;
disableIgnoreCanceledRequests?: boolean;
};
/**
*
* @param err error value
* @returns {boolean} true if the error was handled, false otherwise
*/
export function useResponseErrorHandler(): {
defaultResponseErrorHandler: typeof defaultResponseErrorHandler;
} {
const navigate = useNavigate();
const location = useLocation();
const { toSearchParamQueryMessage } = useQueryMessage();
const defaultResponseErrorHandler = useCallback(
(err: unknown, options?: DefaultResponseErrorHandlerOptions): boolean => {
if (!(err instanceof AxiosError) && !options?.disableHandleUnexpectedErrors) {
displayUnexpectedErrorToast();
return true;
}
if (!(err instanceof AxiosError)) return false;
if (err.message === 'canceled') {
// request was aborted, ignore but return true to indicate it was handled
return !options?.disableIgnoreCanceledRequests;
}
if (err.message === 'Network Error') {
displayNetworkErrorToast();
return true;
}
// handle 401 Unauthorized globally
if (err.status === 401 && !options?.disableUnauthorizedHandling) {
// store current path for redirect after login
const currentPath = location.pathname + location.search;
const searchParam = new URLSearchParams();
searchParam.set(SearchParamKeys.Redirect, currentPath);
searchParam.set(SearchParamKeys.Message, toSearchParamQueryMessage(QueryMessageCode.SessionExpired, QueryMessageType.Info));
navigate(`/login?${searchParam.toString()}`);
return true;
}
if (err.status === 403) {
displayForbiddenErrorToast();
return true;
}
return false;
},
[location, navigate, toSearchParamQueryMessage]
);
return { defaultResponseErrorHandler };
}