FPSMS-frontend
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

QrCodeScanner.tsx 7.5 KiB

11 ay önce
11 ay önce
1 yıl önce
11 ay önce
11 ay önce
11 ay önce
11 ay önce
11 ay önce
11 ay önce
11 ay önce
11 ay önce
11 ay önce
11 ay önce
11 ay önce
11 ay önce
1 yıl önce
11 ay önce
11 ay önce
1 yıl önce
11 ay önce
11 ay önce
11 ay önce
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. import {
  2. Autocomplete,
  3. Box,
  4. Button,
  5. Card,
  6. CardContent,
  7. Grid,
  8. Modal,
  9. ModalProps,
  10. Stack,
  11. SxProps,
  12. TextField,
  13. Typography,
  14. } from "@mui/material";
  15. import {
  16. CameraDevice,
  17. Html5Qrcode,
  18. Html5QrcodeCameraScanConfig,
  19. Html5QrcodeFullConfig,
  20. Html5QrcodeResult,
  21. Html5QrcodeScanner,
  22. Html5QrcodeScannerState,
  23. QrcodeErrorCallback,
  24. QrcodeSuccessCallback,
  25. } from "html5-qrcode";
  26. import { Html5QrcodeError } from "html5-qrcode/esm/core";
  27. import { Html5QrcodeScannerConfig } from "html5-qrcode/esm/html5-qrcode-scanner";
  28. import React, {
  29. RefObject,
  30. useCallback,
  31. useEffect,
  32. useMemo,
  33. useRef,
  34. useState,
  35. } from "react";
  36. import { useTranslation } from "react-i18next";
  37. import QrCodeScannerIcon from "@mui/icons-material/QrCodeScanner";
  38. import StopCircleOutlinedIcon from "@mui/icons-material/StopCircleOutlined";
  39. import CloseOutlinedIcon from "@mui/icons-material/CloseOutlined";
  40. import { QrCodeInfo } from "@/app/api/qrcode";
  41. const scannerSx: React.CSSProperties = {
  42. position: "absolute",
  43. // top: "50%",
  44. // left: "50%",
  45. // transform: "translate(-50%, -50%)",
  46. width: "90%",
  47. maxHeight: "10%",
  48. maxWidth: 1400,
  49. };
  50. type QrCodeScannerProps = {
  51. cameras: CameraDevice[];
  52. title?: string;
  53. contents?: string[];
  54. onScanSuccess: (qrCodeInfo: QrCodeInfo) => void;
  55. onScanError?: (error: string) => void;
  56. isOpen: boolean;
  57. onClose: () => void;
  58. };
  59. const QrCodeScanner: React.FC<QrCodeScannerProps> = ({
  60. title,
  61. contents,
  62. onScanSuccess,
  63. onScanError,
  64. isOpen,
  65. onClose,
  66. }) => {
  67. const { t } = useTranslation();
  68. const [isScanned, setIsScanned] = useState<boolean>(false);
  69. const [scanner, setScanner] = useState<Html5Qrcode | null>(null);
  70. const [cameraList, setCameraList] = useState<CameraDevice[]>([]);
  71. const [selectedCameraId, setSelectedCameraId] = useState<string | null>(null);
  72. const stringList = [
  73. "ABC: abc",
  74. "123:123",
  75. "ABC: abc",
  76. "123:123",
  77. "ABC: abc",
  78. "123:123",
  79. ];
  80. const scannerConfig: Html5QrcodeFullConfig = {
  81. verbose: false,
  82. };
  83. const cameraConfig: Html5QrcodeCameraScanConfig = {
  84. fps: 10,
  85. qrbox: { width: 250, height: 250 },
  86. // aspectRatio: cardRef.current ? (cardRef.current.offsetWidth / cardRef.current.offsetHeight) : 1.78,
  87. aspectRatio: (window.innerWidth / window.innerHeight) * 1.5, // can be better
  88. };
  89. // MediaTrackConstraintSet
  90. const mediaTrackConstraintSet = {
  91. facingMode: "environment",
  92. };
  93. const handleScanStart = useCallback(() => {
  94. if (scanner && selectedCameraId) {
  95. if (scanner.getState() === Html5QrcodeScannerState.SCANNING) {
  96. console.log("first");
  97. scanner.stop();
  98. }
  99. scanner.start(
  100. selectedCameraId,
  101. cameraConfig,
  102. handleScanSuccess,
  103. handleScanError,
  104. );
  105. }
  106. }, [selectedCameraId, scanner]);
  107. const handleCameraList = useCallback(async () => {
  108. const cameras = await Html5Qrcode.getCameras();
  109. setCameraList(cameras);
  110. if (cameras.length > 0) {
  111. handleCameraChange(cameras[cameras.length - 1].id);
  112. }
  113. }, []);
  114. const handleCameraChange = useCallback((id: string) => {
  115. setSelectedCameraId(id);
  116. }, []);
  117. const switchScanStatus = useCallback(() => {
  118. if (scanner) {
  119. console.log(isScanned);
  120. switch (isScanned) {
  121. case true:
  122. setIsScanned(false);
  123. scanner.resume();
  124. break;
  125. case false:
  126. setIsScanned(true);
  127. scanner.pause(true);
  128. break;
  129. }
  130. }
  131. }, [scanner, isScanned]);
  132. const handleScanSuccess = useCallback<QrcodeSuccessCallback>(
  133. (decodedText, result) => {
  134. if (scanner) {
  135. console.log(`Decoded text: ${decodedText}`);
  136. const parseData: QrCodeInfo = JSON.parse(decodedText);
  137. console.log(parseData);
  138. // Handle the decoded text as needed
  139. switchScanStatus();
  140. onScanSuccess(parseData);
  141. }
  142. },
  143. [scanner, onScanSuccess],
  144. );
  145. const handleScanError = useCallback<QrcodeErrorCallback>(
  146. (errorMessage, error) => {
  147. // console.log(`Error: ${errorMessage}`);
  148. if (onScanError) {
  149. onScanError(errorMessage);
  150. }
  151. },
  152. [scanner, onScanError],
  153. );
  154. const handleScanCloseButton = useCallback(async () => {
  155. if (scanner) {
  156. console.log("Cleaning up scanner...");
  157. await scanner.stop();
  158. scanner.clear();
  159. onClose();
  160. }
  161. }, [scanner]);
  162. // close modal without using Cancel Button
  163. const handleScanClose = useCallback(async () => {
  164. if (scanner && !isOpen) {
  165. handleScanCloseButton();
  166. }
  167. }, [scanner, isOpen, handleScanCloseButton]);
  168. // -------------------------------------------------------//
  169. useEffect(() => {
  170. setScanner(new Html5Qrcode("qr-reader", scannerConfig));
  171. handleCameraList();
  172. }, []);
  173. useEffect(() => {
  174. handleScanStart();
  175. }, [scanner, selectedCameraId]);
  176. useEffect(() => {
  177. handleScanClose();
  178. }, [isOpen]);
  179. return (
  180. <>
  181. <Stack spacing={2}>
  182. {title && (
  183. <Typography
  184. variant="overline"
  185. display="block"
  186. marginBlockEnd={1}
  187. paddingLeft={2}
  188. >
  189. {"Title"}
  190. </Typography>
  191. )}
  192. <Grid
  193. container
  194. alignItems="center"
  195. justifyContent="center"
  196. rowSpacing={2}
  197. columns={{ xs: 6, sm: 12 }}
  198. >
  199. <Grid item xs={12}>
  200. <div
  201. style={{
  202. textAlign: "center",
  203. margin: "auto",
  204. justifyContent: "center",
  205. }}
  206. id="qr-reader"
  207. hidden={isScanned}
  208. />
  209. </Grid>
  210. {/* {cameraList.length > 0 && <Grid item xs={6} >
  211. <Autocomplete
  212. disableClearable
  213. noOptionsText={t("No Options")}
  214. options={cameraList}
  215. value={cameraList.find((camera) => camera.id === selectedCameraId)}
  216. onChange={((event, value) => {
  217. setSelectedCameraId(value.id)
  218. })}
  219. renderInput={(params) => (
  220. <TextField
  221. {...params}
  222. variant="outlined"
  223. label={t("Selected Camera")}
  224. />
  225. )}
  226. />
  227. </Grid>} */}
  228. {contents &&
  229. contents.map((string) => {
  230. return (
  231. <Grid item xs={8}>
  232. {string}
  233. </Grid>
  234. );
  235. })}
  236. </Grid>
  237. <Stack
  238. direction="row"
  239. justifyContent={"flex-end"}
  240. spacing={2}
  241. sx={{ margin: 2 }}
  242. >
  243. <Button
  244. size="small"
  245. onClick={switchScanStatus}
  246. variant="contained"
  247. // sx={{ margin: 2 }}
  248. startIcon={
  249. isScanned ? <QrCodeScannerIcon /> : <StopCircleOutlinedIcon />
  250. }
  251. >
  252. {isScanned ? t("Start Scanning") : t("Stop Scanning")}
  253. </Button>
  254. <Button
  255. size="small"
  256. onClick={handleScanCloseButton}
  257. variant="outlined"
  258. // color="error"
  259. // sx={{ margin: 2 }}
  260. startIcon={<CloseOutlinedIcon />}
  261. >
  262. {t("Cancel")}
  263. </Button>
  264. </Stack>
  265. </Stack>
  266. </>
  267. );
  268. };
  269. export default QrCodeScanner;