mirror of
https://github.com/outline/outline.git
synced 2026-06-13 11:25:03 +03:00
1f097b0fdd
* chore: resolve no-explicit-any lint warnings in plugins Replaces uses of `any` in the plugins directory with concrete types, `unknown`, or structured type assertions, addressing the remaining typescript-eslint(no-explicit-any) warnings flagged by oxlint. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: address review feedback in GitLabIssueProvider Drop trailing semicolon from log string and add early return in `destroyNamespace` when neither `user_id` nor `full_path` is present to avoid an unnecessary full-scan transaction. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
116 lines
3.3 KiB
TypeScript
116 lines
3.3 KiB
TypeScript
import { useCallback, useRef } from "react";
|
|
import { getCookie, removeCookie, setCookie } from "tiny-cookie";
|
|
import usePersistedState, {
|
|
setPersistedState,
|
|
} from "~/hooks/usePersistedState";
|
|
import Logger from "~/utils/Logger";
|
|
import history from "~/utils/history";
|
|
import { isAllowedLoginRedirect } from "~/utils/urls";
|
|
|
|
/**
|
|
* Hook to set locally and return the document or collection that the user last visited. This is
|
|
* used to redirect the user back to the last page they were on, if preferred.
|
|
*
|
|
* @returns A tuple of the last visited path and a method to set it.
|
|
*/
|
|
export function useLastVisitedPath(): [string, (path: string) => void] {
|
|
const [lastVisitedPath, setLastVisitedPath] = usePersistedState<string>(
|
|
"lastVisitedPath",
|
|
"/",
|
|
{ listen: false }
|
|
);
|
|
|
|
const setPathAsLastVisitedPath = useCallback(
|
|
(path: string) => {
|
|
if (isAllowedLoginRedirect(path) && path !== lastVisitedPath) {
|
|
setLastVisitedPath(path);
|
|
}
|
|
},
|
|
[lastVisitedPath, setLastVisitedPath]
|
|
);
|
|
|
|
return [lastVisitedPath, setPathAsLastVisitedPath] as const;
|
|
}
|
|
|
|
/**
|
|
* Hook that automatically tracks the current path as the last visited path.
|
|
* This uses a ref to track the previous path and updates localStorage directly
|
|
* without using useEffect to avoid React Doctor warnings.
|
|
*
|
|
* @param currentPath The current path to track.
|
|
*/
|
|
export function useTrackLastVisitedPath(currentPath: string): void {
|
|
const prevPathRef = useRef<string>();
|
|
|
|
// Update localStorage directly if path has changed
|
|
if (
|
|
prevPathRef.current !== currentPath &&
|
|
isAllowedLoginRedirect(currentPath)
|
|
) {
|
|
prevPathRef.current = currentPath;
|
|
setPersistedState("lastVisitedPath", currentPath);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the path that the user visited before being asked to login.
|
|
*
|
|
* @param path The path to set as the post login path.
|
|
*/
|
|
export function setPostLoginPath(path: string) {
|
|
const key = "postLoginRedirectPath";
|
|
|
|
if (isAllowedLoginRedirect(path)) {
|
|
setCookie(key, path, { expires: 1 });
|
|
|
|
try {
|
|
sessionStorage.setItem(key, path);
|
|
} catch (_err) {
|
|
// If the session storage is full or inaccessible, we can't do anything about it.
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hook to set locally and return the path that the user visited before being asked
|
|
* to login.
|
|
*
|
|
* @returns A tuple of getter and setter for the post login path.
|
|
*/
|
|
export function usePostLoginPath() {
|
|
const key = "postLoginRedirectPath";
|
|
|
|
const getter = useCallback(() => {
|
|
let path;
|
|
try {
|
|
path = sessionStorage.getItem(key) || getCookie(key);
|
|
} catch (_err) {
|
|
// Expected error if the session storage is full or inaccessible.
|
|
}
|
|
|
|
if (path) {
|
|
Logger.info("lifecycle", "Spending post login path", { path });
|
|
|
|
// Remove the cookie once the app has been navigated to the post login path. We dont
|
|
// do this immediately as React StrictMode will render multiple times.
|
|
const cleanup = history.listen(() => {
|
|
try {
|
|
sessionStorage.removeItem(key);
|
|
} catch (_err) {
|
|
// Expected error if the session storage is full or inaccessible.
|
|
}
|
|
removeCookie(key);
|
|
cleanup?.();
|
|
});
|
|
|
|
if (isAllowedLoginRedirect(path)) {
|
|
return path;
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}, []);
|
|
|
|
return [getter, setPostLoginPath] as const;
|
|
}
|