mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Refactoring: centralize internal URLs + animation fixes
This commit is contained in:
parent
aff116abbc
commit
9fe73a607a
|
@ -1,7 +1,7 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
import { urls } from '@/utils/constants';
|
import { external_urls } from '@/utils/constants';
|
||||||
|
|
||||||
import TextURL from '../components/ui/TextURL';
|
import TextURL from '../components/ui/TextURL';
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ function Footer() {
|
||||||
<div className='flex gap-3'>
|
<div className='flex gap-3'>
|
||||||
<TextURL text='Библиотека' href='/library' color='clr-footer' />
|
<TextURL text='Библиотека' href='/library' color='clr-footer' />
|
||||||
<TextURL text='Справка' href='/manuals' color='clr-footer' />
|
<TextURL text='Справка' href='/manuals' color='clr-footer' />
|
||||||
<TextURL text='Центр Концепт' href={urls.concept} color='clr-footer' />
|
<TextURL text='Центр Концепт' href={external_urls.concept} color='clr-footer' />
|
||||||
<TextURL text='Экстеор' href='/manuals?topic=exteor' color='clr-footer' />
|
<TextURL text='Экстеор' href='/manuals?topic=exteor' color='clr-footer' />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
import { animateNavigation } from '@/styling/animations';
|
import { animateNavigation } from '@/styling/animations';
|
||||||
|
|
||||||
|
import { urls } from '../urls';
|
||||||
import Logo from './Logo';
|
import Logo from './Logo';
|
||||||
import NavigationButton from './NavigationButton';
|
import NavigationButton from './NavigationButton';
|
||||||
import ToggleNavigationButton from './ToggleNavigationButton';
|
import ToggleNavigationButton from './ToggleNavigationButton';
|
||||||
|
@ -17,10 +18,10 @@ function Navigation() {
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const { noNavigationAnimation } = useConceptOptions();
|
const { noNavigationAnimation } = useConceptOptions();
|
||||||
|
|
||||||
const navigateHome = () => router.push('/');
|
const navigateHome = () => router.push(urls.home);
|
||||||
const navigateLibrary = () => router.push('/library');
|
const navigateLibrary = () => router.push(urls.library);
|
||||||
const navigateHelp = () => router.push('/manuals');
|
const navigateHelp = () => router.push(urls.manuals);
|
||||||
const navigateCreateNew = () => router.push('/library/create');
|
const navigateCreateNew = () => router.push(urls.create_schema);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav
|
<nav
|
||||||
|
|
|
@ -6,6 +6,8 @@ import { useAuth } from '@/context/AuthContext';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
|
|
||||||
|
import { urls } from '../urls';
|
||||||
|
|
||||||
interface UserDropdownProps {
|
interface UserDropdownProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
hideDropdown: () => void;
|
hideDropdown: () => void;
|
||||||
|
@ -18,12 +20,12 @@ function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
|
||||||
|
|
||||||
function navigateProfile() {
|
function navigateProfile() {
|
||||||
hideDropdown();
|
hideDropdown();
|
||||||
router.push('/profile');
|
router.push(urls.profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
function logoutAndRedirect() {
|
function logoutAndRedirect() {
|
||||||
hideDropdown();
|
hideDropdown();
|
||||||
logout(() => router.push('/login/'));
|
logout(() => router.push(urls.login));
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleToggleDarkMode() {
|
function handleToggleDarkMode() {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { useAuth } from '@/context/AuthContext';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import useDropdown from '@/hooks/useDropdown';
|
import useDropdown from '@/hooks/useDropdown';
|
||||||
|
|
||||||
|
import { urls } from '../urls';
|
||||||
import NavigationButton from './NavigationButton';
|
import NavigationButton from './NavigationButton';
|
||||||
import UserDropdown from './UserDropdown';
|
import UserDropdown from './UserDropdown';
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ function UserMenu() {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const menu = useDropdown();
|
const menu = useDropdown();
|
||||||
|
|
||||||
const navigateLogin = () => router.push('/login');
|
const navigateLogin = () => router.push(urls.login);
|
||||||
return (
|
return (
|
||||||
<div ref={menu.ref} className='h-full'>
|
<div ref={menu.ref} className='h-full'>
|
||||||
{!user ? (
|
{!user ? (
|
||||||
|
|
|
@ -13,6 +13,7 @@ import RSFormPage from '@/pages/RSFormPage';
|
||||||
import UserProfilePage from '@/pages/UserProfilePage';
|
import UserProfilePage from '@/pages/UserProfilePage';
|
||||||
|
|
||||||
import ApplicationLayout from './ApplicationLayout';
|
import ApplicationLayout from './ApplicationLayout';
|
||||||
|
import { routes } from './urls';
|
||||||
|
|
||||||
export const Router = createBrowserRouter([
|
export const Router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
|
@ -25,40 +26,40 @@ export const Router = createBrowserRouter([
|
||||||
element: <HomePage />
|
element: <HomePage />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'login',
|
path: routes.login,
|
||||||
element: <LoginPage />
|
element: <LoginPage />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'signup',
|
path: routes.signup,
|
||||||
element: <RegisterPage />
|
element: <RegisterPage />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'restore-password',
|
path: routes.profile,
|
||||||
element: <RestorePasswordPage />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'password-change',
|
|
||||||
element: <PasswordChangePage />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'profile',
|
|
||||||
element: <UserProfilePage />
|
element: <UserProfilePage />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'manuals',
|
path: routes.restore_password,
|
||||||
element: <ManualsPage />
|
element: <RestorePasswordPage />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'library',
|
path: routes.password_change,
|
||||||
|
element: <PasswordChangePage />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: routes.library,
|
||||||
element: <LibraryPage />
|
element: <LibraryPage />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'library/create',
|
path: routes.create_schema,
|
||||||
element: <CreateRSFormPage />
|
element: <CreateRSFormPage />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'rsforms/:id',
|
path: `${routes.rsforms}/:id`,
|
||||||
element: <RSFormPage />
|
element: <RSFormPage />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: routes.manuals,
|
||||||
|
element: <ManualsPage />
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
49
rsconcept/frontend/src/app/urls.ts
Normal file
49
rsconcept/frontend/src/app/urls.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* Module: Internal navigation constants.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Routes.
|
||||||
|
*/
|
||||||
|
export const routes = {
|
||||||
|
login: 'login',
|
||||||
|
signup: 'signup',
|
||||||
|
profile: 'profile',
|
||||||
|
restore_password: 'restore-password',
|
||||||
|
password_change: 'password-change',
|
||||||
|
library: 'library',
|
||||||
|
create_schema: 'library/create',
|
||||||
|
manuals: 'manuals',
|
||||||
|
help: 'manuals',
|
||||||
|
rsforms: 'rsforms'
|
||||||
|
};
|
||||||
|
|
||||||
|
interface SchemaProps {
|
||||||
|
id: number | string;
|
||||||
|
tab: number;
|
||||||
|
version?: number | string;
|
||||||
|
active?: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal navigation URLs.
|
||||||
|
*/
|
||||||
|
export const urls = {
|
||||||
|
home: '/',
|
||||||
|
login: `/${routes.login}`,
|
||||||
|
login_hint: (userName: string) => `/login?username=${userName}`,
|
||||||
|
profile: `/${routes.profile}`,
|
||||||
|
signup: `/${routes.signup}`,
|
||||||
|
library: `/${routes.library}`,
|
||||||
|
library_filter: (strategy: string) => `/library?filter=${strategy}`,
|
||||||
|
create_schema: `/${routes.create_schema}`,
|
||||||
|
manuals: `/${routes.manuals}`,
|
||||||
|
help_topic: (topic: string) => `/manuals?topic=${topic}`,
|
||||||
|
schema: (id: number | string, version?: number | string) =>
|
||||||
|
`/rsforms/${id}` + (version !== undefined ? `?v=${version}` : ''),
|
||||||
|
schema_props: ({ id, tab, version, active }: SchemaProps) => {
|
||||||
|
const versionStr = version !== undefined ? `v=${version}&` : '';
|
||||||
|
const activeStr = active !== undefined ? `&active=${active}` : '';
|
||||||
|
return `/rsforms/${id}?${versionStr}tab=${tab}${activeStr}`;
|
||||||
|
}
|
||||||
|
};
|
|
@ -10,8 +10,8 @@ import { AnimatePresence } from 'framer-motion';
|
||||||
import { forwardRef, useCallback, useMemo, useRef, useState } from 'react';
|
import { forwardRef, useCallback, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import Label from '@/components/ui/Label';
|
import Label from '@/components/ui/Label';
|
||||||
import { useRSForm } from '@/context/RSFormContext';
|
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
|
import { useRSForm } from '@/context/RSFormContext';
|
||||||
import DlgEditReference from '@/dialogs/DlgEditReference';
|
import DlgEditReference from '@/dialogs/DlgEditReference';
|
||||||
import { ReferenceType } from '@/models/language';
|
import { ReferenceType } from '@/models/language';
|
||||||
import { IConstituenta } from '@/models/rsform';
|
import { IConstituenta } from '@/models/rsform';
|
||||||
|
@ -163,7 +163,7 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className={clsx('flex flex-col gap-2', cursor)}>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{showEditor ? (
|
{showEditor ? (
|
||||||
<DlgEditReference
|
<DlgEditReference
|
||||||
|
@ -180,8 +180,6 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
||||||
<div className={clsx('flex flex-col gap-2', cursor)}>
|
|
||||||
<Label text={label} />
|
<Label text={label} />
|
||||||
<CodeMirror
|
<CodeMirror
|
||||||
id={id}
|
id={id}
|
||||||
|
@ -200,7 +198,6 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import axios, { type AxiosError } from 'axios';
|
import axios, { type AxiosError } from 'axios';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import { urls } from '@/utils/constants';
|
import { external_urls } from '@/utils/constants';
|
||||||
import { isResponseHtml } from '@/utils/utils';
|
import { isResponseHtml } from '@/utils/utils';
|
||||||
|
|
||||||
import PrettyJson from '../ui/PrettyJSON';
|
import PrettyJson from '../ui/PrettyJSON';
|
||||||
|
@ -72,7 +72,7 @@ function InfoError({ error }: InfoErrorProps) {
|
||||||
>
|
>
|
||||||
<p className='font-normal clr-text-default'>
|
<p className='font-normal clr-text-default'>
|
||||||
Пожалуйста сделайте скриншот и отправьте вместе с описанием ситуации на почту{' '}
|
Пожалуйста сделайте скриншот и отправьте вместе с описанием ситуации на почту{' '}
|
||||||
<TextURL href={urls.mail_portal} text='portal@acconcept.ru' />
|
<TextURL href={external_urls.mail_portal} text='portal@acconcept.ru' />
|
||||||
<br />
|
<br />
|
||||||
Для продолжения работы перезагрузите страницу
|
Для продолжения работы перезагрузите страницу
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import TextURL from '@/components/ui/TextURL';
|
import TextURL from '@/components/ui/TextURL';
|
||||||
import { urls } from '@/utils/constants';
|
import { external_urls } from '@/utils/constants';
|
||||||
|
|
||||||
function HelpAPI() {
|
function HelpAPI() {
|
||||||
return (
|
return (
|
||||||
|
@ -8,10 +8,10 @@ function HelpAPI() {
|
||||||
<p>В качестве программного интерфейса сервера используется REST API, реализованный с помощью Django.</p>
|
<p>В качестве программного интерфейса сервера используется REST API, реализованный с помощью Django.</p>
|
||||||
<p>На данный момент API находится в разработке, поэтому поддержка внешних запросов не производится.</p>
|
<p>На данный момент API находится в разработке, поэтому поддержка внешних запросов не производится.</p>
|
||||||
<p>
|
<p>
|
||||||
С описанием интерфейса можно ознакомиться <TextURL text='по ссылке' href={urls.restAPI} />.
|
С описанием интерфейса можно ознакомиться <TextURL text='по ссылке' href={external_urls.restAPI} />.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<TextURL text='Принять участие в разработке' href={urls.git_repo} />
|
<TextURL text='Принять участие в разработке' href={external_urls.git_repo} />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import TextURL from '@/components/ui/TextURL';
|
import TextURL from '@/components/ui/TextURL';
|
||||||
import { urls } from '@/utils/constants';
|
import { external_urls } from '@/utils/constants';
|
||||||
|
|
||||||
function HelpExteor() {
|
function HelpExteor() {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
@ -9,7 +9,7 @@ function HelpExteor() {
|
||||||
<p>Экстеор 4.9 — редактор текстов систем понятий эксплицированных в родах структур</p>
|
<p>Экстеор 4.9 — редактор текстов систем понятий эксплицированных в родах структур</p>
|
||||||
<p>Портал превосходит Экстеор в части редактирования экспликаций, но функции синтеза и вычисления интерпретации пока доступны только в Экстеоре. Также следует использовать Экстеор для выгрузки экспликаций в Word для последующей печати</p>
|
<p>Портал превосходит Экстеор в части редактирования экспликаций, но функции синтеза и вычисления интерпретации пока доступны только в Экстеоре. Также следует использовать Экстеор для выгрузки экспликаций в Word для последующей печати</p>
|
||||||
<p>Экстеор доступен на операционной системы Windows 10+</p>
|
<p>Экстеор доступен на операционной системы Windows 10+</p>
|
||||||
<p>Скачать установщик: <TextURL href={urls.exteor64} text='64bit'/> | <TextURL href={urls.exteor32} text='32bit'/></p>
|
<p>Скачать установщик: <TextURL href={external_urls.exteor64} text='64bit'/> | <TextURL href={external_urls.exteor32} text='32bit'/></p>
|
||||||
<h2>Основные функции</h2>
|
<h2>Основные функции</h2>
|
||||||
<li>Работа с РС-формой системы понятий</li>
|
<li>Работа с РС-формой системы понятий</li>
|
||||||
<li>Автоматическое определение типизации выражений</li>
|
<li>Автоматическое определение типизации выражений</li>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import TextURL from '@/components/ui/TextURL';
|
import TextURL from '@/components/ui/TextURL';
|
||||||
import { urls } from '@/utils/constants';
|
import { external_urls } from '@/utils/constants';
|
||||||
|
|
||||||
function HelpMain() {
|
function HelpMain() {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
|
@ -16,8 +16,8 @@ function HelpMain() {
|
||||||
<p>В меню пользователя (правый угол) доступно редактирование пользователя и изменение цветовой темы</p>
|
<p>В меню пользователя (правый угол) доступно редактирование пользователя и изменение цветовой темы</p>
|
||||||
|
|
||||||
<h2>Поддержка</h2>
|
<h2>Поддержка</h2>
|
||||||
<p>Портал разрабатывается <TextURL text='Центром Концепт' href={urls.concept}/> и является проектом с открытым исходным кодом, доступным на <TextURL text='Github' href={urls.git_repo}/></p>
|
<p>Портал разрабатывается <TextURL text='Центром Концепт' href={external_urls.concept}/> и является проектом с открытым исходным кодом, доступным на <TextURL text='Github' href={external_urls.git_repo}/></p>
|
||||||
<p>Ваши пожелания по доработке, найденные ошибки и иные предложения можно направлять по email: <TextURL href={urls.mail_portal} text='portal@acconcept.ru'/></p>
|
<p>Ваши пожелания по доработке, найденные ошибки и иные предложения можно направлять по email: <TextURL href={external_urls.mail_portal} text='portal@acconcept.ru'/></p>
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { useMemo } from 'react';
|
||||||
|
|
||||||
import EmbedYoutube from '@/components/ui/EmbedYoutube';
|
import EmbedYoutube from '@/components/ui/EmbedYoutube';
|
||||||
import useWindowSize from '@/hooks/useWindowSize';
|
import useWindowSize from '@/hooks/useWindowSize';
|
||||||
import { urls, youtube } from '@/utils/constants';
|
import { external_urls, youtube } from '@/utils/constants';
|
||||||
|
|
||||||
const OPT_VIDEO_H = 1080;
|
const OPT_VIDEO_H = 1080;
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@ function HelpRSLang() {
|
||||||
<p>Данный математический аппарат основан на аксиоматической теории множеств Цермелло-Френкеля и аппарате родов структур Н.Бурбаки.</p>
|
<p>Данный математический аппарат основан на аксиоматической теории множеств Цермелло-Френкеля и аппарате родов структур Н.Бурбаки.</p>
|
||||||
<p>Для ознакомления с основами родов структур можно использовать следующие материалы:</p>
|
<p>Для ознакомления с основами родов структур можно использовать следующие материалы:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>1. <a className='underline' href={urls.intro_video}>Видео: Краткое введение в мат. аппарат</a></li>
|
<li>1. <a className='underline' href={external_urls.intro_video}>Видео: Краткое введение в мат. аппарат</a></li>
|
||||||
<li>2. <a className='underline' href={urls.ponomarev}>Текст: Учебник И. Н. Пономарева</a></li>
|
<li>2. <a className='underline' href={external_urls.ponomarev}>Текст: Учебник И. Н. Пономарева</a></li>
|
||||||
<li>3. <a className='underline' href={urls.full_course}>Видео: лекции для 4 курса (второй семестр 2022-23 год)</a></li>
|
<li>3. <a className='underline' href={external_urls.full_course}>Видео: лекции для 4 курса (второй семестр 2022-23 год)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className='justify-center w-full'>
|
<div className='justify-center w-full'>
|
||||||
|
|
|
@ -17,13 +17,13 @@ interface DataLoaderProps extends CProps.AnimatedDiv {
|
||||||
|
|
||||||
function DataLoader({ id, isLoading, hasNoData, error, children, ...restProps }: DataLoaderProps) {
|
function DataLoader({ id, isLoading, hasNoData, error, children, ...restProps }: DataLoaderProps) {
|
||||||
return (
|
return (
|
||||||
<AnimatePresence mode='wait'>
|
<AnimatePresence>
|
||||||
{isLoading ? <Loader key={`${id}-loader`} /> : null}
|
{isLoading ? <Loader key={`${id}-loader`} /> : null}
|
||||||
{error ? <InfoError key={`${id}-error`} error={error} /> : null}
|
{error ? <InfoError key={`${id}-error`} error={error} /> : null}
|
||||||
<AnimateFade id={id} key={`${id}-data`} removeContent={isLoading || !!error || hasNoData} {...restProps}>
|
<AnimateFade id={id} key={`${id}-data`} removeContent={isLoading || !!error || hasNoData} {...restProps}>
|
||||||
{children}
|
{children}
|
||||||
</AnimateFade>
|
</AnimateFade>
|
||||||
<AnimateFade id={id} key={`${id}-data`} removeContent={isLoading || !!error || !hasNoData} {...restProps}>
|
<AnimateFade id={id} key={`${id}-no-data`} removeContent={isLoading || !!error || !hasNoData} {...restProps}>
|
||||||
Данные не загружены
|
Данные не загружены
|
||||||
</AnimateFade>
|
</AnimateFade>
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ function ExpectedAnonymous() {
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
|
|
||||||
function logoutAndRedirect() {
|
function logoutAndRedirect() {
|
||||||
logout(() => router.push('/login/'));
|
logout(() => router.push(urls.login));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -4,6 +4,7 @@ import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import Checkbox from '@/components/ui/Checkbox';
|
import Checkbox from '@/components/ui/Checkbox';
|
||||||
import Modal, { ModalProps } from '@/components/ui/Modal';
|
import Modal, { ModalProps } from '@/components/ui/Modal';
|
||||||
import TextArea from '@/components/ui/TextArea';
|
import TextArea from '@/components/ui/TextArea';
|
||||||
|
@ -51,7 +52,7 @@ function DlgCloneLibraryItem({ hideWindow, base }: DlgCloneLibraryItemProps) {
|
||||||
};
|
};
|
||||||
cloneItem(base.id, data, newSchema => {
|
cloneItem(base.id, data, newSchema => {
|
||||||
toast.success(`Копия создана: ${newSchema.alias}`);
|
toast.success(`Копия создана: ${newSchema.alias}`);
|
||||||
router.push(`/rsforms/${newSchema.id}`);
|
router.push(urls.schema(newSchema.id));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreat
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
<div className='flex items-center self-center'>
|
<div key='dlg_cst_alias_picker' className='flex items-center self-center'>
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
id='dlg_cst_type'
|
id='dlg_cst_type'
|
||||||
placeholder='Выберите тип'
|
placeholder='Выберите тип'
|
||||||
|
@ -61,6 +61,7 @@ function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreat
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<TextArea
|
<TextArea
|
||||||
|
key='dlg_cst_term'
|
||||||
id='dlg_cst_term'
|
id='dlg_cst_term'
|
||||||
spellCheck
|
spellCheck
|
||||||
label='Термин'
|
label='Термин'
|
||||||
|
@ -69,7 +70,7 @@ function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreat
|
||||||
value={state.term_raw}
|
value={state.term_raw}
|
||||||
onChange={event => partialUpdate({ term_raw: event.target.value })}
|
onChange={event => partialUpdate({ term_raw: event.target.value })}
|
||||||
/>
|
/>
|
||||||
<AnimateFade hideContent={!state.definition_formal && isElementary}>
|
<AnimateFade key='dlg_cst_expression' hideContent={!state.definition_formal && isElementary}>
|
||||||
<RSInput
|
<RSInput
|
||||||
id='dlg_cst_expression'
|
id='dlg_cst_expression'
|
||||||
label={
|
label={
|
||||||
|
@ -88,7 +89,7 @@ function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreat
|
||||||
onChange={value => partialUpdate({ definition_formal: value })}
|
onChange={value => partialUpdate({ definition_formal: value })}
|
||||||
/>
|
/>
|
||||||
</AnimateFade>
|
</AnimateFade>
|
||||||
<AnimateFade hideContent={!state.definition_raw && isElementary}>
|
<AnimateFade key='dlg_cst_definition' hideContent={!state.definition_raw && isElementary}>
|
||||||
<TextArea
|
<TextArea
|
||||||
id='dlg_cst_definition'
|
id='dlg_cst_definition'
|
||||||
spellCheck
|
spellCheck
|
||||||
|
@ -101,6 +102,8 @@ function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreat
|
||||||
</AnimateFade>
|
</AnimateFade>
|
||||||
{!showConvention ? (
|
{!showConvention ? (
|
||||||
<button
|
<button
|
||||||
|
key='dlg_cst_show_comment'
|
||||||
|
id='dlg_cst_show_comment'
|
||||||
type='button'
|
type='button'
|
||||||
className='self-start cc-label clr-text-url hover:underline'
|
className='self-start cc-label clr-text-url hover:underline'
|
||||||
onClick={() => setForceComment(true)}
|
onClick={() => setForceComment(true)}
|
||||||
|
@ -110,6 +113,7 @@ function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreat
|
||||||
) : null}
|
) : null}
|
||||||
<AnimateFade hideContent={!showConvention}>
|
<AnimateFade hideContent={!showConvention}>
|
||||||
<TextArea
|
<TextArea
|
||||||
|
key='dlg_cst_convention'
|
||||||
id='dlg_cst_convention'
|
id='dlg_cst_convention'
|
||||||
spellCheck
|
spellCheck
|
||||||
label={isBasic ? 'Конвенция' : 'Комментарий'}
|
label={isBasic ? 'Конвенция' : 'Комментарий'}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { useEffect, useRef, useState } from 'react';
|
||||||
import { BiDownload } from 'react-icons/bi';
|
import { BiDownload } from 'react-icons/bi';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import InfoError from '@/components/info/InfoError';
|
import InfoError from '@/components/info/InfoError';
|
||||||
import Button from '@/components/ui/Button';
|
import Button from '@/components/ui/Button';
|
||||||
import Checkbox from '@/components/ui/Checkbox';
|
import Checkbox from '@/components/ui/Checkbox';
|
||||||
|
@ -43,7 +44,7 @@ function CreateRSFormPage() {
|
||||||
if (router.canBack()) {
|
if (router.canBack()) {
|
||||||
router.back();
|
router.back();
|
||||||
} else {
|
} else {
|
||||||
router.push('/library');
|
router.push(urls.library);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ function CreateRSFormPage() {
|
||||||
};
|
};
|
||||||
createItem(data, newSchema => {
|
createItem(data, newSchema => {
|
||||||
toast.success('Схема успешно создана');
|
toast.success('Схема успешно создана');
|
||||||
router.push(`/rsforms/${newSchema.id}`);
|
router.push(urls.schema(newSchema.id));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { useLayoutEffect } from 'react';
|
import { useLayoutEffect } from 'react';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { TIMEOUT_UI_REFRESH } from '@/utils/constants';
|
import { TIMEOUT_UI_REFRESH } from '@/utils/constants';
|
||||||
|
@ -11,11 +12,11 @@ function HomePage() {
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
router.push('/manuals');
|
router.push(urls.manuals);
|
||||||
}, TIMEOUT_UI_REFRESH);
|
}, TIMEOUT_UI_REFRESH);
|
||||||
} else {
|
} else {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
router.push('/library');
|
router.push(urls.library);
|
||||||
}, TIMEOUT_UI_REFRESH);
|
}, TIMEOUT_UI_REFRESH);
|
||||||
}
|
}
|
||||||
}, [router, user]);
|
}, [router, user]);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import { useCallback, useLayoutEffect, useState } from 'react';
|
import { useCallback, useLayoutEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import DataLoader from '@/components/wrap/DataLoader';
|
import DataLoader from '@/components/wrap/DataLoader';
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useLibrary } from '@/context/LibraryContext';
|
import { useLibrary } from '@/context/LibraryContext';
|
||||||
|
@ -38,7 +39,7 @@ function LibraryPage() {
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (!queryFilter || !Object.values(LibraryFilterStrategy).includes(queryFilter)) {
|
if (!queryFilter || !Object.values(LibraryFilterStrategy).includes(queryFilter)) {
|
||||||
router.replace(`/library?filter=${strategy}`);
|
router.replace(urls.library_filter(strategy));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setQuery('');
|
setQuery('');
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import SearchBar from '@/components/ui/SearchBar';
|
import SearchBar from '@/components/ui/SearchBar';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { ILibraryFilter } from '@/models/miscellaneous';
|
import { ILibraryFilter } from '@/models/miscellaneous';
|
||||||
|
@ -37,7 +38,7 @@ function SearchPanel({ total, filtered, query, setQuery, strategy, setFilter }:
|
||||||
const handleChangeStrategy = useCallback(
|
const handleChangeStrategy = useCallback(
|
||||||
(value: LibraryFilterStrategy) => {
|
(value: LibraryFilterStrategy) => {
|
||||||
if (value !== strategy) {
|
if (value !== strategy) {
|
||||||
router.push(`/library?filter=${value}`);
|
router.push(urls.library_filter(value));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[strategy, router]
|
[strategy, router]
|
||||||
|
|
|
@ -4,6 +4,7 @@ import clsx from 'clsx';
|
||||||
import { useLayoutEffect, useMemo, useState } from 'react';
|
import { useLayoutEffect, useMemo, useState } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import BadgeHelp from '@/components/man/BadgeHelp';
|
import BadgeHelp from '@/components/man/BadgeHelp';
|
||||||
import DataTable, { createColumnHelper, VisibilityState } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper, VisibilityState } from '@/components/ui/DataTable';
|
||||||
import FlexColumn from '@/components/ui/FlexColumn';
|
import FlexColumn from '@/components/ui/FlexColumn';
|
||||||
|
@ -33,7 +34,7 @@ function ViewLibrary({ items, resetQuery }: ViewLibraryProps) {
|
||||||
const { getUserLabel } = useUsers();
|
const { getUserLabel } = useUsers();
|
||||||
const [itemsPerPage, setItemsPerPage] = useLocalStorage<number>(storage.libraryPagination, 50);
|
const [itemsPerPage, setItemsPerPage] = useLocalStorage<number>(storage.libraryPagination, 50);
|
||||||
|
|
||||||
const handleOpenItem = (item: ILibraryItem) => router.push(`/rsforms/${item.id}`);
|
const handleOpenItem = (item: ILibraryItem) => router.push(urls.schema(item.id));
|
||||||
|
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import axios from 'axios';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import InfoError, { ErrorData } from '@/components/info/InfoError';
|
import InfoError, { ErrorData } from '@/components/info/InfoError';
|
||||||
import SubmitButton from '@/components/ui/SubmitButton';
|
import SubmitButton from '@/components/ui/SubmitButton';
|
||||||
import TextInput from '@/components/ui/TextInput';
|
import TextInput from '@/components/ui/TextInput';
|
||||||
|
@ -53,7 +54,7 @@ function LoginPage() {
|
||||||
if (router.canBack()) {
|
if (router.canBack()) {
|
||||||
router.back();
|
router.back();
|
||||||
} else {
|
} else {
|
||||||
router.push('/library');
|
router.push(urls.library);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
import useQueryStrings from '@/hooks/useQueryStrings';
|
import useQueryStrings from '@/hooks/useQueryStrings';
|
||||||
|
@ -16,7 +17,7 @@ function ManualsPage() {
|
||||||
const { mainHeight } = useConceptOptions();
|
const { mainHeight } = useConceptOptions();
|
||||||
|
|
||||||
function onSelectTopic(newTopic: HelpTopic) {
|
function onSelectTopic(newTopic: HelpTopic) {
|
||||||
router.push(`/manuals?topic=${newTopic}`);
|
router.push(urls.help_topic(newTopic));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -4,6 +4,7 @@ import axios from 'axios';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import InfoError, { ErrorData } from '@/components/info/InfoError';
|
import InfoError, { ErrorData } from '@/components/info/InfoError';
|
||||||
import SubmitButton from '@/components/ui/SubmitButton';
|
import SubmitButton from '@/components/ui/SubmitButton';
|
||||||
import TextInput from '@/components/ui/TextInput';
|
import TextInput from '@/components/ui/TextInput';
|
||||||
|
@ -51,8 +52,8 @@ function PasswordChangePage() {
|
||||||
token: token!
|
token: token!
|
||||||
};
|
};
|
||||||
resetPassword(data, () => {
|
resetPassword(data, () => {
|
||||||
router.replace('/');
|
router.replace(urls.home);
|
||||||
router.push('/login');
|
router.push(urls.login);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,8 +141,8 @@ function FormConstituenta({
|
||||||
className={clsx('cc-column', 'mt-1 w-full md:w-[47.8rem] shrink-0', 'px-4 py-1')}
|
className={clsx('cc-column', 'mt-1 w-full md:w-[47.8rem] shrink-0', 'px-4 py-1')}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
<AnimatePresence>
|
|
||||||
<RefsInput
|
<RefsInput
|
||||||
|
key='cst_term'
|
||||||
id='cst_term'
|
id='cst_term'
|
||||||
label='Термин'
|
label='Термин'
|
||||||
placeholder='Обозначение, используемое в текстовых определениях'
|
placeholder='Обозначение, используемое в текстовых определениях'
|
||||||
|
@ -166,7 +166,8 @@ function FormConstituenta({
|
||||||
resize: 'none'
|
resize: 'none'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<AnimateFade hideContent={!!state && !state?.definition_formal && isElementary}>
|
<AnimatePresence>
|
||||||
|
<AnimateFade key='cst_expression_fade' hideContent={!!state && !state?.definition_formal && isElementary}>
|
||||||
<EditorRSExpression
|
<EditorRSExpression
|
||||||
id='cst_expression'
|
id='cst_expression'
|
||||||
label={
|
label={
|
||||||
|
@ -191,7 +192,7 @@ function FormConstituenta({
|
||||||
setTypification={setTypification}
|
setTypification={setTypification}
|
||||||
/>
|
/>
|
||||||
</AnimateFade>
|
</AnimateFade>
|
||||||
<AnimateFade hideContent={!!state && !state?.definition_raw && isElementary}>
|
<AnimateFade key='cst_definition_fade' hideContent={!!state && !state?.definition_raw && isElementary}>
|
||||||
<RefsInput
|
<RefsInput
|
||||||
id='cst_definition'
|
id='cst_definition'
|
||||||
label='Текстовое определение'
|
label='Текстовое определение'
|
||||||
|
@ -205,7 +206,7 @@ function FormConstituenta({
|
||||||
onChange={newValue => setTextDefinition(newValue)}
|
onChange={newValue => setTextDefinition(newValue)}
|
||||||
/>
|
/>
|
||||||
</AnimateFade>
|
</AnimateFade>
|
||||||
<AnimateFade hideContent={!showConvention}>
|
<AnimateFade key='cst_convention_fade' hideContent={!showConvention}>
|
||||||
<TextArea
|
<TextArea
|
||||||
id='cst_convention'
|
id='cst_convention'
|
||||||
spellCheck
|
spellCheck
|
||||||
|
@ -220,6 +221,8 @@ function FormConstituenta({
|
||||||
</AnimateFade>
|
</AnimateFade>
|
||||||
{!showConvention && (!disabled || processing) ? (
|
{!showConvention && (!disabled || processing) ? (
|
||||||
<button
|
<button
|
||||||
|
key='cst_disable_comment'
|
||||||
|
id='cst_disable_comment'
|
||||||
type='button'
|
type='button'
|
||||||
className='self-start cc-label clr-text-url hover:underline'
|
className='self-start cc-label clr-text-url hover:underline'
|
||||||
onClick={() => setForceComment(true)}
|
onClick={() => setForceComment(true)}
|
||||||
|
@ -229,6 +232,8 @@ function FormConstituenta({
|
||||||
) : null}
|
) : null}
|
||||||
{!disabled || processing ? (
|
{!disabled || processing ? (
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
|
key='cst_form_submit'
|
||||||
|
id='cst_form_submit'
|
||||||
text='Сохранить изменения'
|
text='Сохранить изменения'
|
||||||
className='self-center'
|
className='self-center'
|
||||||
disabled={disabled || !isModified}
|
disabled={disabled || !isModified}
|
||||||
|
|
|
@ -154,14 +154,13 @@ function EditorRSExpression({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{showAST ? (
|
{showAST ? (
|
||||||
<DlgShowAST expression={expression} syntaxTree={syntaxTree} hideWindow={() => setShowAST(false)} />
|
<DlgShowAST expression={expression} syntaxTree={syntaxTree} hideWindow={() => setShowAST(false)} />
|
||||||
) : null}
|
) : null}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
||||||
<div>
|
|
||||||
<Overlay position='top-[-0.5rem] right-0 flex'>
|
<Overlay position='top-[-0.5rem] right-0 flex'>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Изменить шрифт'
|
title='Изменить шрифт'
|
||||||
|
@ -224,7 +223,6 @@ function EditorRSExpression({
|
||||||
onShowError={onShowError}
|
onShowError={onShowError}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,10 @@ function StatusBar({ isModified, processing, constituenta, parseData, onAnalyze
|
||||||
{processing ? <Loader key='status-loader' size={3} /> : null}
|
{processing ? <Loader key='status-loader' size={3} /> : null}
|
||||||
{!processing ? (
|
{!processing ? (
|
||||||
<>
|
<>
|
||||||
<StatusIcon status={status} />
|
<StatusIcon key='status-icon' status={status} />
|
||||||
<span className='pb-[0.125rem] font-controls pr-2'>{labelExpressionStatus(status)}</span>
|
<span key='status-text' className='pb-[0.125rem] font-controls pr-2'>
|
||||||
|
{labelExpressionStatus(status)}
|
||||||
|
</span>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
|
@ -6,6 +6,7 @@ import fileDownload from 'js-file-download';
|
||||||
import { createContext, useCallback, useContext, useLayoutEffect, useMemo, useState } from 'react';
|
import { createContext, useCallback, useContext, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import InfoError, { ErrorData } from '@/components/info/InfoError';
|
import InfoError, { ErrorData } from '@/components/info/InfoError';
|
||||||
import Divider from '@/components/ui/Divider';
|
import Divider from '@/components/ui/Divider';
|
||||||
import Loader from '@/components/ui/Loader';
|
import Loader from '@/components/ui/Loader';
|
||||||
|
@ -152,13 +153,7 @@ export const RSEditState = ({
|
||||||
);
|
);
|
||||||
|
|
||||||
const viewVersion = useCallback(
|
const viewVersion = useCallback(
|
||||||
(version?: number) => {
|
(version?: number) => router.push(urls.schema(model.schemaID, version)),
|
||||||
if (version) {
|
|
||||||
router.push(`/rsforms/${model.schemaID}?v=${version}`);
|
|
||||||
} else {
|
|
||||||
router.push(`/rsforms/${model.schemaID}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[router, model]
|
[router, model]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,13 @@ import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import TabLabel from '@/components/ui/TabLabel';
|
import TabLabel from '@/components/ui/TabLabel';
|
||||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||||
import { useLibrary } from '@/context/LibraryContext';
|
import { useLibrary } from '@/context/LibraryContext';
|
||||||
import { useBlockNavigation, useConceptNavigation } from '@/context/NavigationContext';
|
import { useBlockNavigation, useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { useRSForm } from '@/context/RSFormContext';
|
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
|
import { useRSForm } from '@/context/RSFormContext';
|
||||||
import useQueryStrings from '@/hooks/useQueryStrings';
|
import useQueryStrings from '@/hooks/useQueryStrings';
|
||||||
import { ConstituentaID, IConstituenta, IConstituentaMeta } from '@/models/rsform';
|
import { ConstituentaID, IConstituenta, IConstituentaMeta } from '@/models/rsform';
|
||||||
import { prefixes, TIMEOUT_UI_REFRESH } from '@/utils/constants';
|
import { prefixes, TIMEOUT_UI_REFRESH } from '@/utils/constants';
|
||||||
|
@ -34,7 +35,7 @@ function RSTabs() {
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const query = useQueryStrings();
|
const query = useQueryStrings();
|
||||||
const activeTab = (Number(query.get('tab')) ?? RSTabID.CARD) as RSTabID;
|
const activeTab = (Number(query.get('tab')) ?? RSTabID.CARD) as RSTabID;
|
||||||
const version = Number(query.get('v')) ?? undefined;
|
const version = query.get('v') ? Number(query.get('v')) : undefined;
|
||||||
const cstQuery = query.get('active');
|
const cstQuery = query.get('active');
|
||||||
|
|
||||||
const { setNoFooter, calculateHeight } = useConceptOptions();
|
const { setNoFooter, calculateHeight } = useConceptOptions();
|
||||||
|
@ -84,18 +85,23 @@ function RSTabs() {
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const versionStr = version ? `v=${version}&` : '';
|
const url = urls.schema_props({
|
||||||
|
id: schema.id,
|
||||||
|
tab: tab,
|
||||||
|
active: activeID,
|
||||||
|
version: version
|
||||||
|
});
|
||||||
if (activeID) {
|
if (activeID) {
|
||||||
if (tab === activeTab && tab !== RSTabID.CST_EDIT) {
|
if (tab === activeTab && tab !== RSTabID.CST_EDIT) {
|
||||||
router.replace(`/rsforms/${schema.id}?${versionStr}tab=${tab}&active=${activeID}`);
|
router.replace(url);
|
||||||
} else {
|
} else {
|
||||||
router.push(`/rsforms/${schema.id}?${versionStr}tab=${tab}&active=${activeID}`);
|
router.push(url);
|
||||||
}
|
}
|
||||||
} 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;
|
||||||
router.replace(`/rsforms/${schema.id}?${versionStr}tab=${tab}&active=${activeID}`);
|
router.replace(url);
|
||||||
} else {
|
} else {
|
||||||
router.push(`/rsforms/${schema.id}?${versionStr}tab=${tab}`);
|
router.push(url);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[router, schema, activeTab, version]
|
[router, schema, activeTab, version]
|
||||||
|
@ -150,7 +156,7 @@ function RSTabs() {
|
||||||
}
|
}
|
||||||
destroyItem(schema.id, () => {
|
destroyItem(schema.id, () => {
|
||||||
toast.success('Схема удалена');
|
toast.success('Схема удалена');
|
||||||
router.push('/library');
|
router.push(urls.library);
|
||||||
});
|
});
|
||||||
}, [schema, destroyItem, router]);
|
}, [schema, destroyItem, router]);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import {
|
||||||
} from 'react-icons/lu';
|
} from 'react-icons/lu';
|
||||||
import { VscLibrary } from 'react-icons/vsc';
|
import { VscLibrary } from 'react-icons/vsc';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import Button from '@/components/ui/Button';
|
import Button from '@/components/ui/Button';
|
||||||
import Dropdown from '@/components/ui/Dropdown';
|
import Dropdown from '@/components/ui/Dropdown';
|
||||||
import DropdownButton from '@/components/ui/DropdownButton';
|
import DropdownButton from '@/components/ui/DropdownButton';
|
||||||
|
@ -114,11 +115,11 @@ function RSTabsMenu({ onDestroy }: RSTabsMenuProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCreateNew() {
|
function handleCreateNew() {
|
||||||
router.push('/library/create');
|
router.push(urls.create_schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleLogin() {
|
function handleLogin() {
|
||||||
router.push('/login');
|
router.push(urls.login);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -189,7 +190,7 @@ function RSTabsMenu({ onDestroy }: RSTabsMenuProps) {
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text='Библиотека'
|
text='Библиотека'
|
||||||
icon={<VscLibrary size='1rem' className='icon-primary' />}
|
icon={<VscLibrary size='1rem' className='icon-primary' />}
|
||||||
onClick={() => router.push('/library')}
|
onClick={() => router.push(urls.library)}
|
||||||
/>
|
/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { useEffect, useState } from 'react';
|
||||||
import { BiInfoCircle } from 'react-icons/bi';
|
import { BiInfoCircle } from 'react-icons/bi';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import InfoError from '@/components/info/InfoError';
|
import InfoError from '@/components/info/InfoError';
|
||||||
import Button from '@/components/ui/Button';
|
import Button from '@/components/ui/Button';
|
||||||
import Checkbox from '@/components/ui/Checkbox';
|
import Checkbox from '@/components/ui/Checkbox';
|
||||||
|
@ -42,7 +43,7 @@ function RegisterPage() {
|
||||||
if (router.canBack()) {
|
if (router.canBack()) {
|
||||||
router.back();
|
router.back();
|
||||||
} else {
|
} else {
|
||||||
router.push('/library');
|
router.push(urls.library);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ function RegisterPage() {
|
||||||
last_name: lastName
|
last_name: lastName
|
||||||
};
|
};
|
||||||
signup(data, createdUser => {
|
signup(data, createdUser => {
|
||||||
router.push(`/login?username=${createdUser.username}`);
|
router.push(urls.login_hint(createdUser.username));
|
||||||
toast.success(`Пользователь успешно создан: ${createdUser.username}`);
|
toast.success(`Пользователь успешно создан: ${createdUser.username}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import InfoError, { ErrorData } from '@/components/info/InfoError';
|
import InfoError, { ErrorData } from '@/components/info/InfoError';
|
||||||
import FlexColumn from '@/components/ui/FlexColumn';
|
import FlexColumn from '@/components/ui/FlexColumn';
|
||||||
import SubmitButton from '@/components/ui/SubmitButton';
|
import SubmitButton from '@/components/ui/SubmitButton';
|
||||||
|
@ -53,7 +54,7 @@ function EditorPassword() {
|
||||||
};
|
};
|
||||||
updatePassword(data, () => {
|
updatePassword(data, () => {
|
||||||
toast.success('Изменения сохранены');
|
toast.success('Изменения сохранены');
|
||||||
router.push('/login');
|
router.push(urls.login);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { motion } from 'framer-motion';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
import DataTable, { createColumnHelper } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper } from '@/components/ui/DataTable';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { ILibraryItem } from '@/models/library';
|
import { ILibraryItem } from '@/models/library';
|
||||||
|
@ -19,7 +20,7 @@ function ViewSubscriptions({ items }: ViewSubscriptionsProps) {
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const openRSForm = (item: ILibraryItem) => router.push(`/rsforms/${item.id}`);
|
const openRSForm = (item: ILibraryItem) => router.push(urls.schema(item.id));
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
() => [
|
() => [
|
||||||
|
|
|
@ -63,7 +63,7 @@ export const youtube = {
|
||||||
/**
|
/**
|
||||||
* External URLs.
|
* External URLs.
|
||||||
*/
|
*/
|
||||||
export const urls = {
|
export const external_urls = {
|
||||||
concept: 'https://www.acconcept.ru/',
|
concept: 'https://www.acconcept.ru/',
|
||||||
exteor32: 'https://drive.google.com/open?id=1IHlMMwaYlAUBRSxU1RU_hXM5mFU9-oyK&usp=drive_fs',
|
exteor32: 'https://drive.google.com/open?id=1IHlMMwaYlAUBRSxU1RU_hXM5mFU9-oyK&usp=drive_fs',
|
||||||
exteor64: 'https://drive.google.com/open?id=1IJt25ZRQ-ZMA6t7hOqmo5cv05WJCQKMv&usp=drive_fs',
|
exteor64: 'https://drive.google.com/open?id=1IJt25ZRQ-ZMA6t7hOqmo5cv05WJCQKMv&usp=drive_fs',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user