ra-core
Version:
Core components of react-admin, a frontend Framework for building admin applications on top of REST services, using ES6, React
112 lines • 4.18 kB
JavaScript
import { useCallback } from 'react';
import useAuthProvider from "./useAuthProvider.js";
import useLogout from "./useLogout.js";
import { useNotify } from "../notification/index.js";
import { useNavigate } from "../routing/useNavigate.js";
let timer;
/**
* Returns a callback used to call the authProvider.checkError() method
* and an error from the dataProvider. If the authProvider rejects the call,
* the hook logs the user out and shows a logged out notification.
*
* Used in the useDataProvider hook to check for access denied responses
* (e.g. 401 or 403 responses) and trigger a logout.
*
* @see useLogout
* @see useDataProvider
*
* @returns {Function} logoutIfAccessDenied callback
*
* @example
*
* import { useLogoutIfAccessDenied, useNotify, DataProviderContext } from 'react-admin';
*
* const FetchRestrictedResource = () => {
* const dataProvider = useContext(DataProviderContext);
* const logoutIfAccessDenied = useLogoutIfAccessDenied();
* const notify = useNotify()
* useEffect(() => {
* dataProvider.getOne('secret', { id: 123 })
* .catch(error => {
* logoutIfAccessDenied(error);
* notify('server error', { type: 'error' });
* })
* }, []);
* // ...
* }
*/
const useLogoutIfAccessDenied = () => {
const authProvider = useAuthProvider();
const logout = useLogout();
const notify = useNotify();
const navigate = useNavigate();
const handleRedirect = useCallback((url) => {
if (url.startsWith('http')) {
window.location.href = url;
}
else {
navigate(url);
}
}, [navigate]);
const logoutIfAccessDenied = useCallback(async (errorFromCheckAuth) => {
if (!authProvider) {
return logoutIfAccessDeniedWithoutProvider();
}
try {
await authProvider.checkError(errorFromCheckAuth);
return false;
}
catch (errorFromCheckError) {
const logoutUser = errorFromCheckError?.logoutUser ?? true;
// manual debounce
if (timer) {
return true; // side effects already triggered in this tick, exit
}
timer = setTimeout(() => {
timer = undefined;
}, 0);
const redirectTo = errorFromCheckError &&
errorFromCheckError.redirectTo != null
? errorFromCheckError.redirectTo
: errorFromCheckAuth && errorFromCheckAuth.redirectTo
? errorFromCheckAuth.redirectTo
: undefined;
const shouldNotify = !((errorFromCheckError &&
errorFromCheckError.message === false) ||
(errorFromCheckAuth &&
errorFromCheckAuth.message === false) ||
redirectTo?.startsWith('http'));
if (shouldNotify) {
try {
// notify only if not yet logged out
await authProvider.checkAuth({});
if (logoutUser) {
notify(getErrorMessage(errorFromCheckError, 'ra.notification.logged_out'), { type: 'error' });
}
else {
notify(getErrorMessage(errorFromCheckError, 'ra.notification.not_authorized'), { type: 'error' });
}
}
catch {
// ignore
}
}
if (logoutUser) {
logout({}, redirectTo);
}
else if (redirectTo) {
handleRedirect(redirectTo);
}
return true;
}
}, [authProvider, logout, notify, handleRedirect]);
return logoutIfAccessDenied;
};
const logoutIfAccessDeniedWithoutProvider = async () => false;
const getErrorMessage = (error, defaultMessage) => typeof error === 'string'
? error
: typeof error === 'undefined' || !error.message
? defaultMessage
: error.message;
export default useLogoutIfAccessDenied;
//# sourceMappingURL=useLogoutIfAccessDenied.js.map