2024-04-17 15:02:03 +03:00
|
|
|
import { useCallback, useEffect, useMemo } from "react";
|
2023-12-31 16:35:15 +03:00
|
|
|
import { useLocation, useNavigate } from "react-router-dom";
|
2024-03-14 17:27:27 +03:00
|
|
|
import { usePersistence } from "./use-persistence";
|
2023-12-31 16:35:15 +03:00
|
|
|
|
2024-03-19 23:56:38 +03:00
|
|
|
export function useOverlayState<S>(
|
2024-03-05 02:18:30 +03:00
|
|
|
key: string,
|
2024-03-07 04:17:35 +03:00
|
|
|
defaultValue: S | undefined = undefined,
|
|
|
|
|
): [S | undefined, (value: S, replace?: boolean) => void] {
|
2023-12-31 16:35:15 +03:00
|
|
|
const location = useLocation();
|
|
|
|
|
const navigate = useNavigate();
|
2024-05-02 05:23:03 +03:00
|
|
|
|
|
|
|
|
const currentLocationState = useMemo(() => location.state, [location]);
|
2023-12-31 16:35:15 +03:00
|
|
|
|
|
|
|
|
const setOverlayStateValue = useCallback(
|
2024-03-07 04:17:35 +03:00
|
|
|
(value: S, replace: boolean = false) => {
|
2023-12-31 16:35:15 +03:00
|
|
|
const newLocationState = { ...currentLocationState };
|
|
|
|
|
newLocationState[key] = value;
|
2024-03-05 02:18:30 +03:00
|
|
|
navigate(location.pathname, { state: newLocationState, replace });
|
2023-12-31 16:35:15 +03:00
|
|
|
},
|
2024-02-29 01:23:56 +03:00
|
|
|
// we know that these deps are correct
|
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
2024-05-02 05:23:03 +03:00
|
|
|
[key, currentLocationState, navigate],
|
2023-12-31 16:35:15 +03:00
|
|
|
);
|
|
|
|
|
|
2024-03-07 04:17:35 +03:00
|
|
|
const overlayStateValue = useMemo<S | undefined>(
|
2024-03-05 02:18:30 +03:00
|
|
|
() => location.state && location.state[key],
|
|
|
|
|
[location, key],
|
|
|
|
|
);
|
|
|
|
|
|
2024-03-07 04:17:35 +03:00
|
|
|
return [overlayStateValue ?? defaultValue, setOverlayStateValue];
|
2023-12-31 16:35:15 +03:00
|
|
|
}
|
2024-03-14 17:27:27 +03:00
|
|
|
|
|
|
|
|
export function usePersistedOverlayState<S extends string>(
|
|
|
|
|
key: string,
|
|
|
|
|
defaultValue: S | undefined = undefined,
|
2024-05-07 17:28:10 +03:00
|
|
|
): [
|
|
|
|
|
S | undefined,
|
|
|
|
|
(value: S | undefined, replace?: boolean) => void,
|
|
|
|
|
() => void,
|
|
|
|
|
] {
|
2024-03-14 17:27:27 +03:00
|
|
|
const location = useLocation();
|
|
|
|
|
const navigate = useNavigate();
|
2024-05-02 05:23:03 +03:00
|
|
|
const currentLocationState = useMemo(() => location.state, [location]);
|
2024-03-14 17:27:27 +03:00
|
|
|
|
2024-07-24 20:17:32 +03:00
|
|
|
// currently selected value
|
|
|
|
|
|
|
|
|
|
const overlayStateValue = useMemo<S | undefined>(
|
|
|
|
|
() => location.state && location.state[key],
|
|
|
|
|
[location, key],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// saved value from previous session
|
|
|
|
|
|
|
|
|
|
const [persistedValue, setPersistedValue, , deletePersistedValue] =
|
|
|
|
|
usePersistence<S>(key, overlayStateValue);
|
|
|
|
|
|
2024-03-14 17:27:27 +03:00
|
|
|
const setOverlayStateValue = useCallback(
|
|
|
|
|
(value: S | undefined, replace: boolean = false) => {
|
|
|
|
|
setPersistedValue(value);
|
|
|
|
|
const newLocationState = { ...currentLocationState };
|
|
|
|
|
newLocationState[key] = value;
|
|
|
|
|
navigate(location.pathname, { state: newLocationState, replace });
|
|
|
|
|
},
|
|
|
|
|
// we know that these deps are correct
|
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
2024-05-02 05:23:03 +03:00
|
|
|
[key, currentLocationState, navigate],
|
2024-03-14 17:27:27 +03:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
overlayStateValue ?? persistedValue ?? defaultValue,
|
|
|
|
|
setOverlayStateValue,
|
2024-05-07 17:28:10 +03:00
|
|
|
deletePersistedValue,
|
2024-03-14 17:27:27 +03:00
|
|
|
];
|
|
|
|
|
}
|
2024-03-15 21:46:17 +03:00
|
|
|
|
|
|
|
|
export function useHashState<S extends string>(): [
|
|
|
|
|
S | undefined,
|
|
|
|
|
(value: S) => void,
|
|
|
|
|
] {
|
|
|
|
|
const location = useLocation();
|
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
|
|
|
|
|
const setHash = useCallback(
|
|
|
|
|
(value: S | undefined) => {
|
|
|
|
|
if (!value) {
|
|
|
|
|
navigate(location.pathname);
|
|
|
|
|
} else {
|
2024-03-17 15:29:59 +03:00
|
|
|
navigate(`${location.pathname}#${value}`, { state: location.state });
|
2024-03-15 21:46:17 +03:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// we know that these deps are correct
|
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
[location, navigate],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const hash = useMemo(
|
|
|
|
|
() => location.hash.substring(1) as unknown as S,
|
|
|
|
|
[location.hash],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return [hash, setHash];
|
|
|
|
|
}
|
2024-04-17 15:02:03 +03:00
|
|
|
|
|
|
|
|
export function useSearchEffect(
|
|
|
|
|
key: string,
|
|
|
|
|
callback: (value: string) => void,
|
|
|
|
|
) {
|
|
|
|
|
const location = useLocation();
|
|
|
|
|
|
|
|
|
|
const param = useMemo(() => {
|
|
|
|
|
if (!location || !location.search || location.search.length == 0) {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const params = location.search.substring(1).split("&");
|
|
|
|
|
|
2024-06-13 00:03:00 +03:00
|
|
|
const foundParam = params
|
2024-04-17 15:02:03 +03:00
|
|
|
.find((p) => p.includes("=") && p.split("=")[0] == key)
|
|
|
|
|
?.split("=");
|
2024-06-13 00:03:00 +03:00
|
|
|
|
|
|
|
|
if (foundParam && foundParam.length === 2) {
|
|
|
|
|
return [foundParam[0], decodeURIComponent(foundParam[1])];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return undefined;
|
2024-04-17 15:02:03 +03:00
|
|
|
}, [location, key]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!param) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
callback(param[1]);
|
|
|
|
|
}, [param, callback]);
|
|
|
|
|
}
|