diff --git a/rsconcept/frontend/src/App.tsx b/rsconcept/frontend/src/App.tsx index ffa2af93..c9a5e206 100644 --- a/rsconcept/frontend/src/App.tsx +++ b/rsconcept/frontend/src/App.tsx @@ -1,4 +1,4 @@ -import { Route, Routes } from 'react-router-dom'; +import { createBrowserRouter, Outlet, RouterProvider } from 'react-router-dom'; import Footer from './components/Footer'; import Navigation from './components/Navigation/Navigation'; @@ -15,8 +15,8 @@ import RestorePasswordPage from './pages/RestorePasswordPage'; import RSFormPage from './pages/RSFormPage'; import UserProfilePage from './pages/UserProfilePage'; -function App () { - const { noNavigation, noFooter, viewportHeight, mainHeight } = useConceptTheme(); +function Root() { + const { noNavigation, noFooter, viewportHeight, mainHeight } = useConceptTheme(); return (
@@ -26,24 +26,9 @@ function App () { draggable={false} pauseOnFocusLoss={false} /> -
- - } /> - - } /> - } /> - } /> - } /> - - } /> - - } /> - } /> - } /> - } /> - +
{!noNavigation && !noFooter &&
}
@@ -51,4 +36,57 @@ function App () { ); } +const router = createBrowserRouter([ + { + path: '/', + element: , + errorElement: , + children: [ + { + path: '', + element: , + }, + { + path: 'login', + element: , + }, + { + path: 'signup', + element: , + }, + { + path: 'restore-password', + element: , + }, + { + path: 'profile', + element: , + }, + { + path: 'manuals', + element: , + }, + + { + path: 'library', + element: , + }, + { + path: 'rsforms/:id', + element: , + }, + { + path: 'rsform-create', + element: , + }, + ] + }, +]); + +function App () { + return ( + + ); +} + export default App; diff --git a/rsconcept/frontend/src/hooks/useModificationPrompt.ts b/rsconcept/frontend/src/hooks/useModificationPrompt.ts new file mode 100644 index 00000000..81cd5d28 --- /dev/null +++ b/rsconcept/frontend/src/hooks/useModificationPrompt.ts @@ -0,0 +1,14 @@ +import { useState } from 'react'; +import { unstable_usePrompt } from 'react-router-dom'; + +function usePromptUnsaved() { + const [isModified, setIsModified] = useState(false); + unstable_usePrompt({ + when: isModified, + message: 'Изменения не сохранены. Вы уверены что хотите совершить переход?' + }); + + return {isModified, setIsModified}; +} + +export default usePromptUnsaved; \ No newline at end of file diff --git a/rsconcept/frontend/src/main.tsx b/rsconcept/frontend/src/main.tsx index bd8722ca..1030cfd4 100644 --- a/rsconcept/frontend/src/main.tsx +++ b/rsconcept/frontend/src/main.tsx @@ -4,7 +4,6 @@ import React from 'react' import ReactDOM from 'react-dom/client' import { ErrorBoundary } from 'react-error-boundary'; import { IntlProvider } from 'react-intl'; -import { BrowserRouter } from 'react-router-dom'; import App from './App.tsx' import ErrorFallback from './components/ErrorFallback.tsx'; @@ -27,7 +26,6 @@ const logError = (error: Error, info: { componentStack: string }) => { ReactDOM.createRoot(document.getElementById('root')!).render( - - , ) diff --git a/rsconcept/frontend/src/pages/HomePage.tsx b/rsconcept/frontend/src/pages/HomePage.tsx index a1cb99a5..1184cdca 100644 --- a/rsconcept/frontend/src/pages/HomePage.tsx +++ b/rsconcept/frontend/src/pages/HomePage.tsx @@ -21,7 +21,7 @@ function HomePage() { }, [navigate, user]) return ( -
+

Лендинг находится в разработке. Данная страница видна только пользователям с правами администратора.

); diff --git a/rsconcept/frontend/src/pages/NotFoundPage.tsx b/rsconcept/frontend/src/pages/NotFoundPage.tsx index 27a23c8a..f8906642 100644 --- a/rsconcept/frontend/src/pages/NotFoundPage.tsx +++ b/rsconcept/frontend/src/pages/NotFoundPage.tsx @@ -1,8 +1,11 @@ +import TextURL from '../components/Common/TextURL'; + export function NotFoundPage() { return ( -
-

Error 404 - Not Found

-

Данная страница не существует или запрашиваемый объект отсутствует в базы данных

+
+

Ошибка 404 - Страница не найдена

+

Данная страница не существует или запрашиваемый объект отсутствует в базе данных

+
); } diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx index abb37287..cea063aa 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx @@ -9,6 +9,7 @@ import TextArea from '../../components/Common/TextArea'; import HelpConstituenta from '../../components/Help/HelpConstituenta'; import { DumpBinIcon, HelpIcon, PenIcon, SaveIcon, SmallPlusIcon } from '../../components/Icons'; import { useRSForm } from '../../context/RSFormContext'; +import useModificationPrompt from '../../hooks/useModificationPrompt'; import { CstType, EditMode, ICstCreateData, ICstRenameData, ICstUpdateData, SyntaxTree } from '../../utils/models'; import { getCstTypificationLabel } from '../../utils/staticUI'; import EditorRSExpression from './EditorRSExpression'; @@ -33,7 +34,8 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onO return schema?.items?.find((cst) => cst.id === activeID); }, [schema?.items, activeID]); - const [isModified, setIsModified] = useState(false); + const { isModified, setIsModified } = useModificationPrompt(); + const [editMode, setEditMode] = useState(EditMode.TEXT); const [alias, setAlias] = useState(''); @@ -59,7 +61,7 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onO ); }, [activeCst, activeCst?.term, activeCst?.definition.formal, activeCst?.definition.text.raw, activeCst?.convention, - term, textDefinition, expression, convention]); + term, textDefinition, expression, convention, setIsModified]); useLayoutEffect( () => { diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm.tsx index a2682356..ef1d81aa 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm.tsx @@ -13,6 +13,7 @@ import { CrownIcon, DownloadIcon, DumpBinIcon, HelpIcon, SaveIcon, ShareIcon } f import { useAuth } from '../../context/AuthContext'; import { useRSForm } from '../../context/RSFormContext'; import { useUsers } from '../../context/UsersContext'; +import useModificationPrompt from '../../hooks/useModificationPrompt'; import { IRSFormCreateData, LibraryItemType } from '../../utils/models'; interface EditorRSFormProps { @@ -37,7 +38,7 @@ function EditorRSForm({ onDestroy, onClaim, onShare, onDownload }: EditorRSFormP const [common, setCommon] = useState(false); const [canonical, setCanonical] = useState(false); - const [isModified, setIsModified] = useState(true); + const { isModified, setIsModified } = useModificationPrompt(); useLayoutEffect(() => { if (!schema) { @@ -53,7 +54,7 @@ function EditorRSForm({ onDestroy, onClaim, onShare, onDownload }: EditorRSFormP ); }, [schema, schema?.title, schema?.alias, schema?.comment, schema?.is_common, schema?.is_canonical, - title, alias, comment, common, canonical]); + title, alias, comment, common, canonical, setIsModified]); useLayoutEffect(() => { if (schema) { diff --git a/rsconcept/frontend/src/pages/UserProfilePage/EditorProfile.tsx b/rsconcept/frontend/src/pages/UserProfilePage/EditorProfile.tsx index 5e3cac26..14a15cea 100644 --- a/rsconcept/frontend/src/pages/UserProfilePage/EditorProfile.tsx +++ b/rsconcept/frontend/src/pages/UserProfilePage/EditorProfile.tsx @@ -4,6 +4,7 @@ import { toast } from 'react-toastify'; import SubmitButton from '../../components/Common/SubmitButton'; import TextInput from '../../components/Common/TextInput'; import { useUserProfile } from '../../context/UserProfileContext'; +import useModificationPrompt from '../../hooks/useModificationPrompt'; import { IUserUpdateData } from '../../utils/models'; function EditorProfile() { @@ -14,7 +15,7 @@ function EditorProfile() { const [first_name, setFirstName] = useState(''); const [last_name, setLastName] = useState(''); - const [isModified, setIsModified] = useState(true); + const { isModified, setIsModified } = useModificationPrompt(); useLayoutEffect(() => { if (!user) { @@ -26,7 +27,7 @@ function EditorProfile() { user.first_name !== first_name || user.last_name !== last_name ); - }, [user, user?.email, user?.first_name, user?.last_name, email, first_name, last_name]); + }, [user, user?.email, user?.first_name, user?.last_name, email, first_name, last_name, setIsModified]); useLayoutEffect(() => { if (user) {