ra-core
Version:
Core components of react-admin, a frontend Framework for building admin applications on top of REST services, using ES6, React
154 lines • 6.63 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = require("react");
const react_query_1 = require("@tanstack/react-query");
const useAuthProvider_1 = __importStar(require("./useAuthProvider.cjs"));
const store_1 = require("../store/index.cjs");
const routing_1 = require("../routing/index.cjs");
const useCreatePath_1 = require("../routing/useCreatePath.cjs");
/**
* Get a callback for calling the authProvider.logout() method,
* redirect to the login page, and clear the store.
*
* @see useAuthProvider
*
* @returns {Function} logout callback
*
* @example
*
* import { useLogout } from 'react-admin';
*
* const LogoutButton = () => {
* const logout = useLogout();
* const handleClick = () => logout();
* return <button onClick={handleClick}>Logout</button>;
* }
*/
const useLogout = () => {
const authProvider = (0, useAuthProvider_1.default)();
const queryClient = (0, react_query_1.useQueryClient)();
const resetStore = (0, store_1.useResetStore)();
const navigate = (0, routing_1.useNavigate)();
const location = (0, routing_1.useLocation)();
const locationRef = (0, react_1.useRef)(location);
const basename = (0, routing_1.useBasename)();
const loginUrl = (0, useCreatePath_1.removeDoubleSlashes)(`${basename}/${useAuthProvider_1.defaultAuthParams.loginUrl}`);
/*
* We need the current location to pass in the router state
* so that the login hook knows where to redirect to as next route after login.
*
* But if we used the location from useLocation as a dependency of the logout
* function, it would be rebuilt each time the user changes location.
* Consequently, that would force a rerender of all components using this hook
* upon navigation (CoreAdminRouter for example).
*
* To avoid that, we store the location in a ref.
*/
(0, react_1.useEffect)(() => {
locationRef.current = location;
}, [location]);
const logout = (0, react_1.useCallback)((params = {}, redirectFromCaller, redirectToCurrentLocationAfterLogin = true) => {
if (authProvider) {
return authProvider.logout(params).then(redirectFromLogout => {
if (redirectFromLogout === false ||
redirectFromCaller === false) {
resetStore();
queryClient.clear();
// do not redirect
return;
}
const finalRedirectTo = redirectFromCaller || redirectFromLogout || loginUrl;
if (finalRedirectTo?.startsWith('http')) {
// absolute link (e.g. https://my.oidc.server/login)
resetStore();
queryClient.clear();
window.location.href = finalRedirectTo;
return finalRedirectTo;
}
// redirectTo is an internal location that may contain a query string, e.g. '/login?foo=bar'
// we must split it to pass a structured location to navigate()
const redirectToParts = finalRedirectTo.split('?');
const newLocation = {
pathname: redirectToParts[0],
};
let newLocationOptions = {};
if (redirectToCurrentLocationAfterLogin &&
locationRef.current &&
locationRef.current.pathname) {
newLocationOptions = {
state: {
nextPathname: locationRef.current.pathname,
nextSearch: locationRef.current.search,
},
};
}
if (redirectToParts[1]) {
newLocation.search = redirectToParts[1];
}
// We need to navigate and reset the store after a litte delay to avoid a race condition
// between the store reset and the navigation.
//
// This would only happen when the `authProvider.getPermissions` method returns
// a resolved promise with no delay: If the store was reset before the navigation,
// the `usePermissions` query would reset, causing the `CoreAdminRoutes` component to
// rerender the `LogoutOnMount` component leading to an infinite loop.
setTimeout(() => {
navigate(newLocation, newLocationOptions);
resetStore();
queryClient.clear();
}, 0);
return redirectFromLogout;
});
}
else {
navigate({
pathname: loginUrl,
}, {
state: {
nextPathname: locationRef.current &&
locationRef.current.pathname,
},
});
resetStore();
queryClient.clear();
return Promise.resolve();
}
}, [authProvider, resetStore, loginUrl, queryClient, navigate]);
return logout;
};
exports.default = useLogout;
module.exports = exports.default;
//# sourceMappingURL=useLogout.js.map