added camera input for andriod conversion
This commit is contained in:
parent
6f7e2f6cdd
commit
f0cdce7150
|
|
@ -2,16 +2,9 @@ import { useState, useRef, useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
Upload,
|
Upload,
|
||||||
Button,
|
Button,
|
||||||
Spin,
|
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
Select,
|
|
||||||
message,
|
message,
|
||||||
Divider,
|
|
||||||
Row,
|
|
||||||
Col,
|
|
||||||
Table,
|
|
||||||
Image,
|
|
||||||
DatePicker,
|
DatePicker,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
@ -21,7 +14,6 @@ import {
|
||||||
CheckOutlined,
|
CheckOutlined,
|
||||||
CloseOutlined,
|
CloseOutlined,
|
||||||
ReloadOutlined,
|
ReloadOutlined,
|
||||||
EyeOutlined,
|
|
||||||
DeleteFilled,
|
DeleteFilled,
|
||||||
CameraOutlined,
|
CameraOutlined,
|
||||||
EditOutlined,
|
EditOutlined,
|
||||||
|
|
@ -37,218 +29,8 @@ import { InputField } from '../../Components/Forms/InputField.jsx';
|
||||||
import TextAreaInput from '../../Components/Forms/TextArea.jsx';
|
import TextAreaInput from '../../Components/Forms/TextArea.jsx';
|
||||||
import { uploadImage } from '../../Features/upload/upload.js';
|
import { uploadImage } from '../../Features/upload/upload.js';
|
||||||
import { getSession } from '../../Services/Others.js';
|
import { getSession } from '../../Services/Others.js';
|
||||||
|
import ResizableCropper from '../../Components/PedalOCR/CropperArea.jsx';
|
||||||
const { Option } = Select;
|
import ThumbnailsList from '../../Components/PedalOCR/ThumbnailsList.jsx';
|
||||||
const { Column } = Table;
|
|
||||||
|
|
||||||
const CameraModal = ({
|
|
||||||
visible,
|
|
||||||
onClose,
|
|
||||||
onCapture,
|
|
||||||
setCameraModalVisible = () => { },
|
|
||||||
}) => {
|
|
||||||
const videoRef = useRef(null);
|
|
||||||
const canvasRef = useRef(null);
|
|
||||||
const [stream, setStream] = useState(null);
|
|
||||||
const [image, setImage] = useState(null);
|
|
||||||
const [cameraOn, setCameraOn] = useState(false);
|
|
||||||
|
|
||||||
const startCamera = async () => {
|
|
||||||
console.log('Starting camera function called...');
|
|
||||||
|
|
||||||
// First test - just set camera on without stream
|
|
||||||
setCameraOn(true);
|
|
||||||
console.log('Camera state forced to ON for testing');
|
|
||||||
|
|
||||||
try {
|
|
||||||
console.log('Checking getUserMedia support...');
|
|
||||||
if (!navigator.mediaDevices?.getUserMedia) {
|
|
||||||
console.error('getUserMedia not supported');
|
|
||||||
message.error('Camera not supported on this device');
|
|
||||||
setCameraModalVisible(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Requesting camera access...');
|
|
||||||
let mediaStream;
|
|
||||||
try {
|
|
||||||
// Try high quality first
|
|
||||||
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
||||||
video: {
|
|
||||||
facingMode: 'environment',
|
|
||||||
width: { ideal: 1920 },
|
|
||||||
height: { ideal: 1080 },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch (highResError) {
|
|
||||||
console.log(
|
|
||||||
'High resolution failed, trying basic constraints:',
|
|
||||||
highResError.message
|
|
||||||
);
|
|
||||||
// Fallback to basic constraints
|
|
||||||
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
||||||
video: { facingMode: 'environment' },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
console.log('Got media stream:', mediaStream);
|
|
||||||
|
|
||||||
if (videoRef.current) {
|
|
||||||
console.log('Setting video source...');
|
|
||||||
videoRef.current.srcObject = mediaStream;
|
|
||||||
setStream(mediaStream);
|
|
||||||
console.log('Stream set successfully');
|
|
||||||
} else {
|
|
||||||
console.error('Video ref is null');
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Camera error:', err.name, err.message);
|
|
||||||
message.error(`Camera error: ${err.message}`);
|
|
||||||
setCameraModalVisible(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const stopCamera = () => {
|
|
||||||
console.log('Stopping camera...');
|
|
||||||
if (stream) {
|
|
||||||
stream.getTracks().forEach((track) => {
|
|
||||||
console.log('Stopping track:', track);
|
|
||||||
track.stop();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setStream(null);
|
|
||||||
setCameraOn(false);
|
|
||||||
console.log('Camera stopped');
|
|
||||||
};
|
|
||||||
|
|
||||||
const captureImage = () => {
|
|
||||||
const video = videoRef.current;
|
|
||||||
const canvas = canvasRef.current;
|
|
||||||
canvas.width = video.videoWidth;
|
|
||||||
canvas.height = video.videoHeight;
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
ctx.imageSmoothingEnabled = true;
|
|
||||||
ctx.imageSmoothingQuality = 'high';
|
|
||||||
ctx.drawImage(video, 0, 0);
|
|
||||||
const imageData = canvas.toDataURL('image/jpeg', 0.95);
|
|
||||||
setImage(imageData);
|
|
||||||
stopCamera();
|
|
||||||
};
|
|
||||||
|
|
||||||
const retake = () => {
|
|
||||||
setImage(null);
|
|
||||||
startCamera();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUse = () => {
|
|
||||||
canvasRef.current.toBlob(
|
|
||||||
(blob) => {
|
|
||||||
const file = new File([blob], 'camera-capture.jpg', {
|
|
||||||
type: 'image/jpeg',
|
|
||||||
});
|
|
||||||
onCapture(file, true); // Pass true to indicate direct submit
|
|
||||||
handleClose();
|
|
||||||
},
|
|
||||||
'image/jpeg',
|
|
||||||
0.95
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
stopCamera();
|
|
||||||
setImage(null);
|
|
||||||
setCameraOn(false);
|
|
||||||
onClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (visible) {
|
|
||||||
startCamera(); // Auto-start camera when modal opens
|
|
||||||
return () => stopCamera();
|
|
||||||
}
|
|
||||||
}, [visible]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DefaultModal
|
|
||||||
title="Camera"
|
|
||||||
open={visible}
|
|
||||||
handleCancel={handleClose}
|
|
||||||
footer={false}
|
|
||||||
width={400}
|
|
||||||
>
|
|
||||||
<div style={{ textAlign: 'center' }}>
|
|
||||||
{/* <div style={{ marginBottom: 10, padding: 10, backgroundColor: '#f0f0f0' }}>
|
|
||||||
<p>Debug: Camera={cameraOn ? 'ON' : 'OFF'}, Stream={stream ? 'Active' : 'None'}, Image={image ? 'Yes' : 'No'}</p>
|
|
||||||
</div> */}
|
|
||||||
|
|
||||||
{!cameraOn && !image && (
|
|
||||||
<div>
|
|
||||||
<p style={{ marginBottom: 16, color: '#666' }}>
|
|
||||||
Starting camera...
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{cameraOn && (
|
|
||||||
<div>
|
|
||||||
<p>Camera is ON - Video should appear below:</p>
|
|
||||||
<video
|
|
||||||
ref={videoRef}
|
|
||||||
autoPlay
|
|
||||||
playsInline
|
|
||||||
muted
|
|
||||||
width="300"
|
|
||||||
height="400"
|
|
||||||
style={{ border: '2px solid red', marginBottom: 10 }}
|
|
||||||
onCanPlay={() => console.log('Video can play')}
|
|
||||||
onError={(e) => console.error('Video error:', e)}
|
|
||||||
onLoadedMetadata={() => console.log('Video metadata loaded')}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<Button onClick={captureImage} type="primary">
|
|
||||||
Capture
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
onClick={() => setCameraOn(false)}
|
|
||||||
style={{ marginLeft: 10 }}
|
|
||||||
>
|
|
||||||
Stop
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{image && (
|
|
||||||
<>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
gap: '10px',
|
|
||||||
justifyContent: 'center',
|
|
||||||
marginBottom: '1rem',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button onClick={retake}>Retake</Button>
|
|
||||||
<Button onClick={handleUse} type="primary">
|
|
||||||
Use Photo
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<img
|
|
||||||
src={image}
|
|
||||||
alt="Captured"
|
|
||||||
style={{
|
|
||||||
width: '80vw',
|
|
||||||
borderRadius: 8,
|
|
||||||
marginBottom: 10,
|
|
||||||
height: '60vh',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<canvas ref={canvasRef} style={{ display: 'none' }} />
|
|
||||||
</div>
|
|
||||||
</DefaultModal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ScanModal = ({
|
const ScanModal = ({
|
||||||
visible = false,
|
visible = false,
|
||||||
|
|
@ -258,42 +40,77 @@ const ScanModal = ({
|
||||||
processingStep = null,
|
processingStep = null,
|
||||||
ocrLoading = false,
|
ocrLoading = false,
|
||||||
handleClearImage = () => { },
|
handleClearImage = () => { },
|
||||||
uploadedImage = null,
|
|
||||||
selectedFile = null,
|
selectedFile = null,
|
||||||
|
images = [],
|
||||||
|
setImages = () => { },
|
||||||
|
finalImages = [],
|
||||||
|
setCurrentIndex = () => { },
|
||||||
|
setFinalImages = () => { },
|
||||||
|
currentIndex = null,
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
|
const cameraRef = useRef(null);
|
||||||
const isMobile =
|
const isMobile =
|
||||||
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
||||||
navigator.userAgent
|
navigator.userAgent
|
||||||
) ||
|
) ||
|
||||||
'ontouchstart' in window ||
|
'ontouchstart' in window ||
|
||||||
navigator.maxTouchPoints > 0;
|
navigator.maxTouchPoints > 0;
|
||||||
const [cameraModalVisible, setCameraModalVisible] = useState(false);
|
|
||||||
const [buttonDisable, setButtonDisable] = useState(false);
|
const [buttonDisable, setButtonDisable] = useState(false);
|
||||||
|
|
||||||
const handleCameraCapture = (file, directSubmit = false) => {
|
const handleCapture = (file) => {
|
||||||
console.log(
|
console.log('Handle capture called with file:', file?.name);
|
||||||
'Camera capture received:',
|
|
||||||
file,
|
|
||||||
'Direct submit:',
|
|
||||||
directSubmit
|
|
||||||
);
|
|
||||||
|
|
||||||
handleUpload(file);
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
if (directSubmit) {
|
const newImage = {
|
||||||
setButtonDisable(true);
|
id: Date.now(),
|
||||||
setTimeout(() => {
|
src: e.target.result,
|
||||||
try {
|
file: file,
|
||||||
onSubmit(file, true);
|
|
||||||
console.log('Triggering submit after camera capture');
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Submit Error:', err?.message);
|
|
||||||
} finally {
|
|
||||||
setButtonDisable(false);
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
setImages([newImage]);
|
||||||
|
setCurrentIndex(0);
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCropComplete = (croppedImage) => {
|
||||||
|
setFinalImages((prev) => {
|
||||||
|
const newImages = [...prev];
|
||||||
|
newImages[currentIndex] = croppedImage;
|
||||||
|
return newImages;
|
||||||
|
});
|
||||||
|
fetch(croppedImage)
|
||||||
|
.then((res) => res.blob())
|
||||||
|
.then((blob) => {
|
||||||
|
const file = new File([blob], 'camera-capture.jpg', {
|
||||||
|
type: 'image/jpeg',
|
||||||
|
});
|
||||||
|
handleUpload(file);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRemoveImage = (index) => {
|
||||||
|
setFinalImages((prev) => prev.filter((_, i) => i !== index));
|
||||||
|
handleClearImage();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRecropImage = (index) => {
|
||||||
|
const imageToRecrop = finalImages[index];
|
||||||
|
setFinalImages((prev) => prev.filter((_, i) => i !== index));
|
||||||
|
// Add back to images for re-cropping
|
||||||
|
const newImage = { id: Date.now(), src: imageToRecrop };
|
||||||
|
setImages((prev) => [...prev, newImage]);
|
||||||
|
setCurrentIndex(images.length);
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetAll = () => {
|
||||||
|
setImages([]);
|
||||||
|
setFinalImages([]);
|
||||||
|
setCurrentIndex(null);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultModal
|
<DefaultModal
|
||||||
title={
|
title={
|
||||||
|
|
@ -368,12 +185,52 @@ const ScanModal = ({
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<input
|
||||||
|
ref={cameraRef}
|
||||||
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
|
capture="environment"
|
||||||
|
multiple
|
||||||
|
hidden
|
||||||
|
onChange={(e) => {
|
||||||
|
const rawFile = e?.target?.files?.[0];
|
||||||
|
if (!rawFile) return;
|
||||||
|
handleCapture(rawFile);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{currentIndex !== null && images[currentIndex] && (
|
||||||
|
<ResizableCropper
|
||||||
|
imageSrc={images[currentIndex].src}
|
||||||
|
currentIndex={currentIndex}
|
||||||
|
total={images.length}
|
||||||
|
onCropComplete={handleCropComplete}
|
||||||
|
onCancel={resetAll}
|
||||||
|
onNext={() => {
|
||||||
|
if (currentIndex + 1 < images.length) {
|
||||||
|
setCurrentIndex(currentIndex + 1);
|
||||||
|
} else {
|
||||||
|
setCurrentIndex(null);
|
||||||
|
setImages([]);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{finalImages.length > 0 && currentIndex === null && (
|
||||||
|
<>
|
||||||
|
<h4>Uploaded Image :</h4>
|
||||||
|
<ThumbnailsList
|
||||||
|
images={finalImages}
|
||||||
|
onRemove={handleRemoveImage}
|
||||||
|
onRecrop={handleRecropImage}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{isMobile && (
|
{isMobile && (
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
size="large"
|
size="large"
|
||||||
icon={<CameraOutlined />}
|
icon={<CameraOutlined />}
|
||||||
onClick={() => setCameraModalVisible(true)}
|
onClick={() => cameraRef.current.click()}
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
|
@ -399,14 +256,14 @@ const ScanModal = ({
|
||||||
)}
|
)}
|
||||||
<Upload
|
<Upload
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
beforeUpload={handleUpload}
|
beforeUpload={handleCapture}
|
||||||
showUploadList={false}
|
showUploadList={false}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
margin: '0 auto',
|
margin: '0 auto',
|
||||||
border: '2px dashed #999',
|
border: '2px dashed #999',
|
||||||
padding: 30,
|
padding: isMobile ? '12px 30px' : 30,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -414,48 +271,11 @@ const ScanModal = ({
|
||||||
style={{ fontSize: 40, color: '#1292ee' }}
|
style={{ fontSize: 40, color: '#1292ee' }}
|
||||||
/>
|
/>
|
||||||
<p style={{ marginTop: '4px' }}>
|
<p style={{ marginTop: '4px' }}>
|
||||||
Click or drag image to upload
|
{`${isMobile ? 'Upload' : 'Click or drag image to upload'}`}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Upload>
|
</Upload>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{uploadedImage && (
|
|
||||||
<div style={{ marginTop: 20 }}>
|
|
||||||
<div className="preview-header">
|
|
||||||
<div style={{ fontFamily: 'Poppins', fontWeight: '500' }}>
|
|
||||||
Preview:
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
type="default"
|
|
||||||
onClick={handleClearImage}
|
|
||||||
icon={
|
|
||||||
<CloseOutlined
|
|
||||||
style={{ height: '15px', width: '15px' }}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
color="danger"
|
|
||||||
>
|
|
||||||
Clear
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<Image
|
|
||||||
src={uploadedImage}
|
|
||||||
alt="Preview"
|
|
||||||
style={{
|
|
||||||
maxWidth: '100%',
|
|
||||||
maxHeight: 300,
|
|
||||||
border: '1px solid #d9d9d9',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<CameraModal
|
|
||||||
visible={cameraModalVisible}
|
|
||||||
onClose={() => setCameraModalVisible(false)}
|
|
||||||
onCapture={handleCameraCapture}
|
|
||||||
setCameraModalVisible={setCameraModalVisible}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -498,6 +318,9 @@ const InvoiceImageExtractorModal = ({
|
||||||
|
|
||||||
const extractedTableRef = useRef(null);
|
const extractedTableRef = useRef(null);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
const [images, setImages] = useState([]);
|
||||||
|
const [finalImages, setFinalImages] = useState([]);
|
||||||
|
const [currentIndex, setCurrentIndex] = useState(null);
|
||||||
const [ocrLoading, setOcrLoading] = useState(false);
|
const [ocrLoading, setOcrLoading] = useState(false);
|
||||||
const [uploadedImage, setUploadedImage] = useState(null);
|
const [uploadedImage, setUploadedImage] = useState(null);
|
||||||
const [selectedFile, setSelectedFile] = useState(null);
|
const [selectedFile, setSelectedFile] = useState(null);
|
||||||
|
|
@ -661,6 +484,9 @@ const InvoiceImageExtractorModal = ({
|
||||||
cleanupUploadedURL();
|
cleanupUploadedURL();
|
||||||
setProcessingStep(null);
|
setProcessingStep(null);
|
||||||
setSelectedFile(null);
|
setSelectedFile(null);
|
||||||
|
setImages([]);
|
||||||
|
setCurrentIndex(null);
|
||||||
|
setFinalImages([]);
|
||||||
if (visible || submit) {
|
if (visible || submit) {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
setExtractedText('');
|
setExtractedText('');
|
||||||
|
|
@ -728,6 +554,7 @@ const InvoiceImageExtractorModal = ({
|
||||||
CompId,
|
CompId,
|
||||||
BranchId
|
BranchId
|
||||||
}
|
}
|
||||||
|
console.log('Dispatching OCR request with data:', data);
|
||||||
const response = await dispatch(
|
const response = await dispatch(
|
||||||
getInvoiceImageData(data)
|
getInvoiceImageData(data)
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
@ -823,6 +650,9 @@ const InvoiceImageExtractorModal = ({
|
||||||
} else if (uploadMoreVisible) {
|
} else if (uploadMoreVisible) {
|
||||||
setUploadMoreVisible(false);
|
setUploadMoreVisible(false);
|
||||||
}
|
}
|
||||||
|
setImages([]);
|
||||||
|
setCurrentIndex(null);
|
||||||
|
setFinalImages([]);
|
||||||
message.success('Invoice processed successfully!');
|
message.success('Invoice processed successfully!');
|
||||||
} else {
|
} else {
|
||||||
if (response?.statusCode === 1 && response?.data?.length === 0) {
|
if (response?.statusCode === 1 && response?.data?.length === 0) {
|
||||||
|
|
@ -832,7 +662,7 @@ const InvoiceImageExtractorModal = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('API OCR Error:', err);
|
console.error('API OCR Error:', err?.message);
|
||||||
message.error('Failed to process invoice.');
|
message.error('Failed to process invoice.');
|
||||||
} finally {
|
} finally {
|
||||||
setOcrLoading(false);
|
setOcrLoading(false);
|
||||||
|
|
@ -954,8 +784,13 @@ const InvoiceImageExtractorModal = ({
|
||||||
processingStep={processingStep}
|
processingStep={processingStep}
|
||||||
ocrLoading={ocrLoading}
|
ocrLoading={ocrLoading}
|
||||||
handleClearImage={handleClearImage}
|
handleClearImage={handleClearImage}
|
||||||
uploadedImage={uploadedImage}
|
|
||||||
selectedFile={selectedFile}
|
selectedFile={selectedFile}
|
||||||
|
images={images}
|
||||||
|
setImages={setImages}
|
||||||
|
finalImages={finalImages}
|
||||||
|
setFinalImages={setFinalImages}
|
||||||
|
currentIndex={currentIndex}
|
||||||
|
setCurrentIndex={setCurrentIndex}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* PREVIEW MODAL */}
|
{/* PREVIEW MODAL */}
|
||||||
|
|
@ -1213,8 +1048,13 @@ const InvoiceImageExtractorModal = ({
|
||||||
processingStep={processingStep}
|
processingStep={processingStep}
|
||||||
ocrLoading={ocrLoading}
|
ocrLoading={ocrLoading}
|
||||||
handleClearImage={handleClearImage}
|
handleClearImage={handleClearImage}
|
||||||
uploadedImage={uploadedImage}
|
|
||||||
selectedFile={selectedFile}
|
selectedFile={selectedFile}
|
||||||
|
images={images}
|
||||||
|
setImages={setImages}
|
||||||
|
finalImages={finalImages}
|
||||||
|
setFinalImages={setFinalImages}
|
||||||
|
currentIndex={currentIndex}
|
||||||
|
setCurrentIndex={setCurrentIndex}
|
||||||
/>
|
/>
|
||||||
</DefaultModal>
|
</DefaultModal>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue