2023-12-13 14:32:57 +03:00
|
|
|
'use client';
|
2023-09-05 00:23:53 +03:00
|
|
|
|
2023-12-13 14:32:57 +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';
|
2023-12-13 14:32:57 +03:00
|
|
|
|
|
|
|
import { globalIDs } from '@/utils/constants';
|
2023-09-05 00:23:53 +03:00
|
|
|
|
|
|
|
interface INagivationContext{
|
2023-12-13 14:32:57 +03:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
const NagivationContext = createContext<INagivationContext | null>(null);
|
|
|
|
export const useConceptNavigation = () => {
|
|
|
|
const context = useContext(NagivationContext);
|
|
|
|
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) => {
|
2023-12-13 14:32:57 +03:00
|
|
|
const router = useNavigate();
|
2023-09-05 00:23:53 +03:00
|
|
|
const { pathname } = useLocation();
|
2023-12-13 15:03:58 +03:00
|
|
|
|
2023-12-13 14:32:57 +03:00
|
|
|
const [isBlocked, setIsBlocked] = useState(false);
|
2023-12-13 15:03:58 +03:00
|
|
|
const validate = useCallback(
|
2023-12-13 14:32:57 +03:00
|
|
|
() => {
|
2023-12-13 15:03:58 +03:00
|
|
|
return (
|
|
|
|
!isBlocked ||
|
|
|
|
confirm('Изменения не сохранены. Вы уверены что хотите совершить переход?')
|
|
|
|
);
|
|
|
|
}, [isBlocked]);
|
|
|
|
|
|
|
|
const canBack = useCallback(() => (!!window.history && window.history?.length !== 0), []);
|
2023-12-13 14:32:57 +03:00
|
|
|
|
|
|
|
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-12-13 14:32:57 +03:00
|
|
|
}, []);
|
2023-09-05 00:23:53 +03:00
|
|
|
|
2023-12-13 14:32:57 +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
|
|
|
|
2023-12-13 14:32:57 +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
|
|
|
|
2023-12-13 14:32:57 +03:00
|
|
|
const back = useCallback(
|
|
|
|
() => {
|
2023-12-13 15:03:58 +03:00
|
|
|
if (validate()) {
|
|
|
|
scrollTop();
|
|
|
|
router(-1);
|
|
|
|
setIsBlocked(false);
|
|
|
|
}
|
|
|
|
}, [router, validate, scrollTop]);
|
2023-12-13 14:32:57 +03:00
|
|
|
|
|
|
|
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
|
|
|
|
2023-12-13 14:32:57 +03:00
|
|
|
useEffect(() => {
|
|
|
|
scrollTop();
|
|
|
|
}, [pathname, scrollTop]);
|
2023-09-05 00:23:53 +03:00
|
|
|
|
|
|
|
return (
|
2023-12-05 01:22:44 +03:00
|
|
|
<NagivationContext.Provider value={{
|
2023-12-13 14:32:57 +03:00
|
|
|
push, replace, back, forward,
|
|
|
|
canBack, isBlocked, setIsBlocked
|
2023-12-05 01:22:44 +03:00
|
|
|
}}>
|
|
|
|
{children}
|
|
|
|
</NagivationContext.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]);
|
|
|
|
}
|