import Modal from "@/components/Modal"; import styles from "../styles.module.scss"; import { useTranslations } from "@/hooks/translations"; import { ELocalesPlacement } from "@/locales"; import Title from "@/components/Title"; import CameraModal from "@/components/CompatibilityV2/components/CameraModal"; import Loader, { LoaderColor } from "@/components/Loader"; import Toast from "@/components/pages/ABDesign/v1/components/Toast"; import routes from "@/routes"; import { useNavigate } from "react-router-dom"; import { useEffect, useState } from "react"; import { actions } from "@/store"; import { useApi } from "@/api"; import { useDispatch } from "react-redux"; import { IPalmistryFinger, IPalmistryLine } from "@/api/resources/Palmistry"; import { ICompatibilityV2FingerLocal } from "@/store/compatibilityV2"; import { DataURIToBlob } from "@/services/data"; import metricService, { EGoals, EMetrics } from "@/services/metric/metricService"; import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash"; import { checkCameraPermissionState } from "@/services/permission/permisson"; enum EToastVisible { "try_again" = "try_again", "try_again_or_next" = "try_again_or_next", "no_access_camera" = "no_access_camera", "reload_page" = "reload_page", "upload_photo" = "upload_photo", } const isInstagramAndroid = window?.navigator?.userAgent?.includes("Instagram") && /Android/.test(window?.navigator?.userAgent); function AndroidCamera() { const api = useApi(); const dispatch = useDispatch(); const { translate } = useTranslations(ELocalesPlacement.CompatibilityV2); const navigate = useNavigate(); const { isReady, variant: cameraRequestModalCompatibilityV2 } = useUnleash({ flag: EUnleashFlags.cameraRequestModalCompatibilityV2 }); const isShowCameraRequestModal = cameraRequestModalCompatibilityV2 !== "hide"; const { variant: compatibilityV2ScanHand } = useUnleash({ flag: EUnleashFlags.compatibilityV2ScanHand }); const isShowScanHand = compatibilityV2ScanHand !== "hide"; const [isCameraModalOpen, setIsCameraModalOpen] = useState(false); const [isLoading, setIsLoading] = useState(false); const [isRequestCameraModalOpen, setIsRequestCameraModalOpen] = useState(isShowCameraRequestModal); const [toastVisible, setToastVisible] = useState(null); const handleToScanHand = () => { metricService.reachGoal(EGoals.SCAN_ARTIFICIAL_PHOTO, [EMetrics.YANDEX, EMetrics.KLAVIYO]); return navigate(routes.client.compatibilityV2ScanHand()) } const handleToScannedPhoto = () => { metricService.reachGoal(EGoals.CAMERA_SUCCESS, [EMetrics.YANDEX, EMetrics.KLAVIYO]); return navigate(routes.client.compatibilityV2ScannedPhoto()) } const handleCameraError = (error: string | DOMException) => { console.log("camera error: ", error) if (!isShowScanHand) { return setToastVisible(EToastVisible.upload_photo) } return handleToScanHand() } const handleCameraSuccess = (photo: string) => { onTakePhoto(photo) } const handleRequestCameraModalCancel = () => { setIsRequestCameraModalOpen(false) setToastVisible(EToastVisible.no_access_camera) } const handleRequestCameraModalAllow = () => { // if (isInstagramAndroid) { // return handleToScanHand() // } setIsCameraModalOpen(true) setIsRequestCameraModalOpen(false) } useEffect(() => { if (!isShowCameraRequestModal) { // if (isInstagramAndroid) { // return handleToScanHand() // } setIsCameraModalOpen(true) } }, [isShowCameraRequestModal]) useEffect(() => { (async () => { const permissionState = await checkCameraPermissionState(); if (permissionState === "denied") { handleToScanHand() } })() }, []) useEffect(() => { if (isInstagramAndroid) { metricService.reachGoal(EGoals.CAMERA_ANDROID_INSTAGRAM, [EMetrics.YANDEX, EMetrics.KLAVIYO]); } }, [isInstagramAndroid]) // LOGIC TODO: Make hook const onTakePhoto = async (photo: string) => { try { const file = DataURIToBlob(photo); const result = await getLines(file); URL.revokeObjectURL(URL.createObjectURL(file)); dispatch( actions.compatibilityV2.update({ photo, }) ); if (!checkPalmistryLines(result?.lines || [])) return; handleToScannedPhoto(); } catch (error) { console.error('Ошибка при обработке фото:', error); } finally { // Принудительный запуск сборщика мусора (не гарантировано, но может помочь) if (window.gc) { window.gc(); } } }; const fingersNames = { thumb: translate("thumb"), index_finger: translate("index_finger"), middle_finger: translate("middle_finger"), ring_finger: translate("ring_finger"), pinky: translate("pinky"), }; const setFingersNames = ( fingers: IPalmistryFinger[] ): ICompatibilityV2FingerLocal[] => { if (!fingers) return []; return fingers.map((finger) => { return { ...finger, fingerName: fingersNames[finger.name as keyof typeof fingersNames], }; }); }; const getLines = async (file: File | Blob) => { setIsLoading(true); const formData = new FormData(); formData.append("file", file); try { const result = await api.getPalmistryLines({ formData }); const fingers = setFingersNames(result?.fingers); dispatch( actions.compatibilityV2.update({ lines: result?.lines, fingers, }) ); return result; } catch (error) { dispatch( actions.compatibilityV2.update({ lines: [], fingers: [], }) ); return null; } finally { setIsLoading(false); } }; const checkPalmistryLines = (lines: IPalmistryLine[]): boolean => { if (!lines.length || lines.length < 2) { metricService.reachGoal(EGoals.CAMERA_ERROR, [EMetrics.YANDEX, EMetrics.KLAVIYO]); setToastVisible(EToastVisible.try_again); return false; } if (lines.length === 2) { setToastVisible(EToastVisible.try_again_or_next); return false; } return true; }; const onSelectFile = async (event: React.ChangeEvent) => { setToastVisible(null); if (!event.target.files || event.target.files.length === 0) return; const result = await getLines(event.target.files[0]); const reader = new FileReader(); reader.onloadend = () => { dispatch( actions.compatibilityV2.update({ photo: reader.result as string, }) ); if (!checkPalmistryLines(result?.lines || [])) return; handleToScannedPhoto(); }; reader.readAsDataURL(event.target.files[0]); }; if (!isReady) return ; return ( <> {/* Модальное окно запроса камеры */} { }} className={styles.modal} containerClassName={styles["modal-container"]} > {translate("/camera.modal.title")}

{translate("/camera.modal.cancel")}

{translate("/camera.modal.allow")}

{/* Модальное окно загрузки фото */} {/* {!isProduction && uploadMenuModalIsOpen && ( setUploadMenuModalIsOpen(false)} onSelectFile={onSelectFile} onChooseCamera={() => true} /> )} */} {/* Кнопка загрузки фото */} {/* {!isProduction && ( )} */} {/* Модальное окно камеры */} {!isLoading && console.log("close")} onTakePhoto={handleCameraSuccess} onError={handleCameraError} isCameraVisible={isCameraModalOpen} // reinitializeKey={reinitializeCameraCount} />} {/* Лоадер */} {isLoading && ( )} {/* Тост если фото плохое */} {toastVisible === EToastVisible.try_again && (
{translate("/camera.bad_photo")}
)} {/* Тост если нет доступа к камере */} {toastVisible === EToastVisible.no_access_camera && (
{translate("/camera.no_access_camera")}
)} {/* Тост загрузки фото */} {toastVisible === EToastVisible.upload_photo && (
{translate("/camera.no_access_camera")}
)} {/* Тост если фото можно улучшить */} {toastVisible === EToastVisible.try_again_or_next && (
{translate("/camera.do_better")}
)} ) } export default AndroidCamera;