InvenTree/src/frontend/src/components/nav/DetailDrawer.tsx

119 lines
2.8 KiB
TypeScript

import {
ActionIcon,
Divider,
Drawer,
Group,
MantineNumberSize,
Stack,
Text,
createStyles
} from '@mantine/core';
import { IconChevronLeft } from '@tabler/icons-react';
import { useCallback, useMemo } from 'react';
import { Link, Route, Routes, useNavigate, useParams } from 'react-router-dom';
import type { To } from 'react-router-dom';
import { useLocalState } from '../../states/LocalState';
/**
* @param title - drawer title
* @param position - drawer position
* @param renderContent - function used to render the drawer content
* @param urlPrefix - set an additional url segment, useful when multiple drawers are rendered on one page (e.g. "user/")
*/
export interface DrawerProps {
title: string;
position?: 'right' | 'left';
renderContent: (id?: string) => React.ReactNode;
urlPrefix?: string;
size?: MantineNumberSize;
closeOnEscape?: boolean;
}
const useStyles = createStyles(() => ({
flex: {
display: 'flex',
flex: 1
}
}));
function DetailDrawerComponent({
title,
position = 'right',
size,
closeOnEscape = true,
renderContent
}: Readonly<DrawerProps>) {
const navigate = useNavigate();
const { id } = useParams();
const { classes } = useStyles();
const content = renderContent(id);
const opened = useMemo(() => !!id && !!content, [id, content]);
const [detailDrawerStack, addDetailDrawer] = useLocalState((state) => [
state.detailDrawerStack,
state.addDetailDrawer
]);
return (
<Drawer
opened={opened}
onClose={() => {
navigate('../');
addDetailDrawer(false);
}}
position={position}
closeOnEscape={closeOnEscape}
size={size}
classNames={{ root: classes.flex, body: classes.flex }}
scrollAreaComponent={Stack}
title={
<Group>
{detailDrawerStack > 0 && (
<ActionIcon
variant="outline"
onClick={() => {
navigate(-1);
addDetailDrawer(-1);
}}
>
<IconChevronLeft />
</ActionIcon>
)}
<Text size="xl" fw={600} variant="gradient">
{title}
</Text>
</Group>
}
>
<Stack spacing={'xs'} className={classes.flex}>
<Divider />
{content}
</Stack>
</Drawer>
);
}
export function DetailDrawer(props: Readonly<DrawerProps>) {
return (
<Routes>
<Route path=":id?/" element={<DetailDrawerComponent {...props} />} />
</Routes>
);
}
export function DetailDrawerLink({ to, text }: { to: To; text: string }) {
const addDetailDrawer = useLocalState((state) => state.addDetailDrawer);
const onNavigate = useCallback(() => {
addDetailDrawer(1);
}, [addDetailDrawer]);
return (
<Link to={to} onClick={onNavigate}>
<Text>{text}</Text>
</Link>
);
}