/
TimurIsm
/
OpenEyes
Обзор
Документация
Войти
/
TimurIsm
/
OpenEyes
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
front/src/components/NavigationGuard.jsx
100 строк
3 KB
TimurIsm
first_commit
16 май 2026, 15:34
16 май 2026, 15:34
4d3f198
Код
Авторство
О чём код?
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react'; import { useNavigate, useLocation } from 'react-router-dom'; import ModalConfirm from '../modals/ModalConfirm'; const NavigationGuard = ({ when, message }) => { const [showModal, setShowModal] = useState(false); const [targetPath, setTargetPath] = useState(null); const navigate = useNavigate(); const location = useLocation(); const isConfirmedNavigation = useRef(false); const blockedPopState = useRef(false); const handleConfirm = useCallback(() => { isConfirmedNavigation.current = true; setShowModal(false); if (targetPath === 'POP') { window.history.go(-2); } else if (targetPath) { navigate(targetPath); } setTargetPath(null); blockedPopState.current = false; }, [navigate, targetPath]); const handleCancel = useCallback(() => { setShowModal(false); setTargetPath(null); blockedPopState.current = false; }, []); const handleNavigationClick = useCallback((e) => { const link = e.target.closest('a[href]'); if (!link) return; const href = link.getAttribute('href'); if (href?.startsWith('/') && href !== window.location.pathname) { e.preventDefault(); setTargetPath(href); setShowModal(true); } }, []); const handlePopState = useCallback((event) => { if (isConfirmedNavigation.current) { isConfirmedNavigation.current = false; return; } if (!when) return; event.preventDefault(); event.stopPropagation(); setTargetPath('POP'); setShowModal(true); blockedPopState.current = true; if (!window.history.state?.guarded) { window.history.pushState({ guarded: true }, ''); } }, [when]); useEffect(() => { if (!when) return; window.history.pushState({ guarded: true }, ''); document.addEventListener('click', handleNavigationClick, true); window.addEventListener('popstate', handlePopState); return () => { document.removeEventListener('click', handleNavigationClick, true); window.removeEventListener('popstate', handlePopState); isConfirmedNavigation.current = false; blockedPopState.current = false; if (window.history.state?.guarded) { window.history.back(); } }; }, [when, handleNavigationClick, handlePopState]); useEffect(() => { if (!when) return; const handleBeforeUnload = (e) => { e.returnValue = message; return message; }; window.addEventListener('beforeunload', handleBeforeUnload); return () => window.removeEventListener('beforeunload', handleBeforeUnload); }, [when, message]); const modalProps = useMemo(() => ({ isOpen: showModal, onClose: handleCancel, onConfirm: handleConfirm, message }), [showModal, handleCancel, handleConfirm, message]); return <ModalConfirm {...modalProps} />; }; export default React.memo(NavigationGuard);