ConceptPortal-public/rsconcept/frontend/src/context/NavigationContext.tsx

113 lines
2.7 KiB
TypeScript
Raw Normal View History

'use client';
2023-09-05 00:23:53 +03:00
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
2023-12-13 15:03:58 +03:00
import { useLocation, useNavigate } from 'react-router-dom';
import { globalIDs } from '@/utils/constants';
2023-09-05 00:23:53 +03:00
2023-12-26 14:23:51 +03:00
interface INavigationContext{
push: (path: string) => void
replace: (path: string) => void
back: () => void
forward: () => void
canBack: () => boolean
isBlocked: boolean
setIsBlocked: (value: boolean) => void
2023-09-05 00:23:53 +03:00
}
2023-12-26 14:23:51 +03:00
const NavigationContext = createContext<INavigationContext | null>(null);
2023-09-05 00:23:53 +03:00
export const useConceptNavigation = () => {
2023-12-26 14:23:51 +03:00
const context = useContext(NavigationContext);
2023-09-05 00:23:53 +03:00
if (!context) {
throw new Error('useConceptNavigation has to be used within <NavigationState.Provider>');
}
return context;
}
interface NavigationStateProps {
children: React.ReactNode
}
export const NavigationState = ({ children }: NavigationStateProps) => {
const router = useNavigate();
2023-09-05 00:23:53 +03:00
const { pathname } = useLocation();
2023-12-13 15:03:58 +03:00
const [isBlocked, setIsBlocked] = useState(false);
2023-12-13 15:03:58 +03:00
const validate = useCallback(
() => {
2023-12-13 15:03:58 +03:00
return (
!isBlocked ||
confirm('Изменения не сохранены. Вы уверены что хотите совершить переход?')
);
}, [isBlocked]);
const canBack = useCallback(() => (!!window.history && window.history?.length !== 0), []);
const scrollTop = useCallback(
() => {
2023-09-05 00:23:53 +03:00
window.scrollTo(0, 0);
const mainScroll = document.getElementById(globalIDs.main_scroll);
if (mainScroll) {
mainScroll.scroll(0,0);
}
}, []);
2023-09-05 00:23:53 +03:00
const push = useCallback(
(path: string) => {
2023-12-13 15:03:58 +03:00
if (validate()) {
scrollTop();
router(path);
setIsBlocked(false);
}
}, [router, validate, scrollTop]);
2023-09-05 00:23:53 +03:00
const replace = useCallback(
(path: string) => {
2023-12-13 15:03:58 +03:00
if (validate()) {
scrollTop();
router(path, {replace: true});
setIsBlocked(false);
}
}, [router, validate, scrollTop]);
2023-09-05 00:23:53 +03:00
const back = useCallback(
() => {
2023-12-13 15:03:58 +03:00
if (validate()) {
scrollTop();
router(-1);
setIsBlocked(false);
}
}, [router, validate, scrollTop]);
const forward = useCallback(
() => {
2023-12-13 15:03:58 +03:00
if (validate()) {
scrollTop();
router(1);
setIsBlocked(false);
}
}, [router, validate, scrollTop]);
2023-09-05 00:23:53 +03:00
useEffect(() => {
scrollTop();
}, [pathname, scrollTop]);
2023-09-05 00:23:53 +03:00
return (
2023-12-26 14:23:51 +03:00
<NavigationContext.Provider value={{
push, replace, back, forward,
canBack, isBlocked, setIsBlocked
}}>
{children}
2023-12-26 14:23:51 +03:00
</NavigationContext.Provider>);
2023-09-05 00:23:53 +03:00
}
2023-12-13 15:03:58 +03:00
export function useBlockNavigation(isBlocked: boolean) {
const router = useConceptNavigation();
useEffect(
() => {
router.setIsBlocked(isBlocked);
return () => router.setIsBlocked(false);
}, [router, isBlocked]);
}