Portal/rsconcept/frontend/src/pages/OssPage/OssTabs.tsx
IRBorisov 6c3461977d
Some checks are pending
Frontend CI / build (18.x) (push) Waiting to run
Refactoring: UI elements naming convention
2024-06-26 19:47:05 +03:00

175 lines
5.1 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 { useCallback, useLayoutEffect, useMemo, 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 TabLabel from '@/components/ui/TabLabel';
import TextURL from '@/components/ui/TextURL';
import AnimateFade from '@/components/wrap/AnimateFade';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { useLibrary } from '@/context/LibraryContext';
import { useBlockNavigation, useConceptNavigation } from '@/context/NavigationContext';
import { useOSS } from '@/context/OssContext';
import useQueryStrings from '@/hooks/useQueryStrings';
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 = (Number(query.get('tab')) ?? OssTabID.CARD) as OssTabID;
const { calculateHeight } = useConceptOptions();
const { schema, loading, errorLoading } = useOSS();
const { destroyItem } = useLibrary();
const [isModified, setIsModified] = useState(false);
useBlockNavigation(isModified);
useLayoutEffect(() => {
if (schema) {
const oldTitle = document.title;
document.title = schema.title;
return () => {
document.title = oldTitle;
};
}
}, [schema, schema?.title]);
const navigateTab = useCallback(
(tab: OssTabID) => {
if (!schema) {
return;
}
const url = urls.oss_props({
id: schema.id,
tab: tab
});
router.push(url);
},
[router, schema]
);
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);
}
const onDestroySchema = useCallback(() => {
if (!schema || !window.confirm(prompts.deleteLibraryItem)) {
return;
}
destroyItem(schema.id, () => {
toast.success(information.itemDestroyed);
router.push(urls.library);
});
}, [schema, destroyItem, router]);
const panelHeight = useMemo(() => calculateHeight('1.75rem + 4px'), [calculateHeight]);
const cardPanel = useMemo(
() => (
<TabPanel>
<EditorRSForm
isModified={isModified} // prettier: split lines
setIsModified={setIsModified}
onDestroy={onDestroySchema}
/>
</TabPanel>
),
[isModified, onDestroySchema]
);
const graphPanel = useMemo(
() => (
<TabPanel>
<EditorTermGraph />
</TabPanel>
),
[]
);
return (
<OssEditState>
{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'
>
<TabList className={clsx('mx-auto w-fit', 'flex items-stretch', 'border-b-2 border-x-2 divide-x-2')}>
<MenuOssTabs onDestroy={onDestroySchema} />
<TabLabel label='Карточка' titleHtml={`Название: <b>${schema.title ?? ''}</b>`} />
<TabLabel label='Граф' />
</TabList>
<AnimateFade className='overflow-y-auto' style={{ maxHeight: panelHeight }}>
{cardPanel}
{graphPanel}
</AnimateFade>
</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} />;
}