Portal/rsconcept/frontend/src/pages/OssPage/OssTabs.tsx

171 lines
5.2 KiB
TypeScript
Raw Normal View History

2024-06-07 20:17:03 +03:00
'use client';
import axios from 'axios';
import clsx from 'clsx';
import { useEffect, useState } from 'react';
2024-06-07 20:17:03 +03:00
import { TabList, TabPanel, Tabs } from 'react-tabs';
import { toast } from 'react-toastify';
2025-01-23 19:41:31 +03:00
import { useBlockNavigation, useConceptNavigation } from '@/app/Navigation/NavigationContext';
2024-06-07 20:17:03 +03:00
import { urls } from '@/app/urls';
2025-01-21 20:33:05 +03:00
import { useAuth } from '@/backend/auth/useAuth';
2025-01-23 19:41:31 +03:00
import { useDeleteItem } from '@/backend/library/useDeleteItem';
2024-06-07 20:17:03 +03:00
import InfoError, { ErrorData } from '@/components/info/InfoError';
import Loader from '@/components/ui/Loader';
import Overlay from '@/components/ui/Overlay';
2024-06-07 20:17:03 +03:00
import TabLabel from '@/components/ui/TabLabel';
import TextURL from '@/components/ui/TextURL';
import useQueryStrings from '@/hooks/useQueryStrings';
2024-07-23 23:03:58 +03:00
import { OperationID } from '@/models/oss';
import { useAppLayoutStore } from '@/stores/appLayout';
2024-06-07 20:17:03 +03:00
import { information, prompts } from '@/utils/labels';
import EditorRSForm from './EditorOssCard';
import EditorTermGraph from './EditorOssGraph';
import MenuOssTabs from './MenuOssTabs';
2024-06-07 20:17:03 +03:00
import { OssEditState } from './OssEditContext';
export enum OssTabID {
CARD = 0,
GRAPH = 1
}
function OssTabs() {
const router = useConceptNavigation();
const query = useQueryStrings();
2024-07-28 11:38:14 +03:00
const activeTab = query.get('tab') ? (Number(query.get('tab')) as OssTabID) : OssTabID.GRAPH;
2024-08-24 19:40:54 +03:00
const { user } = useAuth();
2025-01-23 19:41:31 +03:00
const { deleteItem } = useDeleteItem();
2024-06-07 20:17:03 +03:00
const hideFooter = useAppLayoutStore(state => state.hideFooter);
2025-01-23 19:41:31 +03:00
const { schema, loading, loadingError: errorLoading } = useOSSControl();
2024-06-07 20:17:03 +03:00
const [isModified, setIsModified] = useState(false);
2024-07-23 23:03:58 +03:00
const [selected, setSelected] = useState<OperationID[]>([]);
2024-08-24 19:40:54 +03:00
useBlockNavigation(
isModified &&
schema !== undefined &&
2025-01-21 20:33:05 +03:00
!!user &&
2024-08-24 19:40:54 +03:00
(user.is_staff || user.id == schema.owner || schema.editors.includes(user.id))
);
2024-06-07 20:17:03 +03:00
useEffect(() => {
2024-06-07 20:17:03 +03:00
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);
}
2024-06-07 20:17:03 +03:00
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() {
2024-08-23 19:09:18 +03:00
if (!schema || !window.confirm(prompts.deleteOSS)) {
2024-06-07 20:17:03 +03:00
return;
}
2025-01-23 19:41:31 +03:00
deleteItem(schema.id, () => {
2024-06-07 20:17:03 +03:00
toast.success(information.itemDestroyed);
router.push(urls.library);
});
}
2024-06-07 20:17:03 +03:00
return (
2024-07-23 23:03:58 +03:00
<OssEditState selected={selected} setSelected={setSelected}>
2024-06-07 20:17:03 +03:00
{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'>
2024-12-18 14:54:45 +03:00
<TabList className={clsx('w-fit', 'flex items-stretch', 'border-b-2 border-x-2 divide-x-2', 'bg-prim-200')}>
<MenuOssTabs onDestroy={onDestroySchema} />
2024-06-07 20:17:03 +03:00
<TabLabel label='Карточка' title={schema.title ?? ''} />
<TabLabel label='Граф' />
</TabList>
</Overlay>
2024-06-07 20:17:03 +03:00
2024-12-12 13:17:24 +03:00
<div className='overflow-x-hidden'>
<TabPanel>
<EditorRSForm
2025-01-23 19:41:31 +03:00
isModified={isModified} //
setIsModified={setIsModified}
onDestroy={onDestroySchema}
/>
</TabPanel>
<TabPanel>
<EditorTermGraph isModified={isModified} setIsModified={setIsModified} />
</TabPanel>
2024-12-12 13:17:24 +03:00
</div>
2024-06-07 20:17:03 +03:00
</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} />;
}