ConceptPortal-public/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx

142 lines
4.6 KiB
TypeScript
Raw Normal View History

2023-07-29 03:31:21 +03:00
import { useCallback, useEffect, useLayoutEffect, useState } from 'react';
2023-07-25 20:27:29 +03:00
import { TabList, TabPanel, Tabs } from 'react-tabs';
import BackendError from '../../components/BackendError';
2023-07-15 17:46:19 +03:00
import ConceptTab from '../../components/Common/ConceptTab';
import { Loader } from '../../components/Common/Loader';
2023-07-25 20:27:29 +03:00
import { useRSForm } from '../../context/RSFormContext';
import useLocalStorage from '../../hooks/useLocalStorage';
2023-07-29 03:31:21 +03:00
import { type IConstituenta,SyntaxTree } from '../../utils/models';
2023-07-28 18:23:37 +03:00
import DlgCloneRSForm from './DlgCloneRSForm';
2023-07-29 03:31:21 +03:00
import DlgShowAST from './DlgShowAST';
2023-07-28 18:23:37 +03:00
import DlgUploadRSForm from './DlgUploadRSForm';
2023-07-28 00:03:37 +03:00
import EditorConstituenta from './EditorConstituenta';
import EditorItems from './EditorItems';
import EditorRSForm from './EditorRSForm';
import RSFormStats from './elements/RSFormStats';
2023-07-27 22:04:25 +03:00
import RSTabsMenu from './RSTabsMenu';
2023-07-15 17:46:19 +03:00
2023-07-27 22:04:25 +03:00
export enum RSTabsList {
2023-07-15 17:46:19 +03:00
CARD = 0,
CST_LIST = 1,
CST_EDIT = 2
}
2023-07-27 22:04:25 +03:00
function RSTabs() {
2023-07-25 20:27:29 +03:00
const { setActiveID, activeID, error, schema, loading } = useRSForm();
2023-07-27 22:04:25 +03:00
const [tabIndex, setTabIndex] = useLocalStorage('rsform_edit_tab', RSTabsList.CARD);
2023-07-21 00:09:05 +03:00
const [init, setInit] = useState(false);
2023-07-15 17:46:19 +03:00
2023-07-29 03:31:21 +03:00
const [showUpload, setShowUpload] = useState(false);
const [showClone, setShowClone] = useState(false);
const [syntaxTree, setSyntaxTree] = useState<SyntaxTree>([]);
const [showAST, setShowAST] = useState(false);
const onShowAST = useCallback(
(ast: SyntaxTree) => {
setSyntaxTree(ast);
setShowAST(true);
}, [])
2023-07-28 18:23:37 +03:00
2023-07-15 17:46:19 +03:00
const onEditCst = (cst: IConstituenta) => {
setActiveID(cst.id);
2023-07-27 22:04:25 +03:00
setTabIndex(RSTabsList.CST_EDIT)
2023-07-15 17:46:19 +03:00
};
const onSelectTab = (index: number) => {
setTabIndex(index);
};
useLayoutEffect(() => {
2023-07-21 00:09:05 +03:00
if (schema) {
const url = new URL(window.location.href);
const activeQuery = url.searchParams.get('active');
2023-07-28 01:37:26 +03:00
const activeCst = schema.items.find((cst) => cst.id === Number(activeQuery));
setActiveID(activeCst?.id);
2023-07-21 00:09:05 +03:00
setInit(true);
2023-07-28 01:37:26 +03:00
const oldTitle = document.title
document.title = schema.title
return () => {
document.title = oldTitle
}
2023-07-21 00:09:05 +03:00
}
2023-07-28 01:37:26 +03:00
}, [setActiveID, schema, schema?.title, setInit]);
2023-07-18 14:55:40 +03:00
useEffect(() => {
const url = new URL(window.location.href);
const tabQuery = url.searchParams.get('tab');
2023-07-27 22:04:25 +03:00
setTabIndex(Number(tabQuery) || RSTabsList.CARD);
2023-07-18 14:55:40 +03:00
}, [setTabIndex]);
useEffect(() => {
2023-07-21 00:09:05 +03:00
if (init) {
const url = new URL(window.location.href);
2023-07-25 20:27:29 +03:00
const currentActive = url.searchParams.get('active');
const currentTab = url.searchParams.get('tab');
2023-07-27 22:04:25 +03:00
const saveHistory = tabIndex === RSTabsList.CST_EDIT && currentActive !== String(activeID);
if (currentTab !== String(tabIndex)) {
url.searchParams.set('tab', String(tabIndex));
}
if (activeID) {
if (currentActive !== String(activeID)) {
url.searchParams.set('active', String(activeID));
}
2023-07-21 00:09:05 +03:00
} else {
url.searchParams.delete('active');
}
if (saveHistory) {
window.history.pushState(null, '', url.toString());
} else {
window.history.replaceState(null, '', url.toString());
}
}
}, [tabIndex, activeID, init]);
2023-07-15 17:46:19 +03:00
return (
2023-07-20 17:11:03 +03:00
<div className='w-full'>
2023-07-15 17:46:19 +03:00
{ loading && <Loader /> }
{ error && <BackendError error={error} />}
{ schema && !loading &&
2023-07-28 18:23:37 +03:00
<>
2023-07-29 03:31:21 +03:00
{showUpload && <DlgUploadRSForm hideWindow={() => { setShowUpload(false); }}/>}
{showClone && <DlgCloneRSForm hideWindow={() => { setShowClone(false); }}/>}
{showAST && <DlgShowAST syntaxTree={syntaxTree} hideWindow={() => { setShowAST(false); }}/>}
2023-07-25 20:27:29 +03:00
<Tabs
2023-07-20 17:11:03 +03:00
selectedIndex={tabIndex}
onSelect={onSelectTab}
defaultFocus={true}
selectedTabClassName='font-bold'
>
<TabList className='flex items-start w-fit clr-bg-pop'>
2023-07-28 18:23:37 +03:00
<RSTabsMenu
2023-07-29 03:31:21 +03:00
showCloneDialog={() => setShowClone(true)}
showUploadDialog={() => setShowUpload(true)}
2023-07-28 18:23:37 +03:00
/>
2023-07-20 17:11:03 +03:00
<ConceptTab>Паспорт схемы</ConceptTab>
<ConceptTab className='border-x-2 clr-border min-w-[10rem] flex justify-between gap-2'>
2023-07-20 17:11:03 +03:00
<span>Конституенты</span>
2023-07-25 20:27:29 +03:00
<span>{`${schema.stats?.count_errors ?? 0} | ${schema.stats?.count_all ?? 0}`}</span>
2023-07-20 17:11:03 +03:00
</ConceptTab>
<ConceptTab>Редактор</ConceptTab>
</TabList>
2023-07-15 17:46:19 +03:00
2023-07-20 17:11:03 +03:00
<TabPanel className='flex items-start w-full gap-2'>
2023-07-28 00:03:37 +03:00
<EditorRSForm />
2023-07-20 17:11:03 +03:00
{schema.stats && <RSFormStats stats={schema.stats}/>}
</TabPanel>
2023-07-15 17:46:19 +03:00
2023-07-20 17:11:03 +03:00
<TabPanel className='w-full'>
2023-07-28 00:03:37 +03:00
<EditorItems onOpenEdit={onEditCst} />
2023-07-20 17:11:03 +03:00
</TabPanel>
2023-07-15 17:46:19 +03:00
2023-07-20 17:11:03 +03:00
<TabPanel>
2023-07-29 03:31:21 +03:00
<EditorConstituenta onShowAST={onShowAST} />
2023-07-20 17:11:03 +03:00
</TabPanel>
2023-07-28 18:23:37 +03:00
</Tabs></>
2023-07-15 17:46:19 +03:00
}
</div>);
}
2023-07-27 22:04:25 +03:00
export default RSTabs;