Merge pull request 'mobile-apk-and-web-qrscan' (#159) from mobile-apk-and-web-qrscan into main
Reviewed-on: Pozomind/pozo-retail-app#159
This commit is contained in:
commit
8d19d901b9
|
|
@ -81,6 +81,7 @@ import { Global_PromoCodeOffers } from '../../../../Features/Offer/Offer.js';
|
||||||
import { validateOffers } from '../BSItemCards/ValidateOffer.jsx';
|
import { validateOffers } from '../BSItemCards/ValidateOffer.jsx';
|
||||||
import { useSaleswiseOfferWatcher } from '../BSItemCards/SalesWiseOffer.jsx';
|
import { useSaleswiseOfferWatcher } from '../BSItemCards/SalesWiseOffer.jsx';
|
||||||
import ExpireConfirmModal from '../BookingFunctionality/ExpireConfirmModal.jsx';
|
import ExpireConfirmModal from '../BookingFunctionality/ExpireConfirmModal.jsx';
|
||||||
|
import BarCodeScan from '../../../../Services/BarCodeScan.jsx';
|
||||||
|
|
||||||
export default function BSC1Search(props) {
|
export default function BSC1Search(props) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
@ -4567,10 +4568,15 @@ export default function BSC1Search(props) {
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
{isMobile && screenWidth <= 768 && (
|
{isMobile && screenWidth <= 768 && (
|
||||||
<BiBarcodeReader
|
// <BiBarcodeReader
|
||||||
className="BSC1Search-barcodeicon"
|
// className="BSC1Search-barcodeicon"
|
||||||
onClick={() => handleQrcode()}
|
// onClick={() => handleQrcode()}
|
||||||
// onClick={() => OnfocusTrue()}
|
// // onClick={() => OnfocusTrue()}
|
||||||
|
// />
|
||||||
|
<BarCodeScan
|
||||||
|
onScan={(value) => {
|
||||||
|
ProductNameOnChange(value, true);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -4821,7 +4827,7 @@ export default function BSC1Search(props) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</DefaultModal>
|
</DefaultModal>
|
||||||
{isMobile && screenWidth <= 768 && (
|
{/* {isMobile && screenWidth <= 768 && (
|
||||||
<DefaultModal
|
<DefaultModal
|
||||||
title="Barcode Reader"
|
title="Barcode Reader"
|
||||||
width={800}
|
width={800}
|
||||||
|
|
@ -4839,7 +4845,7 @@ export default function BSC1Search(props) {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</DefaultModal>
|
</DefaultModal>
|
||||||
)}
|
)} */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ import './Verfiedproduct.scss';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { ApplicationPreferences } from '../../../../../Features/BrachLogin/BranchLogin.js';
|
import { ApplicationPreferences } from '../../../../../Features/BrachLogin/BranchLogin.js';
|
||||||
import { changeOfferAppliedProductsForMembership } from '../../../../../Features/Offer/Offernew/BookingOffernew.js';
|
import { changeOfferAppliedProductsForMembership } from '../../../../../Features/Offer/Offernew/BookingOffernew.js';
|
||||||
|
import BarCodeScan from '../../../../../Services/BarCodeScan.jsx';
|
||||||
|
import { isMobile } from 'react-device-detect';
|
||||||
|
|
||||||
|
|
||||||
const VerfiedProducts = ({ drawerOpen = false, setDrawerOpen = () => {} }) => {
|
const VerfiedProducts = ({ drawerOpen = false, setDrawerOpen = () => {} }) => {
|
||||||
|
|
@ -303,10 +305,16 @@ const VerfiedProducts = ({ drawerOpen = false, setDrawerOpen = () => {} }) => {
|
||||||
>
|
>
|
||||||
Clear
|
Clear
|
||||||
</button>
|
</button>
|
||||||
|
{!isMobile ?
|
||||||
<button onClick={() => setShowScanner((s) => !s)}>
|
(<button onClick={() => setShowScanner((s) => !s)}>
|
||||||
{showScanner ? 'Stop Camera' : 'Scan with Camera'}
|
{showScanner ? 'Stop Camera' : 'Scan with Camera'}
|
||||||
</button>
|
</button>)
|
||||||
|
: (<BarCodeScan
|
||||||
|
onScan={(value) => {
|
||||||
|
setScanValue(value);
|
||||||
|
fetchProductsByOrderId(value);
|
||||||
|
}}
|
||||||
|
/>)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{message && <div className="SelfBooking-message">{message}</div>}
|
{message && <div className="SelfBooking-message">{message}</div>}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import BarcodeScanner from './BarcodeScanner';
|
||||||
import { isMobile } from 'react-device-detect';
|
import { isMobile } from 'react-device-detect';
|
||||||
import { BiBarcodeReader } from 'react-icons/bi';
|
import { BiBarcodeReader } from 'react-icons/bi';
|
||||||
import TooltipWrapper from '../../../../Components/Tooltip/Tooltip';
|
import TooltipWrapper from '../../../../Components/Tooltip/Tooltip';
|
||||||
|
import BarCodeScan from '../../../../Services/BarCodeScan.jsx';
|
||||||
|
|
||||||
const BSNavBarComboSearch = (props) => {
|
const BSNavBarComboSearch = (props) => {
|
||||||
|
|
||||||
|
|
@ -1197,28 +1198,28 @@ const BSNavBarComboSearch = (props) => {
|
||||||
: [];
|
: [];
|
||||||
// });
|
// });
|
||||||
};
|
};
|
||||||
const stopScannerFromParent = () => {
|
// const stopScannerFromParent = () => {
|
||||||
if (scannerRef.current) {
|
// if (scannerRef.current) {
|
||||||
scannerRef.current.stopScanner(); // Call stopScanner from the child component
|
// scannerRef.current.stopScanner(); // Call stopScanner from the child component
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleQrcode = () => {
|
// const handleQrcode = () => {
|
||||||
setOpenScanner((prev) => !prev);
|
// setOpenScanner((prev) => !prev);
|
||||||
if (!openScanner && scannerRef.current) {
|
// if (!openScanner && scannerRef.current) {
|
||||||
scannerRef.current.reinitializeCamera(); // Call the function to reinitialize the camera
|
// scannerRef.current.reinitializeCamera(); // Call the function to reinitialize the camera
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleQrData = (decodedText, err) => {
|
// const handleQrData = (decodedText, err) => {
|
||||||
onChangeprodFunction(decodedText);
|
// onChangeprodFunction(decodedText);
|
||||||
setOpenScanner(false); // Close the modal after scanning
|
// setOpenScanner(false); // Close the modal after scanning
|
||||||
stopScannerFromParent();
|
// stopScannerFromParent();
|
||||||
if (err && err?.error) {
|
// if (err && err?.error) {
|
||||||
setMessageData(err?.error);
|
// setMessageData(err?.error);
|
||||||
setMessageType('error');
|
// setMessageType('error');
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
return (
|
return (
|
||||||
<div className="L">
|
<div className="L">
|
||||||
<Messages
|
<Messages
|
||||||
|
|
@ -1289,10 +1290,14 @@ const BSNavBarComboSearch = (props) => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{isMobile && screenWidth <= 768 ? (
|
{isMobile && screenWidth <= 768 ? (
|
||||||
<BiBarcodeReader
|
// <BiBarcodeReader
|
||||||
className="search-icon"
|
// className="search-icon"
|
||||||
onClick={() => handleQrcode()}
|
// onClick={() => handleQrcode()}
|
||||||
/>
|
// />
|
||||||
|
<BarCodeScan
|
||||||
|
onScan={(value) => {
|
||||||
|
onChangeprodFunction(value);
|
||||||
|
}} />
|
||||||
) : (
|
) : (
|
||||||
<IoSearchOutline className="search-icon" />
|
<IoSearchOutline className="search-icon" />
|
||||||
)}
|
)}
|
||||||
|
|
@ -1395,7 +1400,7 @@ const BSNavBarComboSearch = (props) => {
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
)}
|
)}
|
||||||
{isMobile && screenWidth <= 768 && (
|
{/* {isMobile && screenWidth <= 768 && (
|
||||||
<DefaultModal
|
<DefaultModal
|
||||||
title="Barcode Reader"
|
title="Barcode Reader"
|
||||||
width={800}
|
width={800}
|
||||||
|
|
@ -1413,7 +1418,7 @@ const BSNavBarComboSearch = (props) => {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</DefaultModal>
|
</DefaultModal>
|
||||||
)}
|
)} */}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import { BiBarcodeReader } from 'react-icons/bi';
|
||||||
import { ApplicationPreferences } from '../../../../Features/BrachLogin/BranchLogin.js';
|
import { ApplicationPreferences } from '../../../../Features/BrachLogin/BranchLogin.js';
|
||||||
import { useDateStore } from '../../../../Features/BookingScreen/BookingData/DateStore.js';
|
import { useDateStore } from '../../../../Features/BookingScreen/BookingData/DateStore.js';
|
||||||
import { Messages } from '../../../../../ownLib/my-ui-lib.js';
|
import { Messages } from '../../../../../ownLib/my-ui-lib.js';
|
||||||
|
import BarCodeScan from '../../../../Services/BarCodeScan.jsx';
|
||||||
|
|
||||||
const BSNavBarSearch = (props) => {
|
const BSNavBarSearch = (props) => {
|
||||||
const searchInputRef = useRef(null);
|
const searchInputRef = useRef(null);
|
||||||
|
|
@ -362,28 +363,28 @@ const BSNavBarSearch = (props) => {
|
||||||
|
|
||||||
await dispatch(getCardDataWithoutSub(data));
|
await dispatch(getCardDataWithoutSub(data));
|
||||||
};
|
};
|
||||||
const stopScannerFromParent = () => {
|
// const stopScannerFromParent = () => {
|
||||||
if (scannerRef?.current) {
|
// if (scannerRef?.current) {
|
||||||
scannerRef?.current?.stopScanner(); // Call stopScanner from the child component
|
// scannerRef?.current?.stopScanner(); // Call stopScanner from the child component
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleQrcode = () => {
|
// const handleQrcode = () => {
|
||||||
setOpenScanner((prev) => !prev);
|
// setOpenScanner((prev) => !prev);
|
||||||
if (!openScanner && scannerRef?.current) {
|
// if (!openScanner && scannerRef?.current) {
|
||||||
scannerRef?.current?.reinitializeCamera(); // Call the function to reinitialize the camera
|
// scannerRef?.current?.reinitializeCamera(); // Call the function to reinitialize the camera
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleQrData = async (value, err) => {
|
// const handleQrData = async (value, err) => {
|
||||||
if (err && err?.error) {
|
// if (err && err?.error) {
|
||||||
setMessageData(err?.error);
|
// setMessageData(err?.error);
|
||||||
setMessageType('error');
|
// setMessageType('error');
|
||||||
}
|
// }
|
||||||
await searchdata(value);
|
// await searchdata(value);
|
||||||
setOpenScanner(false);
|
// setOpenScanner(false);
|
||||||
stopScannerFromParent();
|
// stopScannerFromParent();
|
||||||
};
|
// };
|
||||||
|
|
||||||
const onComplete = useCallback(() => {
|
const onComplete = useCallback(() => {
|
||||||
setMessageData(null);
|
setMessageData(null);
|
||||||
|
|
@ -421,9 +422,14 @@ const BSNavBarSearch = (props) => {
|
||||||
disabled={props.OrderType === 'Failed' ? true : false}
|
disabled={props.OrderType === 'Failed' ? true : false}
|
||||||
/>
|
/>
|
||||||
{isMobile && screenWidth <= 768 ? (
|
{isMobile && screenWidth <= 768 ? (
|
||||||
<BiBarcodeReader
|
// <BiBarcodeReader
|
||||||
className="search-icon"
|
// className="search-icon"
|
||||||
onClick={() => handleQrcode()}
|
// onClick={() => handleQrcode()}
|
||||||
|
// />
|
||||||
|
<BarCodeScan
|
||||||
|
onScan={(value) => {
|
||||||
|
searchdata(value);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<IoSearchOutline className="search-icon" />
|
<IoSearchOutline className="search-icon" />
|
||||||
|
|
@ -435,7 +441,7 @@ const BSNavBarSearch = (props) => {
|
||||||
</div>} */}
|
</div>} */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{isMobile && screenWidth <= 768 && (
|
{/* {isMobile && screenWidth <= 768 && (
|
||||||
<DefaultModal
|
<DefaultModal
|
||||||
title="Barcode Reader"
|
title="Barcode Reader"
|
||||||
width={800}
|
width={800}
|
||||||
|
|
@ -454,7 +460,7 @@ const BSNavBarSearch = (props) => {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</DefaultModal>
|
</DefaultModal>
|
||||||
)}
|
)} */}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ import Search from "../../../../Components/Forms/Search";
|
||||||
import VoiceToTextItemCard from "../../../VoiceToText/VoiceToTextItemCard";
|
import VoiceToTextItemCard from "../../../VoiceToText/VoiceToTextItemCard";
|
||||||
import { ApplicationPreferences } from "../../../../Features/BrachLogin/BranchLogin";
|
import { ApplicationPreferences } from "../../../../Features/BrachLogin/BranchLogin";
|
||||||
import { useDateStore } from "../../../../Features/BookingScreen/BookingData/DateStore";
|
import { useDateStore } from "../../../../Features/BookingScreen/BookingData/DateStore";
|
||||||
|
import BarCodeScan from "../../../../Services/BarCodeScan";
|
||||||
|
import { isMobile } from "react-device-detect";
|
||||||
|
|
||||||
const BSNavbarSearchStandard = ({ inputRef }) => {
|
const BSNavbarSearchStandard = ({ inputRef }) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
@ -147,6 +149,9 @@ const BSNavbarSearchStandard = ({ inputRef }) => {
|
||||||
const handleSearch = (e) => {
|
const handleSearch = (e) => {
|
||||||
dispatch(changeSearchedData(e?.target?.value));
|
dispatch(changeSearchedData(e?.target?.value));
|
||||||
};
|
};
|
||||||
|
const handleScan = (e) => {
|
||||||
|
dispatch(changeSearchedData(e));
|
||||||
|
};
|
||||||
const HandleVoiceSearch = () => {
|
const HandleVoiceSearch = () => {
|
||||||
setVoiceSearch(!voiceSearch);
|
setVoiceSearch(!voiceSearch);
|
||||||
};
|
};
|
||||||
|
|
@ -159,6 +164,13 @@ const BSNavbarSearchStandard = ({ inputRef }) => {
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
value={ProdName}
|
value={ProdName}
|
||||||
/>
|
/>
|
||||||
|
{isMobile && screenWidth <= 768 && (
|
||||||
|
<BarCodeScan
|
||||||
|
onScan={(value) => {
|
||||||
|
handleScan(value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ import { PrintStyleFunction } from '../paymentpdfPage/PrintStyleFunction.js';
|
||||||
import { PurchaseOrderMobilePrint } from './PurchsasePrintStyle/PurchaseOrderMobilePrint.js';
|
import { PurchaseOrderMobilePrint } from './PurchsasePrintStyle/PurchaseOrderMobilePrint.js';
|
||||||
import { isMobile } from 'react-device-detect';
|
import { isMobile } from 'react-device-detect';
|
||||||
import { CiEdit } from 'react-icons/ci';
|
import { CiEdit } from 'react-icons/ci';
|
||||||
|
import BarCodeScan from '../../Services/BarCodeScan.jsx';
|
||||||
|
|
||||||
const subDirectory = import.meta.env.BASE_URL;
|
const subDirectory = import.meta.env.BASE_URL;
|
||||||
const stylesMap = {
|
const stylesMap = {
|
||||||
|
|
@ -1628,6 +1629,7 @@ const PurchaseOrder = () => {
|
||||||
}}
|
}}
|
||||||
></AutoComplete>
|
></AutoComplete>
|
||||||
</FloatLabel>
|
</FloatLabel>
|
||||||
|
{!isMobile && (
|
||||||
<Tooltip title={'BarCode/QrCode'} placement={'top'}>
|
<Tooltip title={'BarCode/QrCode'} placement={'top'}>
|
||||||
<BsUpcScan
|
<BsUpcScan
|
||||||
strokeWidth={0.5}
|
strokeWidth={0.5}
|
||||||
|
|
@ -1641,6 +1643,16 @@ const PurchaseOrder = () => {
|
||||||
onClick={handleScanSearch}
|
onClick={handleScanSearch}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{isMobile && (
|
||||||
|
<div className='IsmoBileBarcode'>
|
||||||
|
<BarCodeScan
|
||||||
|
onScan={(value) => {
|
||||||
|
debouncedScannerSearch(value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,8 @@ import AddAllProductsButton from './AddAllProductGrid.jsx';
|
||||||
import SettingsIconWithModal from './SettingsIconWithModal.jsx';
|
import SettingsIconWithModal from './SettingsIconWithModal.jsx';
|
||||||
import VirtualizedTable from './VirtualizedTable.jsx';
|
import VirtualizedTable from './VirtualizedTable.jsx';
|
||||||
import { useDebounce } from './UseDebounce.jsx';
|
import { useDebounce } from './UseDebounce.jsx';
|
||||||
|
import { isMobile } from 'react-device-detect';
|
||||||
|
import BarCodeScan from '../../Services/BarCodeScan.jsx';
|
||||||
|
|
||||||
const subDirectory = import.meta.env.BASE_URL;
|
const subDirectory = import.meta.env.BASE_URL;
|
||||||
const EditableContext = React.createContext(null);
|
const EditableContext = React.createContext(null);
|
||||||
|
|
@ -3813,6 +3815,28 @@ const StockForm = ({ formType }) => {
|
||||||
style={{ width: '250px' }}
|
style={{ width: '250px' }}
|
||||||
></AutoComplete>
|
></AutoComplete>
|
||||||
</FloatLabel>
|
</FloatLabel>
|
||||||
|
{/* <Tooltip title={'BarCode/QrCode'} placement={'top'}>
|
||||||
|
<BsUpcScan
|
||||||
|
strokeWidth={0.5}
|
||||||
|
color="#000"
|
||||||
|
style={{
|
||||||
|
fontSize: '16px',
|
||||||
|
color: scanner ? '#52c41a' : '#888',
|
||||||
|
fontWeight: '600',
|
||||||
|
}}
|
||||||
|
className="product-scan-Icon"
|
||||||
|
onClick={handleScanSearch}
|
||||||
|
/>
|
||||||
|
</Tooltip> */}
|
||||||
|
{isMobile ? (
|
||||||
|
<div className="IsmoBileBarcode">
|
||||||
|
<BarCodeScan
|
||||||
|
onScan={(value) => {
|
||||||
|
debouncedScannerSearch(value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
<Tooltip title={'BarCode/QrCode'} placement={'top'}>
|
<Tooltip title={'BarCode/QrCode'} placement={'top'}>
|
||||||
<BsUpcScan
|
<BsUpcScan
|
||||||
strokeWidth={0.5}
|
strokeWidth={0.5}
|
||||||
|
|
@ -3826,6 +3850,7 @@ const StockForm = ({ formType }) => {
|
||||||
onClick={handleScanSearch}
|
onClick={handleScanSearch}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ import { getCompBranchData } from '../../Features/BrachLogin/BranchLogin.js';
|
||||||
import { changeBreadCrumb } from '../../Features/AppPage/CenterPage.js';
|
import { changeBreadCrumb } from '../../Features/AppPage/CenterPage.js';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
import { postRequestStock } from '../../Features/RequestStock/RequestStock.js';
|
import { postRequestStock } from '../../Features/RequestStock/RequestStock.js';
|
||||||
|
import BarCodeScan from '../../Services/BarCodeScan.jsx';
|
||||||
|
import { isMobile } from 'react-device-detect';
|
||||||
const subDirectory = import.meta.env.BASE_URL;
|
const subDirectory = import.meta.env.BASE_URL;
|
||||||
|
|
||||||
function debounce(func, wait) {
|
function debounce(func, wait) {
|
||||||
|
|
@ -516,13 +518,22 @@ const CreateTransfer = () => {
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
/>
|
/>
|
||||||
</FloatLabel>
|
</FloatLabel>
|
||||||
|
{isMobile ? (
|
||||||
|
<div className="IsmoBileBarcode">
|
||||||
|
<BarCodeScan
|
||||||
|
onScan={(value) => {
|
||||||
|
debouncedScannerSearch(value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
<Tooltip title="BarCode / QR Code">
|
<Tooltip title="BarCode / QR Code">
|
||||||
<BsUpcScan
|
<BsUpcScan
|
||||||
className={`product-scan-icon ${scanner ? 'active' : ''}`}
|
className={`product-scan-icon ${scanner ? 'active' : ''}`}
|
||||||
onClick={handleScannerToggle}
|
onClick={handleScannerToggle}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,419 @@
|
||||||
|
// import React, { useRef, useState, useEffect } from "react";
|
||||||
|
// import { BarcodeScanner } from "@capacitor-mlkit/barcode-scanning";
|
||||||
|
// import { BsUpcScan } from "react-icons/bs";
|
||||||
|
// import { BrowserMultiFormatReader } from "@zxing/library";
|
||||||
|
// import { Capacitor } from "@capacitor/core";
|
||||||
|
// import { DefaultModal } from "../Components/Modal/DefaultModal";
|
||||||
|
|
||||||
|
// export default function BarCodeScan({ onScan }) {
|
||||||
|
// const isMobileApp = Capacitor.getPlatform() !== "web";
|
||||||
|
// const [scanning, setScanning] = useState(false);
|
||||||
|
// const [modalOpen, setModalOpen] = useState(false);
|
||||||
|
// const videoRef = useRef(null);
|
||||||
|
// const codeReaderRef = useRef(null);
|
||||||
|
// const streamRef = useRef(null);
|
||||||
|
|
||||||
|
// const startScan = async () => {
|
||||||
|
// if (scanning) return;
|
||||||
|
// setScanning(true);
|
||||||
|
|
||||||
|
// if (isMobileApp) {
|
||||||
|
// // Mobile: MLKit scanner
|
||||||
|
// try {
|
||||||
|
// const perm = await BarcodeScanner.requestPermissions();
|
||||||
|
// if (perm.camera !== "granted") {
|
||||||
|
// alert("Camera permission not granted");
|
||||||
|
// setScanning(false);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const { barcodes } = await BarcodeScanner.scan();
|
||||||
|
// if (barcodes && barcodes.length > 0) {
|
||||||
|
// onScan(barcodes[0].rawValue);
|
||||||
|
// }
|
||||||
|
// } catch (err) {
|
||||||
|
// alert("Error scanning barcode: " + err.message);
|
||||||
|
// } finally {
|
||||||
|
// setScanning(false);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // Web: open modal and start camera
|
||||||
|
// setModalOpen(true);
|
||||||
|
// setTimeout(() => startWebScan(), 50); // wait for modal DOM
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const startWebScan = async () => {
|
||||||
|
// try {
|
||||||
|
// codeReaderRef.current = new BrowserMultiFormatReader();
|
||||||
|
// streamRef.current = await navigator.mediaDevices.getUserMedia({
|
||||||
|
// video: { facingMode: "environment" },
|
||||||
|
// });
|
||||||
|
// if (videoRef.current) {
|
||||||
|
// videoRef.current.srcObject = streamRef.current;
|
||||||
|
// videoRef.current.play();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// codeReaderRef.current.decodeFromVideoDevice(
|
||||||
|
// null,
|
||||||
|
// videoRef.current,
|
||||||
|
// (result) => {
|
||||||
|
// if (result) {
|
||||||
|
// onScan(result.getText());
|
||||||
|
// stopWebScan();
|
||||||
|
// setModalOpen(false);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// } catch (err) {
|
||||||
|
// alert("Error accessing camera: " + err.message);
|
||||||
|
// setScanning(false);
|
||||||
|
// setModalOpen(false);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const stopWebScan = () => {
|
||||||
|
// if (streamRef.current) {
|
||||||
|
// streamRef.current.getTracks().forEach((track) => track.stop());
|
||||||
|
// streamRef.current = null;
|
||||||
|
// }
|
||||||
|
// if (codeReaderRef.current) {
|
||||||
|
// codeReaderRef.current.reset();
|
||||||
|
// codeReaderRef.current = null;
|
||||||
|
// }
|
||||||
|
// setScanning(false);
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const closeModal = () => {
|
||||||
|
// stopWebScan();
|
||||||
|
// setModalOpen(false);
|
||||||
|
// };
|
||||||
|
|
||||||
|
// // Stop camera if component unmounts
|
||||||
|
// useEffect(() => () => stopWebScan(), []);
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <div style={{ display: "flex", justifyContent: "center", padding: 20 }}>
|
||||||
|
// {!scanning && (
|
||||||
|
// <BsUpcScan
|
||||||
|
// onClick={startScan}
|
||||||
|
// style={{ fontSize: 32, color: "#007bff", cursor: "pointer" }}
|
||||||
|
// />
|
||||||
|
// )}
|
||||||
|
|
||||||
|
// <DefaultModal
|
||||||
|
// title="Barcode Reader"
|
||||||
|
// width={500}
|
||||||
|
// open={modalOpen}
|
||||||
|
// footer={false}
|
||||||
|
// handleCancel={() => {
|
||||||
|
// closeModal();
|
||||||
|
// }}
|
||||||
|
// >
|
||||||
|
// <div
|
||||||
|
// style={{
|
||||||
|
// display: "flex",
|
||||||
|
// flexDirection: "column",
|
||||||
|
// alignItems: "center",
|
||||||
|
// justifyContent: "center",
|
||||||
|
// }}
|
||||||
|
// >
|
||||||
|
// <video
|
||||||
|
// ref={videoRef}
|
||||||
|
// style={{
|
||||||
|
// width: "100%",
|
||||||
|
// maxWidth: 400,
|
||||||
|
// borderRadius: 8,
|
||||||
|
// border: "2px solid #000",
|
||||||
|
// }}
|
||||||
|
// />
|
||||||
|
|
||||||
|
// <button
|
||||||
|
// onClick={closeModal}
|
||||||
|
// style={{
|
||||||
|
// marginTop: 20,
|
||||||
|
// padding: "10px 20px",
|
||||||
|
// fontSize: 16,
|
||||||
|
// borderRadius: 8,
|
||||||
|
// border: "none",
|
||||||
|
// cursor: "pointer",
|
||||||
|
// }}
|
||||||
|
// >
|
||||||
|
// Close
|
||||||
|
// </button>
|
||||||
|
// </div>
|
||||||
|
// </DefaultModal>
|
||||||
|
|
||||||
|
// </div>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
import React, { useRef, useState, useEffect } from "react";
|
||||||
|
import { BarcodeScanner } from "@capacitor-mlkit/barcode-scanning";
|
||||||
|
import { BsUpcScan } from "react-icons/bs";
|
||||||
|
import { Capacitor } from "@capacitor/core";
|
||||||
|
import { DefaultModal } from "../Components/Modal/DefaultModal";
|
||||||
|
import QrScanner from "qr-scanner/qr-scanner.min.js";
|
||||||
|
import {
|
||||||
|
BrowserMultiFormatReader,
|
||||||
|
BarcodeFormat,
|
||||||
|
} from "@zxing/library";
|
||||||
|
|
||||||
|
QrScanner.WORKER_PATH = new URL(
|
||||||
|
"qr-scanner/qr-scanner-worker.min.js",
|
||||||
|
import.meta.url
|
||||||
|
).toString();
|
||||||
|
|
||||||
|
export default function BarCodeScan({ onScan }) {
|
||||||
|
const isMobileApp = Capacitor.getPlatform() !== "web";
|
||||||
|
const [scanning, setScanning] = useState(false);
|
||||||
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
|
|
||||||
|
const videoRef = useRef(null);
|
||||||
|
const qrScannerRef = useRef(null);
|
||||||
|
const barcodeReaderRef = useRef(null);
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// START SCAN
|
||||||
|
// -------------------------
|
||||||
|
const startScan = async () => {
|
||||||
|
if (scanning) return;
|
||||||
|
setScanning(true);
|
||||||
|
|
||||||
|
if (isMobileApp) {
|
||||||
|
try {
|
||||||
|
const perm = await BarcodeScanner.requestPermissions();
|
||||||
|
if (perm.camera !== "granted") {
|
||||||
|
alert("Camera permission not granted");
|
||||||
|
setScanning(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { barcodes } = await BarcodeScanner.scan();
|
||||||
|
if (barcodes?.length > 0) {
|
||||||
|
onScan(barcodes[0].rawValue);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
} finally {
|
||||||
|
setScanning(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setModalOpen(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// START WEB SCAN (HYBRID)
|
||||||
|
// -------------------------
|
||||||
|
const startWebScan = async () => {
|
||||||
|
if (!videoRef.current) return;
|
||||||
|
|
||||||
|
// Start QR scanner (fast)
|
||||||
|
qrScannerRef.current = new QrScanner(
|
||||||
|
videoRef.current,
|
||||||
|
(result) => {
|
||||||
|
stopWebScan();
|
||||||
|
onScan(result.data);
|
||||||
|
setModalOpen(false);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
maxScansPerSecond: 25,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await qrScannerRef.current.start();
|
||||||
|
|
||||||
|
// Start Barcode scanner (ZXing)
|
||||||
|
barcodeReaderRef.current = new BrowserMultiFormatReader(undefined, {
|
||||||
|
possibleFormats: [
|
||||||
|
BarcodeFormat.CODE_128,
|
||||||
|
BarcodeFormat.EAN_13,
|
||||||
|
BarcodeFormat.UPC_A,
|
||||||
|
BarcodeFormat.UPC_E,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
barcodeReaderRef.current.timeBetweenDecodingAttempts = 50;
|
||||||
|
|
||||||
|
barcodeReaderRef.current.decodeFromVideoDevice(
|
||||||
|
null,
|
||||||
|
videoRef.current,
|
||||||
|
(result) => {
|
||||||
|
if (result) {
|
||||||
|
stopWebScan();
|
||||||
|
onScan(result.getText());
|
||||||
|
setModalOpen(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopWebScan = () => {
|
||||||
|
if (qrScannerRef.current) {
|
||||||
|
qrScannerRef.current.stop();
|
||||||
|
qrScannerRef.current.destroy();
|
||||||
|
qrScannerRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (barcodeReaderRef.current) {
|
||||||
|
barcodeReaderRef.current.reset();
|
||||||
|
barcodeReaderRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
setScanning(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
stopWebScan();
|
||||||
|
setModalOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (modalOpen) {
|
||||||
|
startWebScan();
|
||||||
|
}
|
||||||
|
}, [modalOpen]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => stopWebScan();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ display: "flex", justifyContent: "center", padding: 20 }}>
|
||||||
|
{!scanning && (
|
||||||
|
<BsUpcScan
|
||||||
|
onClick={startScan}
|
||||||
|
style={{
|
||||||
|
fontSize: 32,
|
||||||
|
color: "#007bff",
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* <DefaultModal
|
||||||
|
title="QR / Barcode Reader"
|
||||||
|
width={500}
|
||||||
|
open={modalOpen}
|
||||||
|
footer={false}
|
||||||
|
handleCancel={closeModal}
|
||||||
|
>
|
||||||
|
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||||
|
<video
|
||||||
|
ref={videoRef}
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: 400,
|
||||||
|
borderRadius: 8,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={closeModal}
|
||||||
|
style={{
|
||||||
|
marginTop: 20,
|
||||||
|
padding: "10px 20px",
|
||||||
|
fontSize: 16,
|
||||||
|
borderRadius: 8,
|
||||||
|
border: "none",
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
</DefaultModal> */}
|
||||||
|
<DefaultModal
|
||||||
|
title="QR / Barcode Reader"
|
||||||
|
width={500}
|
||||||
|
open={modalOpen}
|
||||||
|
footer={false}
|
||||||
|
handleCancel={closeModal}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "relative",
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: 400,
|
||||||
|
margin: "auto",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* VIDEO */}
|
||||||
|
<video
|
||||||
|
ref={videoRef}
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
borderRadius: 8,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* DARK OVERLAY */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
background: "rgba(0,0,0,0.5)",
|
||||||
|
borderRadius: 8,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* SCAN BOX */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
width: "70%",
|
||||||
|
height: "60%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
border: "3px solid #00ff00",
|
||||||
|
borderRadius: 12,
|
||||||
|
boxShadow: "0 0 0 2000px rgba(0,0,0,0.4)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* SCAN LINE */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
left: "15%",
|
||||||
|
width: "70%",
|
||||||
|
height: 2,
|
||||||
|
background: "red",
|
||||||
|
animation: "scanAnimation 2s infinite linear",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={closeModal}
|
||||||
|
style={{
|
||||||
|
marginTop: 20,
|
||||||
|
padding: "10px 20px",
|
||||||
|
fontSize: 16,
|
||||||
|
borderRadius: 8,
|
||||||
|
border: "none",
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Animation */}
|
||||||
|
<style>
|
||||||
|
{`
|
||||||
|
@keyframes scanAnimation {
|
||||||
|
0% { top: 25%; }
|
||||||
|
50% { top: 70%; }
|
||||||
|
100% { top: 25%; }
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
</style>
|
||||||
|
</DefaultModal>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue