mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
[PUI] Add image based QR code assigment (#7960)
* Add Link/Unlink Barcode action Fixes #7920 * remove unneeded imports * remove duplication * simplify * add testing * refactor type * wait for reload to add coverage * Add warning if custom barcode is used * Add Image based assign * fix action button size * fix selection to prevent wrapping * use left section for button
This commit is contained in:
parent
594c15b3e3
commit
313cb4758e
@ -1,9 +1,12 @@
|
|||||||
import { Trans, t } from '@lingui/macro';
|
import { Trans, t } from '@lingui/macro';
|
||||||
import {
|
import {
|
||||||
|
ActionIcon,
|
||||||
Alert,
|
Alert,
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Code,
|
Code,
|
||||||
|
Divider,
|
||||||
|
Flex,
|
||||||
Group,
|
Group,
|
||||||
Image,
|
Image,
|
||||||
Select,
|
Select,
|
||||||
@ -12,13 +15,17 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
TextInput
|
TextInput
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
import { modals } from '@mantine/modals';
|
import { modals } from '@mantine/modals';
|
||||||
|
import { IconQrcode } from '@tabler/icons-react';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import QR from 'qrcode';
|
import QR from 'qrcode';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
import { set } from 'react-hook-form';
|
||||||
|
|
||||||
import { api } from '../../App';
|
import { api } from '../../App';
|
||||||
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||||
|
import { InputImageBarcode, ScanItem } from '../../pages/Index/Scan';
|
||||||
import { apiUrl } from '../../states/ApiState';
|
import { apiUrl } from '../../states/ApiState';
|
||||||
import { useGlobalSettingsState } from '../../states/SettingsState';
|
import { useGlobalSettingsState } from '../../states/SettingsState';
|
||||||
import { CopyButton } from '../buttons/CopyButton';
|
import { CopyButton } from '../buttons/CopyButton';
|
||||||
@ -142,27 +149,47 @@ export const InvenTreeQRCode = ({
|
|||||||
|
|
||||||
export const QRCodeLink = ({ mdl_prop }: { mdl_prop: QrCodeType }) => {
|
export const QRCodeLink = ({ mdl_prop }: { mdl_prop: QrCodeType }) => {
|
||||||
const [barcode, setBarcode] = useState('');
|
const [barcode, setBarcode] = useState('');
|
||||||
|
const [isScanning, toggleIsScanning] = useDisclosure(false);
|
||||||
|
|
||||||
function linkBarcode() {
|
function linkBarcode(value?: string) {
|
||||||
api
|
api
|
||||||
.post(apiUrl(ApiEndpoints.barcode_link), {
|
.post(apiUrl(ApiEndpoints.barcode_link), {
|
||||||
[mdl_prop.model]: mdl_prop.pk,
|
[mdl_prop.model]: mdl_prop.pk,
|
||||||
barcode: barcode
|
barcode: value || barcode
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
modals.closeAll();
|
modals.closeAll();
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const actionSubmit = (data: ScanItem[]) => {
|
||||||
|
linkBarcode(data[0].data);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
|
{isScanning ? (
|
||||||
|
<>
|
||||||
|
<InputImageBarcode action={actionSubmit} />
|
||||||
|
<Divider />
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
<TextInput
|
<TextInput
|
||||||
label={t`Barcode`}
|
label={t`Barcode`}
|
||||||
value={barcode}
|
value={barcode}
|
||||||
onChange={(event) => setBarcode(event.currentTarget.value)}
|
onChange={(event) => setBarcode(event.currentTarget.value)}
|
||||||
placeholder={t`Scan barcode data here using barcode scanner`}
|
placeholder={t`Scan barcode data here using barcode scanner`}
|
||||||
|
leftSection={
|
||||||
|
<ActionIcon
|
||||||
|
variant="subtle"
|
||||||
|
onClick={toggleIsScanning.toggle}
|
||||||
|
size="input-sm"
|
||||||
|
>
|
||||||
|
<IconQrcode />
|
||||||
|
</ActionIcon>
|
||||||
|
}
|
||||||
|
w="100%"
|
||||||
/>
|
/>
|
||||||
<Button color="green" onClick={linkBarcode} mt="lg" fullWidth>
|
<Button color="green" onClick={() => linkBarcode()} mt="lg" fullWidth>
|
||||||
<Trans>Link</Trans>
|
<Trans>Link</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -55,7 +55,7 @@ import { notYetImplemented } from '../../functions/notifications';
|
|||||||
import { IS_DEV_OR_DEMO } from '../../main';
|
import { IS_DEV_OR_DEMO } from '../../main';
|
||||||
import { apiUrl } from '../../states/ApiState';
|
import { apiUrl } from '../../states/ApiState';
|
||||||
|
|
||||||
interface ScanItem {
|
export interface ScanItem {
|
||||||
id: string;
|
id: string;
|
||||||
ref: string;
|
ref: string;
|
||||||
data: any;
|
data: any;
|
||||||
@ -545,7 +545,7 @@ function InputManual({ action }: Readonly<ScanInputInterface>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Input that uses QR code detection from images */
|
/* Input that uses QR code detection from images */
|
||||||
function InputImageBarcode({ action }: Readonly<ScanInputInterface>) {
|
export function InputImageBarcode({ action }: Readonly<ScanInputInterface>) {
|
||||||
const [qrCodeScanner, setQrCodeScanner] = useState<Html5Qrcode | null>(null);
|
const [qrCodeScanner, setQrCodeScanner] = useState<Html5Qrcode | null>(null);
|
||||||
const [camId, setCamId] = useLocalStorage<CameraDevice | null>({
|
const [camId, setCamId] = useLocalStorage<CameraDevice | null>({
|
||||||
key: 'camId',
|
key: 'camId',
|
||||||
@ -714,17 +714,19 @@ function InputImageBarcode({ action }: Readonly<ScanInputInterface>) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="xs">
|
<Stack gap="xs">
|
||||||
<Group gap="xs">
|
<Group gap="xs" preventGrowOverflow>
|
||||||
<Select
|
<Select
|
||||||
value={cameraValue}
|
value={cameraValue}
|
||||||
onChange={setCameraValue}
|
onChange={setCameraValue}
|
||||||
data={cameras.map((device) => {
|
data={cameras.map((device) => {
|
||||||
return { value: device.id, label: device.label };
|
return { value: device.id, label: device.label };
|
||||||
})}
|
})}
|
||||||
|
maw={200}
|
||||||
size="sm"
|
size="sm"
|
||||||
/>
|
/>
|
||||||
{scanningEnabled ? (
|
{scanningEnabled ? (
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
|
size="input-sm"
|
||||||
onClick={btnStopScanning}
|
onClick={btnStopScanning}
|
||||||
title={t`Stop scanning`}
|
title={t`Stop scanning`}
|
||||||
variant="default"
|
variant="default"
|
||||||
@ -733,6 +735,7 @@ function InputImageBarcode({ action }: Readonly<ScanInputInterface>) {
|
|||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
) : (
|
) : (
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
|
size="input-sm"
|
||||||
onClick={btnStartScanning}
|
onClick={btnStartScanning}
|
||||||
title={t`Start scanning`}
|
title={t`Start scanning`}
|
||||||
disabled={!camId}
|
disabled={!camId}
|
||||||
|
Loading…
Reference in New Issue
Block a user