ConceptPortal-public/rsconcept/frontend/src/pages/OssPage/OssTabs.tsx
Ivan 4c9b0b28b8
Some checks are pending
Frontend CI / build (22.x) (push) Waiting to run
R: Migrating to zustand for local state management pt1
2025-01-14 21:58:16 +03:00

172 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'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 Loader from '@/components/ui/Loader';
import Overlay from '@/components/ui/Overlay';
import TabLabel from '@/components/ui/TabLabel';
import TextURL from '@/components/ui/TextURL';
import { useAuth } from '@/context/AuthContext';
import { useLibrary } from '@/context/LibraryContext';
import { useBlockNavigation, useConceptNavigation } from '@/context/NavigationContext';
import { useOSS } from '@/context/OssContext';
import useQueryStrings from '@/hooks/useQueryStrings';
import { OperationID } from '@/models/oss';
import { useAppLayoutStore } from '@/stores/appLayout';
import { information, prompts } from '@/utils/labels';
import EditorRSForm from './EditorOssCard';
import EditorTermGraph from './EditorOssGraph';
import MenuOssTabs from './MenuOssTabs';
import { OssEditState } from './OssEditContext';
export enum OssTabID {
CARD = 0,
GRAPH = 1
}
function OssTabs() {
const router = useConceptNavigation();
const query = useQueryStrings();
const activeTab = query.get('tab') ? (Number(query.get('tab')) as OssTabID) : OssTabID.GRAPH;
const { user } = useAuth();
const hideFooter = useAppLayoutStore(state => state.hideFooter);
const { schema, loading, loadingError: errorLoading } = useOSS();
const { destroyItem } = useLibrary();
const [isModified, setIsModified] = useState(false);
const [selected, setSelected] = useState<OperationID[]>([]);
useBlockNavigation(
isModified &&
schema !== undefined &&
user !== undefined &&
(user.is_staff || user.id == schema.owner || schema.editors.includes(user.id))
);
useEffect(() => {
if (schema) {
const oldTitle = document.title;
document.title = schema.title;
return () => {
document.title = oldTitle;
};
}
}, [schema, schema?.title]);
useEffect(() => {
hideFooter(activeTab === OssTabID.GRAPH);
}, [activeTab, hideFooter]);
function navigateTab(tab: OssTabID) {
if (!schema) {
return;
}
const url = urls.oss_props({
id: schema.id,
tab: tab
});
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);
}
function onDestroySchema() {
if (!schema || !window.confirm(prompts.deleteOSS)) {
return;
}
destroyItem(schema.id, () => {
toast.success(information.itemDestroyed);
router.push(urls.library);
});
}
return (
<OssEditState selected={selected} setSelected={setSelected}>
{loading ? <Loader /> : null}
{errorLoading ? <ProcessError error={errorLoading} /> : null}
{schema && !loading ? (
<Tabs
selectedIndex={activeTab}
onSelect={onSelectTab}
defaultFocus
selectedTabClassName='clr-selected'
className='flex flex-col mx-auto min-w-fit'
>
<Overlay position='top-0 right-1/2 translate-x-1/2' layer='z-sticky'>
<TabList className={clsx('w-fit', 'flex items-stretch', 'border-b-2 border-x-2 divide-x-2', 'bg-prim-200')}>
<MenuOssTabs onDestroy={onDestroySchema} />
<TabLabel label='Карточка' title={schema.title ?? ''} />
<TabLabel label='Граф' />
</TabList>
</Overlay>
<div className='overflow-x-hidden'>
<TabPanel>
<EditorRSForm
isModified={isModified} // prettier: split lines
setIsModified={setIsModified}
onDestroy={onDestroySchema}
/>
</TabPanel>
<TabPanel>
<EditorTermGraph isModified={isModified} setIsModified={setIsModified} />
</TabPanel>
</div>
</Tabs>
) : null}
</OssEditState>
);
}
export default OssTabs;
// ====== Internals =========
function ProcessError({ error }: { error: ErrorData }): React.ReactElement {
if (axios.isAxiosError(error) && error.response) {
if (error.response.status === 404) {
return (
<div className='flex flex-col items-center p-2 mx-auto'>
<p>{`Операционная схема с указанным идентификатором отсутствует`}</p>
<div className='flex justify-center'>
<TextURL text='Библиотека' href='/library' />
</div>
</div>
);
} else if (error.response.status === 403) {
return (
<div className='flex flex-col items-center p-2 mx-auto'>
<p>Владелец ограничил доступ к данной схеме</p>
<TextURL text='Библиотека' href='/library' />
</div>
);
}
}
return <InfoError error={error} />;
}