This commit is contained in:
Ulle9 2023-08-28 21:58:47 +03:00
commit 631cf61d17
20 changed files with 226 additions and 76 deletions

View File

@ -1,4 +1,4 @@
import { Route, Routes } from 'react-router-dom'; import { createBrowserRouter, Outlet, RouterProvider } from 'react-router-dom';
import Footer from './components/Footer'; import Footer from './components/Footer';
import Navigation from './components/Navigation/Navigation'; import Navigation from './components/Navigation/Navigation';
@ -15,8 +15,8 @@ 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';
function App () { function Root() {
const { noNavigation, noFooter, viewportHeight, mainHeight } = useConceptTheme(); const { noNavigation, noFooter, viewportHeight, mainHeight } = useConceptTheme();
return ( return (
<div className='antialiased clr-app'> <div className='antialiased clr-app'>
<Navigation /> <Navigation />
@ -26,24 +26,9 @@ function App () {
draggable={false} draggable={false}
pauseOnFocusLoss={false} pauseOnFocusLoss={false}
/> />
<div className='overflow-auto' style={{maxHeight: viewportHeight}}> <div className='overflow-auto' style={{maxHeight: viewportHeight}}>
<main className='h-full' style={{minHeight: mainHeight}}> <main className='h-full' style={{minHeight: mainHeight}}>
<Routes> <Outlet />
<Route path='/' element={ <HomePage/>} />
<Route path='login' element={ <LoginPage/>} />
<Route path='signup' element={<RegisterPage/>} />
<Route path='restore-password' element={ <RestorePasswordPage/>} />
<Route path='profile' element={<UserProfilePage/>} />
<Route path='manuals' element={<ManualsPage/>} />
<Route path='library' element={<LibraryPage/>} />
<Route path='rsforms/:id' element={ <RSFormPage/>} />
<Route path='rsform-create' element={ <CreateRSFormPage/>} />
<Route path='*' element={ <NotFoundPage/>} />
</Routes>
</main> </main>
{!noNavigation && !noFooter && <Footer />} {!noNavigation && !noFooter && <Footer />}
</div> </div>
@ -51,4 +36,57 @@ function App () {
); );
} }
const router = createBrowserRouter([
{
path: '/',
element: <Root />,
errorElement: <NotFoundPage />,
children: [
{
path: '',
element: <HomePage />,
},
{
path: 'login',
element: <LoginPage />,
},
{
path: 'signup',
element: <RegisterPage />,
},
{
path: 'restore-password',
element: <RestorePasswordPage />,
},
{
path: 'profile',
element: <UserProfilePage />,
},
{
path: 'manuals',
element: <ManualsPage />,
},
{
path: 'library',
element: <LibraryPage />,
},
{
path: 'rsforms/:id',
element: <RSFormPage />,
},
{
path: 'rsform-create',
element: <CreateRSFormPage />,
},
]
},
]);
function App () {
return (
<RouterProvider router={router} />
);
}
export default App; export default App;

View File

@ -9,7 +9,7 @@ interface BackendErrorProps {
} }
function DescribeError(error: ErrorInfo) { function DescribeError(error: ErrorInfo) {
console.log(error); reportError(error);
if (!error) { if (!error) {
return <p>Ошибки отсутствуют</p>; return <p>Ошибки отсутствуют</p>;
} else if (typeof error === 'string') { } else if (typeof error === 'string') {

View File

@ -0,0 +1,30 @@
interface EmbedYoutubeProps {
videoID: string
pxHeight: number
pxWidth?: number
}
function EmbedYoutube({ videoID, pxHeight, pxWidth }: EmbedYoutubeProps) {
if (!pxWidth) {
pxWidth = pxHeight * 16 / 9;
}
return (
<div
className='relative'
style={{height: 0, paddingBottom: `${pxHeight}px`, paddingLeft: `${pxWidth}px`}}
>
<iframe
className='absolute top-0 left-0 clr-border'
style={{minHeight: `${pxHeight}px`, minWidth: `${pxWidth}px`}}
width={`${pxWidth}px`}
height={`${pxHeight}px`}
src={`https://www.youtube.com/embed/${videoID}`}
allow='accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture'
allowFullScreen
title='Встроенное видео Youtube'
/>
</div>
);
}
export default EmbedYoutube;

View File

@ -3,7 +3,7 @@ import { type FallbackProps } from 'react-error-boundary';
import Button from './Common/Button'; import Button from './Common/Button';
function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) { function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
console.log(error); reportError(error);
return ( return (
<div className='flex flex-col items-center antialiased clr-app' role='alert'> <div className='flex flex-col items-center antialiased clr-app' role='alert'>
<h1 className='text-lg font-semibold'>Something went wrong!</h1> <h1 className='text-lg font-semibold'>Something went wrong!</h1>

View File

@ -1,16 +1,40 @@
import { urls } from '../../utils/constants'; import { useMemo } from 'react';
import useWindowSize from '../../hooks/useWindowSize';
import { urls, youtube } from '../../utils/constants';
import EmbedYoutube from '../Common/EmbedYoutube';
const OPT_VIDEO_H = 1080
function HelpRSLang() { function HelpRSLang() {
const windowSize = useWindowSize();
const videoHeight = useMemo(
() => {
const viewH = windowSize.height ?? 0;
const viewW = windowSize.width ?? 0;
return Math.min(OPT_VIDEO_H, viewH - 370, Math.floor((viewW - 250)*9/16));
}, [windowSize]);
return ( return (
<div> <div className='flex flex-col w-full gap-4'>
<h1>Язык родов структур</h1> <div>
<p>Формальная запись (<u>экспликация</u>) концептуальных схем осуществляется с помощью языка родов структур. Данный математический аппарат основан на аксиоматической теории множеств Цермелло-Френкеля и аппарате родов структур Н.Бурбаки.</p> <h1>Язык родов структур</h1>
<p>Для ознакомления с основами родов структур можно использовать следующие материалы:</p> <p>Формальная запись (<u>экспликация</u>) концептуальных схем осуществляется с помощью языка родов структур.</p>
<ul> <p>Данный математический аппарат основан на аксиоматической теории множеств Цермелло-Френкеля и аппарате родов структур Н.Бурбаки.</p>
<li>1. <a className='underline' href={urls.intro_video}>Краткое введение в мат. аппарат</a></li> <p>Для ознакомления с основами родов структур можно использовать следующие материалы:</p>
<li>2. <a className='underline' href={urls.full_course}>Видео лекций по мат. аппарату для 4 курса (второй семестр 2022-23 год)</a></li> <ul>
<li>3. <a className='underline' href={urls.ponomarev}>Учебник И. Н. Пономарева</a></li> <li>1. <a className='underline' href={urls.intro_video}>Краткое введение в мат. аппарат</a></li>
</ul> <li>2. <a className='underline' href={urls.full_course}>Видео лекций по мат. аппарату для 4 курса (второй семестр 2022-23 год)</a></li>
<li>3. <a className='underline' href={urls.ponomarev}>Учебник И. Н. Пономарева</a></li>
</ul>
</div>
<div className='justify-center hidden w-full md:flex fleex-col'>
<EmbedYoutube
videoID={youtube.intro}
pxHeight={videoHeight}
/>
</div>
</div> </div>
); );
} }

View File

@ -21,5 +21,11 @@ const darkTheme = EditorView.baseTheme(bracketsDarkT);
const lightTheme = EditorView.baseTheme(bracketsLightT); const lightTheme = EditorView.baseTheme(bracketsLightT);
export function ccBracketMatching(darkMode: boolean) { export function ccBracketMatching(darkMode: boolean) {
return [bracketMatching({ renderMatch: bracketRender }), darkMode ? darkTheme : lightTheme]; return [
bracketMatching({
renderMatch: bracketRender,
brackets:'{}[]()'
}),
darkMode ? darkTheme : lightTheme
];
} }

View File

@ -51,15 +51,19 @@ export class TextWrapper {
} }
envelopeWith(left: string, right: string) { envelopeWith(left: string, right: string) {
const hasSelection = this.ref.view.state.selection.main.from !== this.ref.view.state.selection.main.to
const newSelection = hasSelection ? {
anchor: this.ref.view.state.selection.main.from,
head: this.ref.view.state.selection.main.to + left.length + right.length
} : {
anchor: this.ref.view.state.selection.main.to + left.length + right.length - 1,
}
this.ref.view.dispatch({ this.ref.view.dispatch({
changes: [ changes: [
{from: this.ref.view.state.selection.main.from, insert: left}, {from: this.ref.view.state.selection.main.from, insert: left},
{from: this.ref.view.state.selection.main.to, insert: right} {from: this.ref.view.state.selection.main.to, insert: right}
], ],
selection: { selection: newSelection
anchor: this.ref.view.state.selection.main.from,
head: this.ref.view.state.selection.main.to + left.length + right.length
}
}); });
} }
@ -89,11 +93,6 @@ export class TextWrapper {
} else { } else {
this.envelopeWith('I{(σ, γ) | σ:∈X1; γ:=F1[σ]; P1[σ, γ]', '}'); this.envelopeWith('I{(σ, γ) | σ:∈X1; γ:=F1[σ]; P1[σ, γ]', '}');
} }
this.ref.view.dispatch({
selection: {
anchor: this.ref.view.state.selection.main.from + 2,
}
});
return true; return true;
} }
case TokenID.NT_RECURSIVE_FULL: { case TokenID.NT_RECURSIVE_FULL: {
@ -102,11 +101,6 @@ export class TextWrapper {
} else { } else {
this.envelopeWith('R{ξ:=D1 | F1[ξ]≠∅ | ξF1[ξ]', '}'); this.envelopeWith('R{ξ:=D1 | F1[ξ]≠∅ | ξF1[ξ]', '}');
} }
this.ref.view.dispatch({
selection: {
anchor: this.ref.view.state.selection.main.from + 2,
}
});
return true; return true;
} }
case TokenID.BIGPR: this.envelopeWith('Pr1(', ')'); return true; case TokenID.BIGPR: this.envelopeWith('Pr1(', ')'); return true;
@ -128,11 +122,13 @@ export class TextWrapper {
} }
case TokenID.PUNC_SL: { case TokenID.PUNC_SL: {
this.envelopeWith('[', ']'); this.envelopeWith('[', ']');
this.ref.view.dispatch({ if (hasSelection) {
selection: { this.ref.view.dispatch({
anchor: hasSelection ? this.ref.view.state.selection.main.to: this.ref.view.state.selection.main.from + 1, selection: {
} anchor: hasSelection ? this.ref.view.state.selection.main.to: this.ref.view.state.selection.main.from + 1,
}
}); });
}
return true; return true;
} }
case TokenID.BOOLEAN: { case TokenID.BOOLEAN: {

View File

@ -58,7 +58,7 @@ export const ThemeState = ({ children }: ThemeStateProps) => {
const mainHeight = useMemo( const mainHeight = useMemo(
() => { () => {
return !noNavigation ? return !noNavigation ?
'calc(100vh - 8.6rem)' 'calc(100vh - 8rem)'
: '100vh'; : '100vh';
}, [noNavigation]); }, [noNavigation]);

View File

@ -9,7 +9,6 @@ import { getCstExpressionPrefix } from '../utils/staticUI';
const LOGIC_TYPIIFCATION = 'LOGIC'; const LOGIC_TYPIIFCATION = 'LOGIC';
function checkTypeConsistency(type: CstType, typification: string, args: IFunctionArg[]): boolean { function checkTypeConsistency(type: CstType, typification: string, args: IFunctionArg[]): boolean {
console.log(typification)
switch (type) { switch (type) {
case CstType.BASE: case CstType.BASE:
case CstType.CONSTANT: case CstType.CONSTANT:

View File

@ -0,0 +1,14 @@
import { useState } from 'react';
import { unstable_usePrompt } from 'react-router-dom';
function usePromptUnsaved() {
const [isModified, setIsModified] = useState(false);
unstable_usePrompt({
when: isModified,
message: 'Изменения не сохранены. Вы уверены что хотите совершить переход?'
});
return {isModified, setIsModified};
}
export default usePromptUnsaved;

View File

@ -0,0 +1,31 @@
import { useEffect, useState } from 'react';
function useWindowSize() {
const isClient = typeof window === "object";
function getSize() {
return {
width: isClient ? window.innerWidth : undefined,
height: isClient ? window.innerHeight : undefined
};
}
const [windowSize, setWindowSize] = useState(getSize);
useEffect(
() => {
if (!isClient) {
return;
}
function handleResize() {
setWindowSize(getSize());
}
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return windowSize;
}
export default useWindowSize;

View File

@ -1,10 +1,9 @@
import './index.css' import './index.css'
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom/client' import { createRoot } from 'react-dom/client'
import { ErrorBoundary } from 'react-error-boundary'; import { ErrorBoundary } from 'react-error-boundary';
import { IntlProvider } from 'react-intl'; import { IntlProvider } from 'react-intl';
import { BrowserRouter } from 'react-router-dom';
import App from './App.tsx' import App from './App.tsx'
import ErrorFallback from './components/ErrorFallback.tsx'; import ErrorFallback from './components/ErrorFallback.tsx';
@ -25,9 +24,8 @@ const logError = (error: Error, info: { componentStack: string }) => {
console.log('Component stack: ' + info.componentStack) console.log('Component stack: ' + info.componentStack)
}; };
ReactDOM.createRoot(document.getElementById('root')!).render( createRoot(document.getElementById('root')!).render(
<React.StrictMode> <React.StrictMode>
<BrowserRouter>
<ErrorBoundary <ErrorBoundary
FallbackComponent={ErrorFallback} FallbackComponent={ErrorFallback}
onReset={resetState} onReset={resetState}
@ -47,6 +45,5 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
</ThemeState> </ThemeState>
</IntlProvider> </IntlProvider>
</ErrorBoundary> </ErrorBoundary>
</BrowserRouter>
</React.StrictMode>, </React.StrictMode>,
) )

View File

@ -21,7 +21,7 @@ function HomePage() {
}, [navigate, user]) }, [navigate, user])
return ( return (
<div className='flex flex-col items-center justify-center w-full py-2'> <div className='flex flex-col items-center justify-center w-full px-4 py-2'>
<p>Лендинг находится в разработке. Данная страница видна только пользователям с правами администратора.</p> <p>Лендинг находится в разработке. Данная страница видна только пользователям с правами администратора.</p>
</div> </div>
); );

View File

@ -1,8 +1,11 @@
import TextURL from '../components/Common/TextURL';
export function NotFoundPage() { export function NotFoundPage() {
return ( return (
<div> <div className='flex flex-col px-4 py-2'>
<h1 className='text-xl font-semibold'>Error 404 - Not Found</h1> <h1 className='text-xl font-semibold'>Ошибка 404 - Страница не найдена</h1>
<p className='mt-2'>Данная страница не существует или запрашиваемый объект отсутствует в базы данных</p> <p className='mt-2'>Данная страница не существует или запрашиваемый объект отсутствует в базе данных</p>
<TextURL href='/' text='Вернуться на Портал' />
</div> </div>
); );
} }

View File

@ -9,6 +9,7 @@ import TextArea from '../../components/Common/TextArea';
import HelpConstituenta from '../../components/Help/HelpConstituenta'; import HelpConstituenta from '../../components/Help/HelpConstituenta';
import { DumpBinIcon, HelpIcon, PenIcon, SaveIcon, SmallPlusIcon } from '../../components/Icons'; import { DumpBinIcon, HelpIcon, PenIcon, SaveIcon, SmallPlusIcon } from '../../components/Icons';
import { useRSForm } from '../../context/RSFormContext'; import { useRSForm } from '../../context/RSFormContext';
import useModificationPrompt from '../../hooks/useModificationPrompt';
import { CstType, EditMode, ICstCreateData, ICstRenameData, ICstUpdateData, SyntaxTree } from '../../utils/models'; import { CstType, EditMode, ICstCreateData, ICstRenameData, ICstUpdateData, SyntaxTree } from '../../utils/models';
import { getCstTypificationLabel } from '../../utils/staticUI'; import { getCstTypificationLabel } from '../../utils/staticUI';
import EditorRSExpression from './EditorRSExpression'; import EditorRSExpression from './EditorRSExpression';
@ -33,7 +34,8 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onO
return schema?.items?.find((cst) => cst.id === activeID); return schema?.items?.find((cst) => cst.id === activeID);
}, [schema?.items, activeID]); }, [schema?.items, activeID]);
const [isModified, setIsModified] = useState(false); const { isModified, setIsModified } = useModificationPrompt();
const [editMode, setEditMode] = useState(EditMode.TEXT); const [editMode, setEditMode] = useState(EditMode.TEXT);
const [alias, setAlias] = useState(''); const [alias, setAlias] = useState('');
@ -59,7 +61,7 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onO
); );
}, [activeCst, activeCst?.term, activeCst?.definition.formal, }, [activeCst, activeCst?.term, activeCst?.definition.formal,
activeCst?.definition.text.raw, activeCst?.convention, activeCst?.definition.text.raw, activeCst?.convention,
term, textDefinition, expression, convention]); term, textDefinition, expression, convention, setIsModified]);
useLayoutEffect( useLayoutEffect(
() => { () => {
@ -70,8 +72,6 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onO
setTextDefinition(activeCst.definition?.text?.raw ?? ''); setTextDefinition(activeCst.definition?.text?.raw ?? '');
setExpression(activeCst.definition?.formal ?? ''); setExpression(activeCst.definition?.formal ?? '');
setTypification(activeCst ? getCstTypificationLabel(activeCst) : 'N/A'); setTypification(activeCst ? getCstTypificationLabel(activeCst) : 'N/A');
} else if (schema && schema?.items.length > 0) {
onOpenEdit(schema.items[0].id);
} }
}, [activeCst, onOpenEdit, schema]); }, [activeCst, onOpenEdit, schema]);

View File

@ -13,6 +13,7 @@ import { CrownIcon, DownloadIcon, DumpBinIcon, HelpIcon, SaveIcon, ShareIcon } f
import { useAuth } from '../../context/AuthContext'; import { useAuth } from '../../context/AuthContext';
import { useRSForm } from '../../context/RSFormContext'; import { useRSForm } from '../../context/RSFormContext';
import { useUsers } from '../../context/UsersContext'; import { useUsers } from '../../context/UsersContext';
import useModificationPrompt from '../../hooks/useModificationPrompt';
import { IRSFormCreateData, LibraryItemType } from '../../utils/models'; import { IRSFormCreateData, LibraryItemType } from '../../utils/models';
interface EditorRSFormProps { interface EditorRSFormProps {
@ -37,7 +38,7 @@ function EditorRSForm({ onDestroy, onClaim, onShare, onDownload }: EditorRSFormP
const [common, setCommon] = useState(false); const [common, setCommon] = useState(false);
const [canonical, setCanonical] = useState(false); const [canonical, setCanonical] = useState(false);
const [isModified, setIsModified] = useState(true); const { isModified, setIsModified } = useModificationPrompt();
useLayoutEffect(() => { useLayoutEffect(() => {
if (!schema) { if (!schema) {
@ -53,7 +54,7 @@ function EditorRSForm({ onDestroy, onClaim, onShare, onDownload }: EditorRSFormP
); );
}, [schema, schema?.title, schema?.alias, schema?.comment, }, [schema, schema?.title, schema?.alias, schema?.comment,
schema?.is_common, schema?.is_canonical, schema?.is_common, schema?.is_canonical,
title, alias, comment, common, canonical]); title, alias, comment, common, canonical, setIsModified]);
useLayoutEffect(() => { useLayoutEffect(() => {
if (schema) { if (schema) {

View File

@ -163,6 +163,12 @@ function RSTabs() {
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)) {
++activeIndex; ++activeIndex;
} }
if (activeIndex >= schema.items.length) {
activeIndex = schema.items.length - 1;
while (activeIndex >= 0 && deleted.find(id => id === schema.items[activeIndex].id)) {
--activeIndex;
}
}
navigateTo(activeTab, schema.items[activeIndex].id); navigateTo(activeTab, schema.items[activeIndex].id);
} }
if (afterDelete) afterDelete(deleted); if (afterDelete) afterDelete(deleted);

View File

@ -4,6 +4,7 @@ import { toast } from 'react-toastify';
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 { useUserProfile } from '../../context/UserProfileContext'; import { useUserProfile } from '../../context/UserProfileContext';
import useModificationPrompt from '../../hooks/useModificationPrompt';
import { IUserUpdateData } from '../../utils/models'; import { IUserUpdateData } from '../../utils/models';
function EditorProfile() { function EditorProfile() {
@ -14,7 +15,7 @@ function EditorProfile() {
const [first_name, setFirstName] = useState(''); const [first_name, setFirstName] = useState('');
const [last_name, setLastName] = useState(''); const [last_name, setLastName] = useState('');
const [isModified, setIsModified] = useState(true); const { isModified, setIsModified } = useModificationPrompt();
useLayoutEffect(() => { useLayoutEffect(() => {
if (!user) { if (!user) {
@ -26,7 +27,7 @@ function EditorProfile() {
user.first_name !== first_name || user.first_name !== first_name ||
user.last_name !== last_name user.last_name !== last_name
); );
}, [user, user?.email, user?.first_name, user?.last_name, email, first_name, last_name]); }, [user, user?.email, user?.first_name, user?.last_name, email, first_name, last_name, setIsModified]);
useLayoutEffect(() => { useLayoutEffect(() => {
if (user) { if (user) {

View File

@ -117,7 +117,7 @@ export function getActiveUsers(request: FrontPull<IUserInfo[]>) {
export function getLibrary(request: FrontPull<ILibraryItem[]>) { export function getLibrary(request: FrontPull<ILibraryItem[]>) {
AxiosGet({ AxiosGet({
title: 'Available RSForms (Library) list', title: 'Available LibraryItems list',
endpoint: '/api/library/active', endpoint: '/api/library/active',
request: request request: request
}); });
@ -138,7 +138,7 @@ export function postNewRSForm(request: FrontExchange<IRSFormCreateData, ILibrary
export function postCloneLibraryItem(target: string, request: FrontExchange<IRSFormCreateData, IRSFormData>) { export function postCloneLibraryItem(target: string, request: FrontExchange<IRSFormCreateData, IRSFormData>) {
AxiosPost({ AxiosPost({
title: 'clone RSForm', title: 'Clone RSForm',
endpoint: `/api/library/${target}/clone`, endpoint: `/api/library/${target}/clone`,
request: request request: request
}); });
@ -154,7 +154,7 @@ export function getRSFormDetails(target: string, request: FrontPull<IRSFormData>
export function patchLibraryItem(target: string, request: FrontExchange<ILibraryUpdateData, ILibraryItem>) { export function patchLibraryItem(target: string, request: FrontExchange<ILibraryUpdateData, ILibraryItem>) {
AxiosPatch({ AxiosPatch({
title: `RSForm id=${target}`, title: `LibraryItem id=${target}`,
endpoint: `/api/library/${target}`, endpoint: `/api/library/${target}`,
request: request request: request
}); });
@ -162,7 +162,7 @@ export function patchLibraryItem(target: string, request: FrontExchange<ILibrary
export function deleteLibraryItem(target: string, request: FrontAction) { export function deleteLibraryItem(target: string, request: FrontAction) {
AxiosDelete({ AxiosDelete({
title: `RSForm id=${target}`, title: `LibraryItem id=${target}`,
endpoint: `/api/library/${target}`, endpoint: `/api/library/${target}`,
request: request request: request
}); });
@ -170,7 +170,7 @@ export function deleteLibraryItem(target: string, request: FrontAction) {
export function postClaimLibraryItem(target: string, request: FrontPull<ILibraryItem>) { export function postClaimLibraryItem(target: string, request: FrontPull<ILibraryItem>) {
AxiosPost({ AxiosPost({
title: `Claim on RSForm id=${target}`, title: `Claim on LibrartyItem id=${target}`,
endpoint: `/api/library/${target}/claim`, endpoint: `/api/library/${target}/claim`,
request: request request: request
}); });
@ -178,7 +178,7 @@ export function postClaimLibraryItem(target: string, request: FrontPull<ILibrary
export function postSubscribe(target: string, request: FrontAction) { export function postSubscribe(target: string, request: FrontAction) {
AxiosPost({ AxiosPost({
title: `Claim on RSForm id=${target}`, title: `Subscribe to LibrartyItem id=${target}`,
endpoint: `/api/library/${target}/subscribe`, endpoint: `/api/library/${target}/subscribe`,
request: request request: request
}); });
@ -186,7 +186,7 @@ export function postSubscribe(target: string, request: FrontAction) {
export function deleteUnsubscribe(target: string, request: FrontAction) { export function deleteUnsubscribe(target: string, request: FrontAction) {
AxiosDelete({ AxiosDelete({
title: `Claim on RSForm id=${target}`, title: `Unsubscribe from LibraryItem id=${target}`,
endpoint: `/api/library/${target}/unsubscribe`, endpoint: `/api/library/${target}/unsubscribe`,
request: request request: request
}); });

View File

@ -13,6 +13,10 @@ const dev = {
export const config = process.env.NODE_ENV === 'production' ? prod : dev; export const config = process.env.NODE_ENV === 'production' ? prod : dev;
export const TIMEOUT_UI_REFRESH = 100; export const TIMEOUT_UI_REFRESH = 100;
export const youtube = {
intro: '0Ty9mu9sOJo'
};
export const urls = { export const 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',