mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-02 05:26:45 +00:00
Add scan to action menu (#8781)
* small style fixes * refactor: split scanning and dialog logic * feat: Add modal and quick action to scan a barcode from anywhere
This commit is contained in:
parent
3e73162368
commit
c582ca0afd
@ -1,7 +1,7 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { Box, Divider, Modal } from '@mantine/core';
|
import { Box, Divider, Modal } from '@mantine/core';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { type NavigateFunction, useNavigate } from 'react-router-dom';
|
||||||
import { api } from '../../App';
|
import { api } from '../../App';
|
||||||
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||||
import type { ModelType } from '../../enums/ModelType';
|
import type { ModelType } from '../../enums/ModelType';
|
||||||
@ -17,17 +17,34 @@ export default function BarcodeScanDialog({
|
|||||||
title,
|
title,
|
||||||
opened,
|
opened,
|
||||||
onClose
|
onClose
|
||||||
}: {
|
}: Readonly<{
|
||||||
title?: string;
|
title?: string;
|
||||||
opened: boolean;
|
opened: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}) {
|
}>) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const user = useUserState();
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
size='lg'
|
||||||
|
opened={opened}
|
||||||
|
onClose={onClose}
|
||||||
|
title={<StylishText size='xl'>{title ?? t`Scan Barcode`}</StylishText>}
|
||||||
|
>
|
||||||
|
<Divider />
|
||||||
|
<Box>
|
||||||
|
<ScanInputHandler navigate={navigate} onClose={onClose} />
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export function ScanInputHandler({
|
||||||
|
onClose,
|
||||||
|
navigate
|
||||||
|
}: Readonly<{ onClose: () => void; navigate: NavigateFunction }>) {
|
||||||
const [error, setError] = useState<string>('');
|
const [error, setError] = useState<string>('');
|
||||||
|
|
||||||
const [processing, setProcessing] = useState<boolean>(false);
|
const [processing, setProcessing] = useState<boolean>(false);
|
||||||
|
const user = useUserState();
|
||||||
|
|
||||||
const onScan = useCallback((barcode: string) => {
|
const onScan = useCallback((barcode: string) => {
|
||||||
if (!barcode || barcode.length === 0) {
|
if (!barcode || barcode.length === 0) {
|
||||||
@ -80,19 +97,5 @@ export default function BarcodeScanDialog({
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return <BarcodeInput onScan={onScan} error={error} processing={processing} />;
|
||||||
<>
|
|
||||||
<Modal
|
|
||||||
size='lg'
|
|
||||||
opened={opened}
|
|
||||||
onClose={onClose}
|
|
||||||
title={<StylishText size='xl'>{title ?? t`Scan Barcode`}</StylishText>}
|
|
||||||
>
|
|
||||||
<Divider />
|
|
||||||
<Box>
|
|
||||||
<BarcodeInput onScan={onScan} error={error} processing={processing} />
|
|
||||||
</Box>
|
|
||||||
</Modal>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
21
src/frontend/src/components/modals/QrModal.tsx
Normal file
21
src/frontend/src/components/modals/QrModal.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import {} from '@mantine/core';
|
||||||
|
import type { ContextModalProps } from '@mantine/modals';
|
||||||
|
import type { NavigateFunction } from 'react-router-dom';
|
||||||
|
import { ScanInputHandler } from '../barcodes/BarcodeScanDialog';
|
||||||
|
|
||||||
|
export function QrModal({
|
||||||
|
context,
|
||||||
|
id,
|
||||||
|
innerProps
|
||||||
|
}: Readonly<
|
||||||
|
ContextModalProps<{ modalBody: string; navigate: NavigateFunction }>
|
||||||
|
>) {
|
||||||
|
function close() {
|
||||||
|
context.closeModal(id);
|
||||||
|
}
|
||||||
|
function navigate() {
|
||||||
|
context.closeModal(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <ScanInputHandler navigate={innerProps.navigate} onClose={close} />;
|
||||||
|
}
|
@ -6,6 +6,7 @@ import { ContextMenuProvider } from 'mantine-contextmenu';
|
|||||||
|
|
||||||
import { AboutInvenTreeModal } from '../components/modals/AboutInvenTreeModal';
|
import { AboutInvenTreeModal } from '../components/modals/AboutInvenTreeModal';
|
||||||
import { LicenseModal } from '../components/modals/LicenseModal';
|
import { LicenseModal } from '../components/modals/LicenseModal';
|
||||||
|
import { QrModal } from '../components/modals/QrModal';
|
||||||
import { ServerInfoModal } from '../components/modals/ServerInfoModal';
|
import { ServerInfoModal } from '../components/modals/ServerInfoModal';
|
||||||
import { useLocalState } from '../states/LocalState';
|
import { useLocalState } from '../states/LocalState';
|
||||||
import { LanguageContext } from './LanguageContext';
|
import { LanguageContext } from './LanguageContext';
|
||||||
@ -47,7 +48,8 @@ export function ThemeContext({
|
|||||||
modals={{
|
modals={{
|
||||||
info: ServerInfoModal,
|
info: ServerInfoModal,
|
||||||
about: AboutInvenTreeModal,
|
about: AboutInvenTreeModal,
|
||||||
license: LicenseModal
|
license: LicenseModal,
|
||||||
|
qr: QrModal
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Notifications />
|
<Notifications />
|
||||||
|
@ -1,12 +1,20 @@
|
|||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import type { SpotlightActionData } from '@mantine/spotlight';
|
import type { SpotlightActionData } from '@mantine/spotlight';
|
||||||
import { IconLink, IconPointer } from '@tabler/icons-react';
|
import { IconBarcode, IconLink, IconPointer } from '@tabler/icons-react';
|
||||||
import type { NavigateFunction } from 'react-router-dom';
|
import type { NavigateFunction } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { openContextModal } from '@mantine/modals';
|
||||||
import { useLocalState } from '../states/LocalState';
|
import { useLocalState } from '../states/LocalState';
|
||||||
import { useUserState } from '../states/UserState';
|
import { useUserState } from '../states/UserState';
|
||||||
import { aboutInvenTree, docLinks, licenseInfo, serverInfo } from './links';
|
import { aboutInvenTree, docLinks, licenseInfo, serverInfo } from './links';
|
||||||
|
|
||||||
|
export function openQrModal(navigate: NavigateFunction) {
|
||||||
|
return openContextModal({
|
||||||
|
modal: 'qr',
|
||||||
|
innerProps: { navigate: navigate }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function getActions(navigate: NavigateFunction) {
|
export function getActions(navigate: NavigateFunction) {
|
||||||
const setNavigationOpen = useLocalState((state) => state.setNavigationOpen);
|
const setNavigationOpen = useLocalState((state) => state.setNavigationOpen);
|
||||||
const { user } = useUserState();
|
const { user } = useUserState();
|
||||||
@ -55,6 +63,13 @@ export function getActions(navigate: NavigateFunction) {
|
|||||||
description: t`Open the main navigation menu`,
|
description: t`Open the main navigation menu`,
|
||||||
onClick: () => setNavigationOpen(true),
|
onClick: () => setNavigationOpen(true),
|
||||||
leftSection: <IconPointer size='1.2rem' />
|
leftSection: <IconPointer size='1.2rem' />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'scan',
|
||||||
|
label: t`Scan`,
|
||||||
|
description: t`Scan a barcode or QR code`,
|
||||||
|
onClick: () => openQrModal(navigate),
|
||||||
|
leftSection: <IconBarcode size='1.2rem' />
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user