2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 03:26:45 +00:00
InvenTree/src/frontend/src/components/nav/DetailDrawer.tsx
Matthias Mair c41760a500
chore: bump zustand (#9577)
* bump zustand to v5

* add missing shallow

* fix missing shallow

---------

Co-authored-by: Oliver <oliver.henry.walters@gmail.com>
2025-04-25 09:39:08 +10:00

108 lines
2.8 KiB
TypeScript

import { ActionIcon, Divider, Drawer, Group, Stack, Text } 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 type { UiSizeType } from '@lib/types/Core';
import { useShallow } from 'zustand/react/shallow';
import { useLocalState } from '../../states/LocalState';
import { StylishText } from '../items/StylishText';
import * as classes from './DetailDrawer.css';
/**
* @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?: UiSizeType;
closeOnEscape?: boolean;
}
function DetailDrawerComponent({
title,
position = 'right',
size,
closeOnEscape = true,
renderContent
}: Readonly<DrawerProps>) {
const navigate = useNavigate();
const { id } = useParams();
const content = renderContent(id);
const opened = useMemo(() => !!id && !!content, [id, content]);
const [detailDrawerStack, addDetailDrawer] = useLocalState(
useShallow((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>
)}
<StylishText size='xl'>{title}</StylishText>
</Group>
}
>
<Stack gap={'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
}: Readonly<{ to: To; text: string }>) {
const addDetailDrawer = useLocalState(
useShallow((state) => state.addDetailDrawer)
);
const onNavigate = useCallback(() => {
addDetailDrawer(1);
}, [addDetailDrawer]);
return (
<Link to={to} onClick={onNavigate}>
<Text>{text}</Text>
</Link>
);
}