mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Refactor navigation
This commit is contained in:
parent
895ad1554b
commit
b53fe27b1e
|
@ -3,6 +3,7 @@ import { createBrowserRouter, Outlet, RouterProvider } from 'react-router-dom';
|
||||||
import ConceptToaster from './components/ConceptToaster';
|
import ConceptToaster from './components/ConceptToaster';
|
||||||
import Footer from './components/Footer';
|
import Footer from './components/Footer';
|
||||||
import Navigation from './components/Navigation/Navigation';
|
import Navigation from './components/Navigation/Navigation';
|
||||||
|
import { NavigationState } from './context/NagivationContext';
|
||||||
import { useConceptTheme } from './context/ThemeContext';
|
import { useConceptTheme } from './context/ThemeContext';
|
||||||
import CreateRSFormPage from './pages/CreateRSFormPage';
|
import CreateRSFormPage from './pages/CreateRSFormPage';
|
||||||
import HomePage from './pages/HomePage';
|
import HomePage from './pages/HomePage';
|
||||||
|
@ -14,25 +15,36 @@ import RegisterPage from './pages/RegisterPage';
|
||||||
import RestorePasswordPage from './pages/RestorePasswordPage';
|
import RestorePasswordPage from './pages/RestorePasswordPage';
|
||||||
import RSFormPage from './pages/RSFormPage';
|
import RSFormPage from './pages/RSFormPage';
|
||||||
import UserProfilePage from './pages/UserProfilePage';
|
import UserProfilePage from './pages/UserProfilePage';
|
||||||
|
import { globalIDs } from './utils/constants';
|
||||||
|
|
||||||
function Root() {
|
function Root() {
|
||||||
const { noNavigation, noFooter, viewportHeight, mainHeight } = useConceptTheme();
|
const { noNavigation, noFooter, viewportHeight, mainHeight, showScroll } = useConceptTheme();
|
||||||
return (
|
return (
|
||||||
|
<NavigationState>
|
||||||
<div className='w-screen antialiased clr-app'>
|
<div className='w-screen antialiased clr-app'>
|
||||||
<Navigation />
|
|
||||||
<ConceptToaster
|
<ConceptToaster
|
||||||
className='mt-[4rem] text-sm'
|
className='mt-[4rem] text-sm'
|
||||||
autoClose={3000}
|
autoClose={3000}
|
||||||
draggable={false}
|
draggable={false}
|
||||||
pauseOnFocusLoss={false}
|
pauseOnFocusLoss={false}
|
||||||
/>
|
/>
|
||||||
<div className='w-full overflow-auto' style={{maxHeight: viewportHeight}}>
|
|
||||||
|
<Navigation />
|
||||||
|
<div id={globalIDs.main_scroll}
|
||||||
|
className='w-full overflow-x-auto'
|
||||||
|
style={{
|
||||||
|
maxHeight: viewportHeight,
|
||||||
|
overflowY: showScroll ? 'scroll': 'auto'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<main className='w-full h-full' style={{minHeight: mainHeight}}>
|
<main className='w-full h-full' style={{minHeight: mainHeight}}>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</main>
|
</main>
|
||||||
{!noNavigation && !noFooter && <Footer />}
|
{!noNavigation && !noFooter && <Footer />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</NavigationState>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,17 +6,17 @@ function HelpMain() {
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col w-full'>
|
<div className='flex flex-col w-full'>
|
||||||
<h1>Портал</h1>
|
<h1>Портал</h1>
|
||||||
<p className='lg:text-justify'>Портал позволяет анализировать предметные области, формально записывать системы определений (концептуальные схемы) и синтезировать их с помощью математического аппарата родов структур.</p>
|
<p className=''>Портал позволяет анализировать предметные области, формально записывать системы определений (концептуальные схемы) и синтезировать их с помощью математического аппарата родов структур.</p>
|
||||||
<p className='mt-2 lg:text-justify'>Навигация по порталу осуществляется верхнюю панель или ссылки в "подвале" страницы. Их можно скрыть с помощью кнопки в правом верхнем углу.</p>
|
<p className='mt-2'>Навигация по порталу осуществляется верхнюю панель или ссылки в "подвале" страницы. Их можно скрыть с помощью кнопки в правом верхнем углу.</p>
|
||||||
<p className='mt-2 lg:text-justify'>В меню пользователя (правый верхний угол) доступно редактирование данных пользователя и изменение цветовой темы.</p>
|
<p className='mt-2'>В меню пользователя (правый верхний угол) доступно редактирование данных пользователя и изменение цветовой темы.</p>
|
||||||
<p className='mt-4 mb-1 text-center'><b>Основные разделы</b></p>
|
<p className='mt-4 mb-1 text-center'><b>Основные разделы</b></p>
|
||||||
<li className='text-left'><TextURL text='Библиотека' href='/library' /> - все схемы доступные пользователю</li>
|
<li className='text-left'><TextURL text='Библиотека' href='/library' /> - все схемы доступные пользователю</li>
|
||||||
<li className='text-left'><TextURL text='Общие схемы' href={`/library?filter=${LibraryFilterStrategy.COMMON}`} /> - общедоступные схемы и инструменты поиска и навигации по ним</li>
|
<li className='text-left'><TextURL text='Общие схемы' href={`/library?filter=${LibraryFilterStrategy.COMMON}`} /> - общедоступные схемы и инструменты поиска и навигации по ним</li>
|
||||||
<li className='text-left'><TextURL text='Мои схемы' href={`/library?filter=${LibraryFilterStrategy.PERSONAL}`} /> - отслеживаемые и редактируемые схемы. Основной рабочий раздел</li>
|
<li className='text-left'><TextURL text='Мои схемы' href={`/library?filter=${LibraryFilterStrategy.PERSONAL}`} /> - отслеживаемые и редактируемые схемы. Основной рабочий раздел</li>
|
||||||
<li className='text-left'><TextURL text='Профиль' href='/profile' /> - данные пользователя и смена пароля</li>
|
<li className='text-left'><TextURL text='Профиль' href='/profile' /> - данные пользователя и смена пароля</li>
|
||||||
<p className='mt-4 mb-1 text-center'><b>Поддержка</b></p>
|
<p className='mt-4 mb-1 text-center'><b>Поддержка</b></p>
|
||||||
<p className='lg:text-justify'>Портал разрабатывается <TextURL text='Центром Концепт' href={urls.concept}/> и является проектом с открытым исходным кодом, доступным на <TextURL text='Github' href={urls.gitrepo}/>.</p>
|
<p className=''>Портал разрабатывается <TextURL text='Центром Концепт' href={urls.concept}/> и является проектом с открытым исходным кодом, доступным на <TextURL text='Github' href={urls.gitrepo}/>.</p>
|
||||||
<p className='mt-2 lg:text-justify'>Ждём Ваши пожелания по доработке, найденные ошибки и иные предложения по адресу <TextURL href={urls.mailportal} text='portal@acconcept.ru'/></p>
|
<p className='mt-2'>Ждём Ваши пожелания по доработке, найденные ошибки и иные предложения по адресу <TextURL href={urls.mailportal} text='portal@acconcept.ru'/></p>
|
||||||
<p></p>
|
<p></p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useConceptNavigation } from '../../context/NagivationContext';
|
||||||
|
|
||||||
import { useConceptTheme } from '../../context/ThemeContext';
|
import { useConceptTheme } from '../../context/ThemeContext';
|
||||||
import { EducationIcon, LibraryIcon, PlusIcon } from '../Icons';
|
import { EducationIcon, LibraryIcon, PlusIcon } from '../Icons';
|
||||||
import Logo from './Logo'
|
import Logo from './Logo'
|
||||||
|
@ -7,12 +6,12 @@ import NavigationButton from './NavigationButton';
|
||||||
import UserMenu from './UserMenu';
|
import UserMenu from './UserMenu';
|
||||||
|
|
||||||
function Navigation () {
|
function Navigation () {
|
||||||
const navigate = useNavigate();
|
const { navigateTo } = useConceptNavigation();
|
||||||
const { noNavigation, toggleNoNavigation } = useConceptTheme();
|
const { noNavigation, toggleNoNavigation } = useConceptTheme();
|
||||||
|
|
||||||
const navigateLibrary = () => navigate('/library');
|
const navigateLibrary = () => navigateTo('/library');
|
||||||
const navigateHelp = () => navigate('/manuals');
|
const navigateHelp = () => navigateTo('/manuals');
|
||||||
const navigateCreateNew = () => navigate('/rsform-create');
|
const navigateCreateNew = () => navigateTo('/rsform-create');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className='sticky top-0 left-0 right-0 z-50 select-none h-fit'>
|
<nav className='sticky top-0 left-0 right-0 z-50 select-none h-fit'>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
|
|
||||||
import { useAuth } from '../../context/AuthContext';
|
import { useAuth } from '../../context/AuthContext';
|
||||||
|
import { useConceptNavigation } from '../../context/NagivationContext';
|
||||||
import { useConceptTheme } from '../../context/ThemeContext';
|
import { useConceptTheme } from '../../context/ThemeContext';
|
||||||
import { LibraryFilterStrategy } from '../../utils/models';
|
import { LibraryFilterStrategy } from '../../utils/models';
|
||||||
import Dropdown from '../Common/Dropdown';
|
import Dropdown from '../Common/Dropdown';
|
||||||
|
@ -12,23 +11,23 @@ interface UserDropdownProps {
|
||||||
|
|
||||||
function UserDropdown({ hideDropdown }: UserDropdownProps) {
|
function UserDropdown({ hideDropdown }: UserDropdownProps) {
|
||||||
const { darkMode, toggleDarkMode } = useConceptTheme();
|
const { darkMode, toggleDarkMode } = useConceptTheme();
|
||||||
const navigate = useNavigate();
|
const { navigateTo } = useConceptNavigation();
|
||||||
const { user, logout } = useAuth();
|
const { user, logout } = useAuth();
|
||||||
|
|
||||||
const navigateProfile = () => {
|
const navigateProfile = () => {
|
||||||
hideDropdown();
|
hideDropdown();
|
||||||
navigate('/profile');
|
navigateTo('/profile');
|
||||||
};
|
};
|
||||||
|
|
||||||
const logoutAndRedirect =
|
const logoutAndRedirect =
|
||||||
() => {
|
() => {
|
||||||
hideDropdown();
|
hideDropdown();
|
||||||
logout(() => navigate('/login/'));
|
logout(() => navigateTo('/login/'));
|
||||||
};
|
};
|
||||||
|
|
||||||
const navigateMyWork = () => {
|
const navigateMyWork = () => {
|
||||||
hideDropdown();
|
hideDropdown();
|
||||||
navigate(`/library?filter=${LibraryFilterStrategy.PERSONAL}`);
|
navigateTo(`/library?filter=${LibraryFilterStrategy.PERSONAL}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
|
|
||||||
import { useAuth } from '../../context/AuthContext';
|
import { useAuth } from '../../context/AuthContext';
|
||||||
|
import { useConceptNavigation } from '../../context/NagivationContext';
|
||||||
import useDropdown from '../../hooks/useDropdown';
|
import useDropdown from '../../hooks/useDropdown';
|
||||||
import { InDoor, UserIcon } from '../Icons';
|
import { InDoor, UserIcon } from '../Icons';
|
||||||
import NavigationButton from './NavigationButton';
|
import NavigationButton from './NavigationButton';
|
||||||
import UserDropdown from './UserDropdown';
|
import UserDropdown from './UserDropdown';
|
||||||
|
|
||||||
function UserMenu() {
|
function UserMenu() {
|
||||||
const navigate = useNavigate();
|
const { navigateTo } = useConceptNavigation();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const menu = useDropdown();
|
const menu = useDropdown();
|
||||||
|
|
||||||
const navigateLogin = () => navigate('/login');
|
const navigateLogin = () => navigateTo('/login');
|
||||||
return (
|
return (
|
||||||
<div ref={menu.ref} className='h-full'>
|
<div ref={menu.ref} className='h-full'>
|
||||||
<div className='flex items-center justify-end h-full w-fit'>
|
<div className='flex items-center justify-end h-full w-fit'>
|
||||||
|
|
60
rsconcept/frontend/src/context/NagivationContext.tsx
Normal file
60
rsconcept/frontend/src/context/NagivationContext.tsx
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import { createContext, useCallback, useContext, useEffect } from 'react';
|
||||||
|
import { NavigateOptions, useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { globalIDs } from '../utils/constants';
|
||||||
|
|
||||||
|
interface INagivationContext{
|
||||||
|
navigateTo: (path: string, options?: NavigateOptions) => void
|
||||||
|
navigateHistory: (offset: number) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
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) => {
|
||||||
|
const implNavigate = useNavigate();
|
||||||
|
const { pathname } = useLocation();
|
||||||
|
|
||||||
|
function scrollTop() {
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
const mainScroll = document.getElementById(globalIDs.main_scroll);
|
||||||
|
if (mainScroll) {
|
||||||
|
mainScroll.scroll(0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const navigateTo = useCallback(
|
||||||
|
(path: string, options?: NavigateOptions) => {
|
||||||
|
scrollTop();
|
||||||
|
implNavigate(path, options);
|
||||||
|
}, [implNavigate]);
|
||||||
|
|
||||||
|
const navigateHistory = useCallback(
|
||||||
|
(offset: number) => {
|
||||||
|
scrollTop();
|
||||||
|
implNavigate(offset);
|
||||||
|
}, [implNavigate]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
scrollTop();
|
||||||
|
}, [pathname]);
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NagivationContext.Provider value={{
|
||||||
|
navigateTo, navigateHistory
|
||||||
|
}}>
|
||||||
|
{children}
|
||||||
|
</NagivationContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
|
@ -13,9 +13,13 @@ interface IThemeContext {
|
||||||
toggleDarkMode: () => void
|
toggleDarkMode: () => void
|
||||||
|
|
||||||
noNavigation: boolean
|
noNavigation: boolean
|
||||||
|
toggleNoNavigation: () => void
|
||||||
|
|
||||||
noFooter: boolean
|
noFooter: boolean
|
||||||
setNoFooter: (value: boolean) => void
|
setNoFooter: (value: boolean) => void
|
||||||
toggleNoNavigation: () => void
|
|
||||||
|
showScroll: boolean
|
||||||
|
setShowScroll: (value: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const ThemeContext = createContext<IThemeContext | null>(null);
|
const ThemeContext = createContext<IThemeContext | null>(null);
|
||||||
|
@ -36,6 +40,7 @@ export const ThemeState = ({ children }: ThemeStateProps) => {
|
||||||
const [colors, setColors] = useState<IColorTheme>(lightT);
|
const [colors, setColors] = useState<IColorTheme>(lightT);
|
||||||
const [noNavigation, setNoNavigation] = useState(false);
|
const [noNavigation, setNoNavigation] = useState(false);
|
||||||
const [noFooter, setNoFooter] = useState(false);
|
const [noFooter, setNoFooter] = useState(false);
|
||||||
|
const [showScroll, setShowScroll] = useState(false);
|
||||||
|
|
||||||
function setDarkClass(isDark: boolean) {
|
function setDarkClass(isDark: boolean) {
|
||||||
const root = window.document.documentElement;
|
const root = window.document.documentElement;
|
||||||
|
@ -72,10 +77,10 @@ export const ThemeState = ({ children }: ThemeStateProps) => {
|
||||||
return (
|
return (
|
||||||
<ThemeContext.Provider value={{
|
<ThemeContext.Provider value={{
|
||||||
darkMode, colors,
|
darkMode, colors,
|
||||||
noNavigation, noFooter,
|
noNavigation, noFooter, showScroll,
|
||||||
toggleDarkMode: () => setDarkMode(prev => !prev),
|
toggleDarkMode: () => setDarkMode(prev => !prev),
|
||||||
toggleNoNavigation: () => setNoNavigation(prev => !prev),
|
toggleNoNavigation: () => setNoNavigation(prev => !prev),
|
||||||
setNoFooter,
|
setNoFooter, setShowScroll,
|
||||||
viewportHeight, mainHeight
|
viewportHeight, mainHeight
|
||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -153,7 +153,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
:is(.clr-selected,
|
:is(.clr-selected,
|
||||||
.clr-btn-primary,
|
.clr-btn-primary
|
||||||
) {
|
) {
|
||||||
color: var(--cl-fg-100);
|
color: var(--cl-fg-100);
|
||||||
background-color: var(--cl-prim-bg-80);
|
background-color: var(--cl-prim-bg-80);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import BackendError from '../components/BackendError';
|
import BackendError from '../components/BackendError';
|
||||||
|
@ -12,11 +12,12 @@ import TextArea from '../components/Common/TextArea';
|
||||||
import TextInput from '../components/Common/TextInput';
|
import TextInput from '../components/Common/TextInput';
|
||||||
import RequireAuth from '../components/RequireAuth';
|
import RequireAuth from '../components/RequireAuth';
|
||||||
import { useLibrary } from '../context/LibraryContext';
|
import { useLibrary } from '../context/LibraryContext';
|
||||||
|
import { useConceptNavigation } from '../context/NagivationContext';
|
||||||
import { IRSFormCreateData, LibraryItemType } from '../utils/models';
|
import { IRSFormCreateData, LibraryItemType } from '../utils/models';
|
||||||
|
|
||||||
function CreateRSFormPage() {
|
function CreateRSFormPage() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const { navigateTo, navigateHistory } = useConceptNavigation();
|
||||||
const { createSchema, error, setError, processing } = useLibrary();
|
const { createSchema, error, setError, processing } = useLibrary();
|
||||||
|
|
||||||
const [title, setTitle] = useState('');
|
const [title, setTitle] = useState('');
|
||||||
|
@ -39,9 +40,9 @@ function CreateRSFormPage() {
|
||||||
|
|
||||||
function handleCancel() {
|
function handleCancel() {
|
||||||
if (location.key !== 'default') {
|
if (location.key !== 'default') {
|
||||||
navigate(-1);
|
navigateHistory(-1);
|
||||||
} else {
|
} else {
|
||||||
navigate('/library');
|
navigateTo('/library');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ function CreateRSFormPage() {
|
||||||
};
|
};
|
||||||
createSchema(data, (newSchema) => {
|
createSchema(data, (newSchema) => {
|
||||||
toast.success('Схема успешно создана');
|
toast.success('Схема успешно создана');
|
||||||
navigate(`/rsforms/${newSchema.id}`);
|
navigateTo(`/rsforms/${newSchema.id}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import { useLayoutEffect } from 'react';
|
import { useLayoutEffect } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
|
|
||||||
import { useAuth } from '../context/AuthContext';
|
import { useAuth } from '../context/AuthContext';
|
||||||
|
import { useConceptNavigation } from '../context/NagivationContext';
|
||||||
import { TIMEOUT_UI_REFRESH } from '../utils/constants';
|
import { TIMEOUT_UI_REFRESH } from '../utils/constants';
|
||||||
|
|
||||||
function HomePage() {
|
function HomePage() {
|
||||||
const navigate = useNavigate();
|
const { navigateTo } = useConceptNavigation();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigate('/manuals');
|
navigateTo('/manuals');
|
||||||
}, TIMEOUT_UI_REFRESH);
|
}, TIMEOUT_UI_REFRESH);
|
||||||
} else {
|
} else {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigate('/library');
|
navigateTo('/library');
|
||||||
}, TIMEOUT_UI_REFRESH);
|
}, TIMEOUT_UI_REFRESH);
|
||||||
}
|
}
|
||||||
}, [navigate, user])
|
}, [navigateTo, user])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col items-center justify-center w-full px-4 py-2'>
|
<div className='flex flex-col items-center justify-center w-full px-4 py-2'>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { useCallback, useLayoutEffect, useState } from 'react';
|
import { useCallback, useLayoutEffect, useState } from 'react';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
import { MagnifyingGlassIcon } from '../../components/Icons';
|
import { MagnifyingGlassIcon } from '../../components/Icons';
|
||||||
import { useAuth } from '../../context/AuthContext';
|
import { useAuth } from '../../context/AuthContext';
|
||||||
|
import { useConceptNavigation } from '../../context/NagivationContext';
|
||||||
import useLocalStorage from '../../hooks/useLocalStorage';
|
import useLocalStorage from '../../hooks/useLocalStorage';
|
||||||
import { ILibraryFilter, LibraryFilterStrategy } from '../../utils/models';
|
import { ILibraryFilter, LibraryFilterStrategy } from '../../utils/models';
|
||||||
import PickerStrategy from './PickerStrategy';
|
import PickerStrategy from './PickerStrategy';
|
||||||
|
@ -26,7 +27,7 @@ interface SearchPanelProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function SearchPanel({ total, filtered, setFilter }: SearchPanelProps) {
|
function SearchPanel({ total, filtered, setFilter }: SearchPanelProps) {
|
||||||
const navigate = useNavigate();
|
const { navigateTo } = useConceptNavigation();
|
||||||
const search = useLocation().search;
|
const search = useLocation().search;
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|
||||||
|
@ -51,29 +52,29 @@ function SearchPanel({ total, filtered, setFilter }: SearchPanelProps) {
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const searchFilter = new URLSearchParams(search).get('filter') as LibraryFilterStrategy | null;
|
const searchFilter = new URLSearchParams(search).get('filter') as LibraryFilterStrategy | null;
|
||||||
if (searchFilter === null) {
|
if (searchFilter === null) {
|
||||||
navigate(`/library?filter=${strategy}`, { replace: true });
|
navigateTo(`/library?filter=${strategy}`, { replace: true });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const inputStrategy = searchFilter && Object.values(LibraryFilterStrategy).includes(searchFilter) ? searchFilter : LibraryFilterStrategy.MANUAL;
|
const inputStrategy = searchFilter && Object.values(LibraryFilterStrategy).includes(searchFilter) ? searchFilter : LibraryFilterStrategy.MANUAL;
|
||||||
setQuery('')
|
setQuery('')
|
||||||
setStrategy(inputStrategy)
|
setStrategy(inputStrategy)
|
||||||
setFilter(ApplyStrategy(inputStrategy));
|
setFilter(ApplyStrategy(inputStrategy));
|
||||||
}, [user, search, setQuery, setFilter, setStrategy, strategy, navigate]);
|
}, [user, search, setQuery, setFilter, setStrategy, strategy, navigateTo]);
|
||||||
|
|
||||||
const handleChangeStrategy = useCallback(
|
const handleChangeStrategy = useCallback(
|
||||||
(value: LibraryFilterStrategy) => {
|
(value: LibraryFilterStrategy) => {
|
||||||
if (value === strategy) {
|
if (value === strategy) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
navigate(`/library?filter=${value}`)
|
navigateTo(`/library?filter=${value}`)
|
||||||
}, [strategy, navigate]);
|
}, [strategy, navigateTo]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='sticky top-0 left-0 right-0 z-30 flex items-center justify-start w-full border-b clr-input'>
|
<div className='sticky top-0 left-0 right-0 z-30 flex items-center justify-start w-full border-b clr-input'>
|
||||||
<div className='px-2 py-1 select-none whitespace-nowrap min-w-[10rem]'>
|
<div className='px-2 py-1 select-none whitespace-nowrap min-w-[10rem]'>
|
||||||
Фильтр
|
Фильтр
|
||||||
<span className='ml-2'>
|
<span className='ml-2'>
|
||||||
<b>{filtered}</b> из {total}
|
{filtered} из {total}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center justify-center w-full pr-[10rem]'>
|
<div className='flex items-center justify-center w-full pr-[10rem]'>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
|
|
||||||
import ConceptDataTable from '../../components/Common/ConceptDataTable';
|
import ConceptDataTable from '../../components/Common/ConceptDataTable';
|
||||||
import ConceptTooltip from '../../components/Common/ConceptTooltip';
|
import ConceptTooltip from '../../components/Common/ConceptTooltip';
|
||||||
|
@ -8,6 +7,7 @@ import TextURL from '../../components/Common/TextURL';
|
||||||
import HelpLibrary from '../../components/Help/HelpLibrary';
|
import HelpLibrary from '../../components/Help/HelpLibrary';
|
||||||
import { EducationIcon, EyeIcon, GroupIcon, HelpIcon } from '../../components/Icons';
|
import { EducationIcon, EyeIcon, GroupIcon, HelpIcon } from '../../components/Icons';
|
||||||
import { useAuth } from '../../context/AuthContext';
|
import { useAuth } from '../../context/AuthContext';
|
||||||
|
import { useConceptNavigation } from '../../context/NagivationContext';
|
||||||
import { useUsers } from '../../context/UsersContext';
|
import { useUsers } from '../../context/UsersContext';
|
||||||
import { prefixes } from '../../utils/constants';
|
import { prefixes } from '../../utils/constants';
|
||||||
import { ILibraryItem } from '../../utils/models';
|
import { ILibraryItem } from '../../utils/models';
|
||||||
|
@ -18,12 +18,12 @@ interface ViewLibraryProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function ViewLibrary({ items, cleanQuery }: ViewLibraryProps) {
|
function ViewLibrary({ items, cleanQuery }: ViewLibraryProps) {
|
||||||
const { user } = useAuth();
|
const { navigateTo } = useConceptNavigation();
|
||||||
const navigate = useNavigate();
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const { user } = useAuth();
|
||||||
const { getUserLabel } = useUsers();
|
const { getUserLabel } = useUsers();
|
||||||
|
|
||||||
const openRSForm = (item: ILibraryItem) => navigate(`/rsforms/${item.id}`);
|
const openRSForm = (item: ILibraryItem) => navigateTo(`/rsforms/${item.id}`);
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
() => [
|
() => [
|
||||||
|
|
|
@ -3,16 +3,24 @@ import { useLayoutEffect, useState } from 'react';
|
||||||
import BackendError from '../../components/BackendError'
|
import BackendError from '../../components/BackendError'
|
||||||
import { ConceptLoader } from '../../components/Common/ConceptLoader'
|
import { ConceptLoader } from '../../components/Common/ConceptLoader'
|
||||||
import { useLibrary } from '../../context/LibraryContext';
|
import { useLibrary } from '../../context/LibraryContext';
|
||||||
|
import { useConceptTheme } from '../../context/ThemeContext';
|
||||||
import { ILibraryFilter, ILibraryItem } from '../../utils/models';
|
import { ILibraryFilter, ILibraryItem } from '../../utils/models';
|
||||||
import SearchPanel from './SearchPanel';
|
import SearchPanel from './SearchPanel';
|
||||||
import ViewLibrary from './ViewLibrary';
|
import ViewLibrary from './ViewLibrary';
|
||||||
|
|
||||||
function LibraryPage() {
|
function LibraryPage() {
|
||||||
const library = useLibrary();
|
const library = useLibrary();
|
||||||
|
const { setShowScroll } = useConceptTheme();
|
||||||
|
|
||||||
const [ filter, setFilter ] = useState<ILibraryFilter>({});
|
const [ filter, setFilter ] = useState<ILibraryFilter>({});
|
||||||
const [ items, setItems ] = useState<ILibraryItem[]>([]);
|
const [ items, setItems ] = useState<ILibraryItem[]>([]);
|
||||||
|
|
||||||
|
useLayoutEffect(
|
||||||
|
() => {
|
||||||
|
setShowScroll(true);
|
||||||
|
return () => setShowScroll(false);
|
||||||
|
}, [setShowScroll]);
|
||||||
|
|
||||||
useLayoutEffect(
|
useLayoutEffect(
|
||||||
() => {
|
() => {
|
||||||
setItems(library.filter(filter));
|
setItems(library.filter(filter));
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
import BackendError, { ErrorInfo } from '../components/BackendError';
|
import BackendError, { ErrorInfo } from '../components/BackendError';
|
||||||
import Form from '../components/Common/Form';
|
import Form from '../components/Common/Form';
|
||||||
|
@ -8,6 +8,7 @@ import SubmitButton from '../components/Common/SubmitButton';
|
||||||
import TextInput from '../components/Common/TextInput';
|
import TextInput from '../components/Common/TextInput';
|
||||||
import TextURL from '../components/Common/TextURL';
|
import TextURL from '../components/Common/TextURL';
|
||||||
import { useAuth } from '../context/AuthContext';
|
import { useAuth } from '../context/AuthContext';
|
||||||
|
import { useConceptNavigation } from '../context/NagivationContext';
|
||||||
import { useConceptTheme } from '../context/ThemeContext';
|
import { useConceptTheme } from '../context/ThemeContext';
|
||||||
import { IUserLoginData } from '../utils/models';
|
import { IUserLoginData } from '../utils/models';
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@ function ProcessError({error}: {error: ErrorInfo}): React.ReactElement {
|
||||||
function LoginPage() {
|
function LoginPage() {
|
||||||
const {mainHeight} = useConceptTheme();
|
const {mainHeight} = useConceptTheme();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const { navigateTo, navigateHistory } = useConceptNavigation();
|
||||||
const search = useLocation().search;
|
const search = useLocation().search;
|
||||||
const { user, login, loading, error, setError } = useAuth();
|
const { user, login, loading, error, setError } = useAuth();
|
||||||
|
|
||||||
|
@ -52,9 +53,9 @@ function LoginPage() {
|
||||||
};
|
};
|
||||||
login(data, () => {
|
login(data, () => {
|
||||||
if (location.key !== 'default') {
|
if (location.key !== 'default') {
|
||||||
navigate(-1);
|
navigateHistory(-1);
|
||||||
} else {
|
} else {
|
||||||
navigate('/library');
|
navigateTo('/library');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +1,37 @@
|
||||||
import { useCallback, useLayoutEffect, useState } from 'react';
|
import { useCallback, useLayoutEffect, useState } from 'react';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { useConceptNavigation } from '../../context/NagivationContext';
|
||||||
import { useConceptTheme } from '../../context/ThemeContext';
|
import { useConceptTheme } from '../../context/ThemeContext';
|
||||||
import { HelpTopic } from '../../utils/models';
|
import { HelpTopic } from '../../utils/models';
|
||||||
import TopicsList from './TopicsList';
|
import TopicsList from './TopicsList';
|
||||||
import ViewTopic from './ViewTopic';
|
import ViewTopic from './ViewTopic';
|
||||||
|
|
||||||
function ManualsPage() {
|
function ManualsPage() {
|
||||||
const navigate = useNavigate();
|
const { navigateTo } = useConceptNavigation();
|
||||||
const search = useLocation().search;
|
const search = useLocation().search;
|
||||||
const { mainHeight } = useConceptTheme();
|
const { mainHeight } = useConceptTheme();
|
||||||
const [activeTopic, setActiveTopic] = useState<HelpTopic>(HelpTopic.MAIN);
|
const [activeTopic, setActiveTopic] = useState<HelpTopic>(HelpTopic.MAIN);
|
||||||
|
|
||||||
const navigateTo = useCallback(
|
const navigateTopic = useCallback(
|
||||||
(newTopic: HelpTopic) => {
|
(newTopic: HelpTopic) => {
|
||||||
navigate(`/manuals?topic=${newTopic}`);
|
navigateTo(`/manuals?topic=${newTopic}`);
|
||||||
}, [navigate]);
|
}, [navigateTo]);
|
||||||
|
|
||||||
|
|
||||||
function onSelectTopic(newTopic: HelpTopic) {
|
function onSelectTopic(newTopic: HelpTopic) {
|
||||||
navigateTo(newTopic);
|
navigateTopic(newTopic);
|
||||||
}
|
}
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const topic = new URLSearchParams(search).get('topic') as HelpTopic;
|
const topic = new URLSearchParams(search).get('topic') as HelpTopic;
|
||||||
if (!Object.values(HelpTopic).includes(topic)) {
|
if (!Object.values(HelpTopic).includes(topic)) {
|
||||||
navigateTo(HelpTopic.MAIN);
|
navigateTopic(HelpTopic.MAIN);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
setActiveTopic(topic);
|
setActiveTopic(topic);
|
||||||
}
|
}
|
||||||
}, [search, setActiveTopic, navigateTo]);
|
}, [search, setActiveTopic, navigateTopic]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex w-full gap-2 justify-stretch' style={{minHeight: mainHeight}}>
|
<div className='flex w-full gap-2 justify-stretch' style={{minHeight: mainHeight}}>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import Checkbox from '../../components/Common/Checkbox';
|
import Checkbox from '../../components/Common/Checkbox';
|
||||||
|
@ -7,6 +6,7 @@ import Modal from '../../components/Common/Modal';
|
||||||
import TextArea from '../../components/Common/TextArea';
|
import TextArea from '../../components/Common/TextArea';
|
||||||
import TextInput from '../../components/Common/TextInput';
|
import TextInput from '../../components/Common/TextInput';
|
||||||
import { useLibrary } from '../../context/LibraryContext';
|
import { useLibrary } from '../../context/LibraryContext';
|
||||||
|
import { useConceptNavigation } from '../../context/NagivationContext';
|
||||||
import { useRSForm } from '../../context/RSFormContext';
|
import { useRSForm } from '../../context/RSFormContext';
|
||||||
import { IRSFormCreateData } from '../../utils/models';
|
import { IRSFormCreateData } from '../../utils/models';
|
||||||
import { getCloneTitle } from '../../utils/staticUI';
|
import { getCloneTitle } from '../../utils/staticUI';
|
||||||
|
@ -16,7 +16,7 @@ interface DlgCloneRSFormProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function DlgCloneRSForm({ hideWindow }: DlgCloneRSFormProps) {
|
function DlgCloneRSForm({ hideWindow }: DlgCloneRSFormProps) {
|
||||||
const navigate = useNavigate();
|
const { navigateTo } = useConceptNavigation();
|
||||||
const [title, setTitle] = useState('');
|
const [title, setTitle] = useState('');
|
||||||
const [alias, setAlias] = useState('');
|
const [alias, setAlias] = useState('');
|
||||||
const [comment, setComment] = useState('');
|
const [comment, setComment] = useState('');
|
||||||
|
@ -50,7 +50,7 @@ function DlgCloneRSForm({ hideWindow }: DlgCloneRSFormProps) {
|
||||||
};
|
};
|
||||||
cloneSchema(schema.id, data, newSchema => {
|
cloneSchema(schema.id, data, newSchema => {
|
||||||
toast.success(`Схема создана: ${newSchema.alias}`);
|
toast.success(`Схема создана: ${newSchema.alias}`);
|
||||||
navigate(`/rsforms/${newSchema.id}`);
|
navigateTo(`/rsforms/${newSchema.id}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -264,7 +264,7 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
|
||||||
<div className='mr-3 whitespace-nowrap'>
|
<div className='mr-3 whitespace-nowrap'>
|
||||||
Выбраны
|
Выбраны
|
||||||
<span className='ml-2'>
|
<span className='ml-2'>
|
||||||
<b>{selected.length}</b> из {schema?.stats?.count_all ?? 0}
|
{selected.length} из {schema?.stats?.count_all ?? 0}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center justify-start w-full gap-1'>
|
<div className='flex items-center justify-start w-full gap-1'>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import fileDownload from 'js-file-download';
|
import fileDownload from 'js-file-download';
|
||||||
import { useCallback, useLayoutEffect, useState } from 'react';
|
import { useCallback, useLayoutEffect, useState } from 'react';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import { ConceptLoader } from '../../components/Common/ConceptLoader';
|
||||||
import ConceptTab from '../../components/Common/ConceptTab';
|
import ConceptTab from '../../components/Common/ConceptTab';
|
||||||
import TextURL from '../../components/Common/TextURL';
|
import TextURL from '../../components/Common/TextURL';
|
||||||
import { useLibrary } from '../../context/LibraryContext';
|
import { useLibrary } from '../../context/LibraryContext';
|
||||||
|
import { useConceptNavigation } from '../../context/NagivationContext';
|
||||||
import { useRSForm } from '../../context/RSFormContext';
|
import { useRSForm } from '../../context/RSFormContext';
|
||||||
import { useConceptTheme } from '../../context/ThemeContext';
|
import { useConceptTheme } from '../../context/ThemeContext';
|
||||||
import useModificationPrompt from '../../hooks/useModificationPrompt';
|
import useModificationPrompt from '../../hooks/useModificationPrompt';
|
||||||
|
@ -50,7 +51,7 @@ function ProcessError({error}: {error: ErrorInfo}): React.ReactElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
function RSTabs() {
|
function RSTabs() {
|
||||||
const navigate = useNavigate();
|
const { navigateTo } = useConceptNavigation();
|
||||||
const search = useLocation().search;
|
const search = useLocation().search;
|
||||||
const {
|
const {
|
||||||
error, schema, loading, claim, download, isTracking,
|
error, schema, loading, claim, download, isTracking,
|
||||||
|
@ -101,25 +102,25 @@ function RSTabs() {
|
||||||
}, [search, setActiveTab, setActiveID, schema, setNoFooter]);
|
}, [search, setActiveTab, setActiveID, schema, setNoFooter]);
|
||||||
|
|
||||||
function onSelectTab(index: number) {
|
function onSelectTab(index: number) {
|
||||||
navigateTo(index, activeID);
|
navigateTab(index, activeID);
|
||||||
}
|
}
|
||||||
|
|
||||||
const navigateTo = useCallback(
|
const navigateTab = useCallback(
|
||||||
(tab: RSTabID, activeID?: number) => {
|
(tab: RSTabID, activeID?: number) => {
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (activeID) {
|
if (activeID) {
|
||||||
navigate(`/rsforms/${schema.id}?tab=${tab}&active=${activeID}`, {
|
navigateTo(`/rsforms/${schema.id}?tab=${tab}&active=${activeID}`, {
|
||||||
replace: tab === activeTab && tab !== RSTabID.CST_EDIT
|
replace: tab === activeTab && tab !== RSTabID.CST_EDIT
|
||||||
});
|
});
|
||||||
} else if (tab !== activeTab && tab === RSTabID.CST_EDIT && schema.items.length > 0) {
|
} else if (tab !== activeTab && tab === RSTabID.CST_EDIT && schema.items.length > 0) {
|
||||||
activeID = schema.items[0].id;
|
activeID = schema.items[0].id;
|
||||||
navigate(`/rsforms/${schema.id}?tab=${tab}&active=${activeID}`, { replace: true });
|
navigateTo(`/rsforms/${schema.id}?tab=${tab}&active=${activeID}`, { replace: true });
|
||||||
} else {
|
} else {
|
||||||
navigate(`/rsforms/${schema.id}?tab=${tab}`);
|
navigateTo(`/rsforms/${schema.id}?tab=${tab}`);
|
||||||
}
|
}
|
||||||
}, [navigate, schema, activeTab]);
|
}, [navigateTo, schema, activeTab]);
|
||||||
|
|
||||||
const handleCreateCst = useCallback(
|
const handleCreateCst = useCallback(
|
||||||
(data: ICstCreateData) => {
|
(data: ICstCreateData) => {
|
||||||
|
@ -129,7 +130,7 @@ function RSTabs() {
|
||||||
data.alias = createAliasFor(data.cst_type, schema);
|
data.alias = createAliasFor(data.cst_type, schema);
|
||||||
cstCreate(data, newCst => {
|
cstCreate(data, newCst => {
|
||||||
toast.success(`Конституента добавлена: ${newCst.alias}`);
|
toast.success(`Конституента добавлена: ${newCst.alias}`);
|
||||||
navigateTo(activeTab, newCst.id);
|
navigateTab(activeTab, newCst.id);
|
||||||
if (activeTab === RSTabID.CST_EDIT || activeTab === RSTabID.CST_LIST) {
|
if (activeTab === RSTabID.CST_EDIT || activeTab === RSTabID.CST_LIST) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const element = document.getElementById(`${prefixes.cst_list}${newCst.alias}`);
|
const element = document.getElementById(`${prefixes.cst_list}${newCst.alias}`);
|
||||||
|
@ -143,7 +144,7 @@ function RSTabs() {
|
||||||
}, TIMEOUT_UI_REFRESH);
|
}, TIMEOUT_UI_REFRESH);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [schema, cstCreate, navigateTo, activeTab]);
|
}, [schema, cstCreate, navigateTab, activeTab]);
|
||||||
|
|
||||||
const promptCreateCst = useCallback(
|
const promptCreateCst = useCallback(
|
||||||
(initialData: ICstCreateData, skipDialog?: boolean) => {
|
(initialData: ICstCreateData, skipDialog?: boolean) => {
|
||||||
|
@ -181,7 +182,7 @@ function RSTabs() {
|
||||||
const deletedNames = deleted.map(id => schema.items.find(cst => cst.id === id)?.alias).join(', ');
|
const deletedNames = deleted.map(id => schema.items.find(cst => cst.id === id)?.alias).join(', ');
|
||||||
toast.success(`Конституенты удалены: ${deletedNames}`);
|
toast.success(`Конституенты удалены: ${deletedNames}`);
|
||||||
if (deleted.length === schema.items.length) {
|
if (deleted.length === schema.items.length) {
|
||||||
navigateTo(RSTabID.CST_LIST);
|
navigateTab(RSTabID.CST_LIST);
|
||||||
}
|
}
|
||||||
if (activeIndex) {
|
if (activeIndex) {
|
||||||
while (activeIndex < schema.items.length && deleted.find(id => id === schema.items[activeIndex].id)) {
|
while (activeIndex < schema.items.length && deleted.find(id => id === schema.items[activeIndex].id)) {
|
||||||
|
@ -193,11 +194,11 @@ function RSTabs() {
|
||||||
--activeIndex;
|
--activeIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
navigateTo(activeTab, schema.items[activeIndex].id);
|
navigateTab(activeTab, schema.items[activeIndex].id);
|
||||||
}
|
}
|
||||||
if (afterDelete) afterDelete(deleted);
|
if (afterDelete) afterDelete(deleted);
|
||||||
});
|
});
|
||||||
}, [afterDelete, cstDelete, schema, activeID, activeTab, navigateTo]);
|
}, [afterDelete, cstDelete, schema, activeID, activeTab, navigateTab]);
|
||||||
|
|
||||||
const promptDeleteCst = useCallback(
|
const promptDeleteCst = useCallback(
|
||||||
(selected: number[], callback?: (items: number[]) => void) => {
|
(selected: number[], callback?: (items: number[]) => void) => {
|
||||||
|
@ -218,8 +219,8 @@ function RSTabs() {
|
||||||
|
|
||||||
const onOpenCst = useCallback(
|
const onOpenCst = useCallback(
|
||||||
(cstID: number) => {
|
(cstID: number) => {
|
||||||
navigateTo(RSTabID.CST_EDIT, cstID)
|
navigateTab(RSTabID.CST_EDIT, cstID)
|
||||||
}, [navigateTo]);
|
}, [navigateTab]);
|
||||||
|
|
||||||
const onDestroySchema = useCallback(
|
const onDestroySchema = useCallback(
|
||||||
() => {
|
() => {
|
||||||
|
@ -228,9 +229,9 @@ function RSTabs() {
|
||||||
}
|
}
|
||||||
destroySchema(schema.id, () => {
|
destroySchema(schema.id, () => {
|
||||||
toast.success('Схема удалена');
|
toast.success('Схема удалена');
|
||||||
navigate('/library');
|
navigateTo('/library');
|
||||||
});
|
});
|
||||||
}, [schema, destroySchema, navigate]);
|
}, [schema, destroySchema, navigateTo]);
|
||||||
|
|
||||||
const onClaimSchema = useCallback(
|
const onClaimSchema = useCallback(
|
||||||
() => {
|
() => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import BackendError from '../components/BackendError';
|
import BackendError from '../components/BackendError';
|
||||||
|
@ -8,11 +8,12 @@ import Form from '../components/Common/Form';
|
||||||
import SubmitButton from '../components/Common/SubmitButton';
|
import SubmitButton from '../components/Common/SubmitButton';
|
||||||
import TextInput from '../components/Common/TextInput';
|
import TextInput from '../components/Common/TextInput';
|
||||||
import { useAuth } from '../context/AuthContext';
|
import { useAuth } from '../context/AuthContext';
|
||||||
|
import { useConceptNavigation } from '../context/NagivationContext';
|
||||||
import { type IUserSignupData } from '../utils/models';
|
import { type IUserSignupData } from '../utils/models';
|
||||||
|
|
||||||
function RegisterPage() {
|
function RegisterPage() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const { navigateTo, navigateHistory } = useConceptNavigation();
|
||||||
const { user, signup, loading, error, setError } = useAuth();
|
const { user, signup, loading, error, setError } = useAuth();
|
||||||
|
|
||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
|
@ -28,9 +29,9 @@ function RegisterPage() {
|
||||||
|
|
||||||
function handleCancel() {
|
function handleCancel() {
|
||||||
if (location.key !== 'default') {
|
if (location.key !== 'default') {
|
||||||
navigate(-1);
|
navigateHistory(-1);
|
||||||
} else {
|
} else {
|
||||||
navigate('/library');
|
navigateTo('/library');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +47,7 @@ function RegisterPage() {
|
||||||
last_name: lastName
|
last_name: lastName
|
||||||
};
|
};
|
||||||
signup(data, createdUser => {
|
signup(data, createdUser => {
|
||||||
navigate(`/login?username=${createdUser.username}`);
|
navigateTo(`/login?username=${createdUser.username}`);
|
||||||
toast.success(`Пользователь успешно создан: ${createdUser.username}`);
|
toast.success(`Пользователь успешно создан: ${createdUser.username}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import BackendError from '../../components/BackendError';
|
import BackendError from '../../components/BackendError';
|
||||||
import SubmitButton from '../../components/Common/SubmitButton';
|
import SubmitButton from '../../components/Common/SubmitButton';
|
||||||
import TextInput from '../../components/Common/TextInput';
|
import TextInput from '../../components/Common/TextInput';
|
||||||
import { useAuth } from '../../context/AuthContext';
|
import { useAuth } from '../../context/AuthContext';
|
||||||
|
import { useConceptNavigation } from '../../context/NagivationContext';
|
||||||
import { IUserUpdatePassword } from '../../utils/models';
|
import { IUserUpdatePassword } from '../../utils/models';
|
||||||
|
|
||||||
|
|
||||||
function EditorPassword() {
|
function EditorPassword() {
|
||||||
|
const { navigateTo } = useConceptNavigation();
|
||||||
const { updatePassword, error, setError, loading } = useAuth();
|
const { updatePassword, error, setError, loading } = useAuth();
|
||||||
|
|
||||||
const [oldPassword, setOldPassword] = useState('');
|
const [oldPassword, setOldPassword] = useState('');
|
||||||
const [newPassword, setNewPassword] = useState('');
|
const [newPassword, setNewPassword] = useState('');
|
||||||
const [newPasswordRepeat, setNewPasswordRepeat] = useState('');
|
const [newPasswordRepeat, setNewPasswordRepeat] = useState('');
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const passwordColor = useMemo(
|
const passwordColor = useMemo(
|
||||||
() => {
|
() => {
|
||||||
|
@ -39,7 +39,7 @@ function EditorPassword() {
|
||||||
};
|
};
|
||||||
updatePassword(data, () => {
|
updatePassword(data, () => {
|
||||||
toast.success('Изменения сохранены');
|
toast.success('Изменения сохранены');
|
||||||
navigate('/login')
|
navigateTo('/login');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
|
|
||||||
import ConceptDataTable from '../../components/Common/ConceptDataTable';
|
import ConceptDataTable from '../../components/Common/ConceptDataTable';
|
||||||
|
import { useConceptNavigation } from '../../context/NagivationContext';
|
||||||
import { ILibraryItem } from '../../utils/models';
|
import { ILibraryItem } from '../../utils/models';
|
||||||
|
|
||||||
interface ViewSubscriptionsProps {
|
interface ViewSubscriptionsProps {
|
||||||
|
@ -10,10 +10,10 @@ interface ViewSubscriptionsProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function ViewSubscriptions({items}: ViewSubscriptionsProps) {
|
function ViewSubscriptions({items}: ViewSubscriptionsProps) {
|
||||||
const navigate = useNavigate();
|
const { navigateTo } = useConceptNavigation();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const openRSForm = (item: ILibraryItem) => navigate(`/rsforms/${item.id}`);
|
const openRSForm = (item: ILibraryItem) => navigateTo(`/rsforms/${item.id}`);
|
||||||
|
|
||||||
const columns = useMemo(() =>
|
const columns = useMemo(() =>
|
||||||
[
|
[
|
||||||
|
|
|
@ -25,6 +25,10 @@ export const resources = {
|
||||||
graph_font: '/DejaVu.ttf'
|
graph_font: '/DejaVu.ttf'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const globalIDs = {
|
||||||
|
main_scroll: 'main-scroll'
|
||||||
|
}
|
||||||
|
|
||||||
export const prefixes = {
|
export const prefixes = {
|
||||||
cst_list: 'cst-list-',
|
cst_list: 'cst-list-',
|
||||||
cst_status_list: 'cst-status-list-',
|
cst_status_list: 'cst-status-list-',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user