'use client'; import axios from 'axios'; import clsx from 'clsx'; import { useEffect, useState } from 'react'; import { TabList, TabPanel, Tabs } from 'react-tabs'; import { toast } from 'react-toastify'; import { urls } from '@/app/urls'; import InfoError, { ErrorData } from '@/components/info/InfoError'; import Divider from '@/components/ui/Divider'; import Loader from '@/components/ui/Loader'; import Overlay from '@/components/ui/Overlay'; import TabLabel from '@/components/ui/TabLabel'; import TextURL from '@/components/ui/TextURL'; import { useConceptOptions } from '@/context/ConceptOptionsContext'; import { useGlobalOss } from '@/context/GlobalOssContext'; import { useLibrary } from '@/context/LibraryContext'; import { useBlockNavigation, useConceptNavigation } from '@/context/NavigationContext'; import { useRSForm } from '@/context/RSFormContext'; import useQueryStrings from '@/hooks/useQueryStrings'; import { ConstituentaID, IConstituenta, IConstituentaMeta } from '@/models/rsform'; import { PARAMETER, prefixes } from '@/utils/constants'; import { information, labelVersion, prompts } from '@/utils/labels'; import { OssTabID } from '../OssPage/OssTabs'; import EditorConstituenta from './EditorConstituenta'; import EditorRSForm from './EditorRSFormCard'; import EditorRSList from './EditorRSList'; import EditorTermGraph from './EditorTermGraph'; import MenuRSTabs from './MenuRSTabs'; import { RSEditState } from './RSEditContext'; export enum RSTabID { CARD = 0, CST_LIST = 1, CST_EDIT = 2, TERM_GRAPH = 3 } function RSTabs() { const router = useConceptNavigation(); const query = useQueryStrings(); const activeTab = query.get('tab') ? (Number(query.get('tab')) as RSTabID) : RSTabID.CARD; const version = query.get('v') ? Number(query.get('v')) : undefined; const cstQuery = query.get('active'); const { setNoFooter } = useConceptOptions(); const { schema, loading, errorLoading, isArchive, itemID } = useRSForm(); const library = useLibrary(); const oss = useGlobalOss(); const [isModified, setIsModified] = useState(false); useBlockNavigation(isModified); const [selected, setSelected] = useState([]); const activeCst: IConstituenta | undefined = (() => { if (!schema || selected.length === 0) { return undefined; } else { return schema.cstByID.get(selected.at(-1)!); } })(); useEffect(() => { if (schema) { const oldTitle = document.title; document.title = schema.title; return () => { document.title = oldTitle; }; } }, [schema, schema?.title]); useEffect(() => { setNoFooter(activeTab !== RSTabID.CARD); setIsModified(false); if (activeTab === RSTabID.CST_EDIT) { const cstID = Number(cstQuery); if (cstID && schema?.cstByID.has(cstID)) { setSelected([cstID]); } else { setSelected([]); } } return () => setNoFooter(false); }, [activeTab, cstQuery, setSelected, schema, setNoFooter, setIsModified]); function navigateTab(tab: RSTabID, activeID?: ConstituentaID) { if (!schema) { return; } const url = urls.schema_props({ id: schema.id, tab: tab, active: activeID, version: version }); if (activeID) { if (tab === activeTab && tab !== RSTabID.CST_EDIT) { router.replace(url); } else { router.push(url); } } else if (tab !== activeTab && tab === RSTabID.CST_EDIT && schema.items.length > 0) { activeID = schema.items[0].id; router.replace(url); } else { router.push(url); } } function onSelectTab(index: number, last: number, event: Event) { if (last === index) { return; } if (event.type == 'keydown') { const kbEvent = event as KeyboardEvent; if (kbEvent.altKey) { if (kbEvent.code === 'ArrowLeft') { router.back(); return; } else if (kbEvent.code === 'ArrowRight') { router.forward(); return; } } } navigateTab(index, selected.length > 0 ? selected.at(-1) : undefined); } function onCreateCst(newCst: IConstituentaMeta) { navigateTab(activeTab, newCst.id); if (activeTab === RSTabID.CST_LIST) { setTimeout(() => { const element = document.getElementById(`${prefixes.cst_list}${newCst.alias}`); if (element) { element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'end' }); } }, PARAMETER.refreshTimeout); } } function onDeleteCst(newActive?: ConstituentaID) { if (!newActive) { navigateTab(RSTabID.CST_LIST); } else if (activeTab === RSTabID.CST_EDIT) { navigateTab(activeTab, newActive); } else { navigateTab(activeTab); } } function onOpenCst(cstID: ConstituentaID) { if (cstID !== activeCst?.id || activeTab !== RSTabID.CST_EDIT) { navigateTab(RSTabID.CST_EDIT, cstID); } } function onDestroySchema() { if (!schema || !window.confirm(prompts.deleteLibraryItem)) { return; } const backToOSS = oss.schema?.schemas.includes(schema.id); library.destroyItem(schema.id, () => { toast.success(information.itemDestroyed); if (backToOSS) { oss.invalidate(); router.push(urls.oss(oss.schema!.id, OssTabID.GRAPH)); } else { router.push(urls.library); } }); } return ( {loading ? : null} {errorLoading ? : null} {schema && !loading ? ( Версия: ${labelVersion(schema)}`} /> Ошибок: ${ schema.stats?.count_errors ?? 0 }`} />
) : null}
); } export default RSTabs; // ====== Internals ========= function ProcessError({ error, isArchive, itemID }: { error: ErrorData; isArchive: boolean; itemID: string; }): React.ReactElement { if (axios.isAxiosError(error) && error.response) { if (error.response.status === 404) { return (

{`Концептуальная схема с указанным идентификатором ${isArchive ? 'и версией ' : ''}отсутствует`}

{isArchive ? : null} {isArchive ? : null}
); } else if (error.response.status === 403) { return (

Владелец ограничил доступ к данной схеме

); } } return ; }