Merge branch 'develop' into 'main'

AW-429-comp-v1-ios-ab

See merge request witapp/aura-webapp!728
This commit is contained in:
Daniil Chemerkin 2025-04-13 21:24:15 +00:00
commit 7d60bd2d3e
11 changed files with 72 additions and 35 deletions

View File

@ -5,7 +5,7 @@
<script> <script>
const ua = window.navigator.userAgent; const ua = window.navigator.userAgent;
if ( if (
ua.includes("Instagram") ua.includes("Instagram")// || ua.includes("FBAN") || ua.includes("FBAV") || ua.includes("FBIOS")
) { ) {
if (/iPad|iPhone|iPod/.test(ua)) { if (/iPad|iPhone|iPod/.test(ua)) {
window.location.href = "x-safari-" + window.location.href; window.location.href = "x-safari-" + window.location.href;

View File

@ -21,6 +21,7 @@ interface CameraModalProps {
onClose: () => void; onClose: () => void;
onTakePhoto: (photo: string) => void; onTakePhoto: (photo: string) => void;
onError: (error: string | DOMException) => void; onError: (error: string | DOMException) => void;
onVideoReady?: () => void;
reinitializeKey?: number; // for reinitializing the camera (change the key to reinitialize the camera) reinitializeKey?: number; // for reinitializing the camera (change the key to reinitialize the camera)
isCameraVisible?: boolean; isCameraVisible?: boolean;
} }
@ -29,6 +30,7 @@ function CameraModal({
onClose, onClose,
onTakePhoto, onTakePhoto,
onError, onError,
onVideoReady,
reinitializeKey = 0, reinitializeKey = 0,
isCameraVisible = true isCameraVisible = true
}: CameraModalProps) { }: CameraModalProps) {
@ -81,6 +83,7 @@ function CameraModal({
const onUserMedia = (stream: MediaStream) => { const onUserMedia = (stream: MediaStream) => {
setIsVideoReady(true); setIsVideoReady(true);
onVideoReady?.();
const track = stream.getVideoTracks()[0]; const track = stream.getVideoTracks()[0];
if (track) { if (track) {
checkTorchAvailability(track); checkTorchAvailability(track);

View File

@ -19,6 +19,7 @@ import { DataURIToBlob } from "@/services/data";
import metricService, { EGoals, EMetrics } from "@/services/metric/metricService"; import metricService, { EGoals, EMetrics } from "@/services/metric/metricService";
import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash"; import { EUnleashFlags, useUnleash } from "@/hooks/ab/unleash/useUnleash";
import { checkCameraPermissionState } from "@/services/permission/permisson"; import { checkCameraPermissionState } from "@/services/permission/permisson";
import { isAndroid, isWebView } from "@/services/hacks/webviewToSystemBrowser";
enum EToastVisible { enum EToastVisible {
"try_again" = "try_again", "try_again" = "try_again",
@ -28,7 +29,7 @@ enum EToastVisible {
"upload_photo" = "upload_photo", "upload_photo" = "upload_photo",
} }
const isInstagramAndroid = window?.navigator?.userAgent?.includes("Instagram") && /Android/.test(window?.navigator?.userAgent); const isWebViewAndroid = isWebView() && isAndroid;
function AndroidCamera() { function AndroidCamera() {
const api = useApi(); const api = useApi();
@ -48,10 +49,17 @@ function AndroidCamera() {
const isShowScanHand = compatibilityV2ScanHand !== "hide"; const isShowScanHand = compatibilityV2ScanHand !== "hide";
const { variant: compatibilityV2TimeForCameraInit } = useUnleash({
flag: EUnleashFlags.compatibilityV2TimeForCameraInit
});
const timeForCameraInit = Number(compatibilityV2TimeForCameraInit) || 6000;
const [isCameraModalOpen, setIsCameraModalOpen] = useState(false); const [isCameraModalOpen, setIsCameraModalOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [isRequestCameraModalOpen, setIsRequestCameraModalOpen] = useState(isShowCameraRequestModal); const [isRequestCameraModalOpen, setIsRequestCameraModalOpen] = useState(isShowCameraRequestModal);
const [toastVisible, setToastVisible] = useState<EToastVisible | null>(null); const [toastVisible, setToastVisible] = useState<EToastVisible | null>(null);
const [isVideoReady, setIsVideoReady] = useState(false);
const handleToScanHand = () => { const handleToScanHand = () => {
metricService.reachGoal(EGoals.SCAN_ARTIFICIAL_PHOTO, [EMetrics.YANDEX, EMetrics.KLAVIYO]); metricService.reachGoal(EGoals.SCAN_ARTIFICIAL_PHOTO, [EMetrics.YANDEX, EMetrics.KLAVIYO]);
@ -75,23 +83,39 @@ function AndroidCamera() {
onTakePhoto(photo) onTakePhoto(photo)
} }
const handleRequestCameraModalCancel = () => { const handleRequestCameraModalCancel = () => {
setIsRequestCameraModalOpen(false) setIsRequestCameraModalOpen(false)
setToastVisible(EToastVisible.no_access_camera) setToastVisible(EToastVisible.no_access_camera)
} }
const handleRequestCameraModalAllow = () => { const handleRequestCameraModalAllow = () => {
// if (isInstagramAndroid) { // if (isWebViewAndroid) {
// return handleToScanHand() // return handleToScanHand()
// } // }
setIsCameraModalOpen(true) setIsCameraModalOpen(true)
setIsRequestCameraModalOpen(false) setIsRequestCameraModalOpen(false)
} }
useEffect(() => {
if (!isCameraModalOpen || !isWebViewAndroid || !isReady || compatibilityV2TimeForCameraInit === "disabled") return;
const timer = setTimeout(() => {
if (isShowScanHand) {
handleToScanHand();
} else {
setToastVisible(EToastVisible.upload_photo)
}
}, timeForCameraInit);
if (isVideoReady) {
clearTimeout(timer);
}
return () => clearTimeout(timer);
}, [isCameraModalOpen, isVideoReady, isReady, timeForCameraInit])
useEffect(() => { useEffect(() => {
if (!isShowCameraRequestModal) { if (!isShowCameraRequestModal) {
// if (isInstagramAndroid) { // if (isWebViewAndroid) {
// return handleToScanHand() // return handleToScanHand()
// } // }
setIsCameraModalOpen(true) setIsCameraModalOpen(true)
@ -108,10 +132,10 @@ function AndroidCamera() {
}, []) }, [])
useEffect(() => { useEffect(() => {
if (isInstagramAndroid) { if (isWebViewAndroid) {
metricService.reachGoal(EGoals.CAMERA_ANDROID_INSTAGRAM, [EMetrics.YANDEX, EMetrics.KLAVIYO]); metricService.reachGoal(EGoals.CAMERA_ANDROID_INSTAGRAM, [EMetrics.YANDEX, EMetrics.KLAVIYO]);
} }
}, [isInstagramAndroid]) }, [isWebViewAndroid])
// LOGIC TODO: Make hook // LOGIC TODO: Make hook
@ -275,6 +299,7 @@ function AndroidCamera() {
onTakePhoto={handleCameraSuccess} onTakePhoto={handleCameraSuccess}
onError={handleCameraError} onError={handleCameraError}
isCameraVisible={isCameraModalOpen} isCameraVisible={isCameraModalOpen}
onVideoReady={() => setIsVideoReady(true)}
// reinitializeKey={reinitializeCameraCount} // reinitializeKey={reinitializeCameraCount}
/>} />}
@ -317,7 +342,7 @@ function AndroidCamera() {
<span>{translate("/camera.no_access_camera")}</span> <span>{translate("/camera.no_access_camera")}</span>
<div className={styles["toast-buttons-container"]}> <div className={styles["toast-buttons-container"]}>
<button onClick={() => { <button onClick={() => {
// if (isInstagramAndroid) { // if (isWebViewAndroid) {
// return handleToScanHand() // return handleToScanHand()
// } // }
setToastVisible(null) setToastVisible(null)

View File

@ -103,7 +103,7 @@ function GenderPage() {
useEffect(() => { useEffect(() => {
if (privacyPolicyChecked && gender && isSelected) { if (privacyPolicyChecked && gender && isSelected) {
webviewToSystemBrowser(["android"]); webviewToSystemBrowser(["android", "ios"]);
handleNext(); handleNext();
} }
}, [gender, handleNext, isSelected, privacyPolicyChecked]); }, [gender, handleNext, isSelected, privacyPolicyChecked]);

View File

@ -96,8 +96,8 @@ function GenderPage() {
useEffect(() => { useEffect(() => {
if (privacyPolicyChecked && gender && isSelected) { if (privacyPolicyChecked && gender && isSelected) {
webviewToSystemBrowser(["android"]); webviewToSystemBrowser(["android", "ios"]);
handleNext(); handleNext();
} }
}, [gender, handleNext, isSelected, privacyPolicyChecked]); }, [gender, handleNext, isSelected, privacyPolicyChecked]);

View File

@ -94,7 +94,7 @@ function GenderPage() {
useEffect(() => { useEffect(() => {
if (privacyPolicyChecked && gender && isSelected) { if (privacyPolicyChecked && gender && isSelected) {
webviewToSystemBrowser(["android"]); webviewToSystemBrowser(["android", "ios"]);
handleNext(); handleNext();
} }
}, [gender, handleNext, isSelected, privacyPolicyChecked]); }, [gender, handleNext, isSelected, privacyPolicyChecked]);

View File

@ -84,7 +84,7 @@ function GenderPalmistry() {
useEffect(() => { useEffect(() => {
if (privacyPolicyChecked && gender && isSelected) { if (privacyPolicyChecked && gender && isSelected) {
webviewToSystemBrowser(["android"]); webviewToSystemBrowser(["android", "ios"]);
handleNext(); handleNext();
} }
}, [gender, handleNext, isSelected, privacyPolicyChecked]); }, [gender, handleNext, isSelected, privacyPolicyChecked]);

View File

@ -25,7 +25,8 @@ export enum EUnleashFlags {
"compatibilityV1EmailEnter" = "compatibilityV1EmailEnter", "compatibilityV1EmailEnter" = "compatibilityV1EmailEnter",
"compatibilityV2ScanHand" = "compatibilityV2ScanHand", "compatibilityV2ScanHand" = "compatibilityV2ScanHand",
"preloadImages" = "preloadImages", "preloadImages" = "preloadImages",
"scanHandTimeCompatibilityV2" = "scanHandTimeCompatibilityV2" "scanHandTimeCompatibilityV2" = "scanHandTimeCompatibilityV2",
"compatibilityV2TimeForCameraInit" = "compatibilityV2TimeForCameraInit"
} }
interface IUseUnleashProps<T extends EUnleashFlags> { interface IUseUnleashProps<T extends EUnleashFlags> {
@ -56,6 +57,7 @@ interface IVariants {
[EUnleashFlags.compatibilityV2ScanHand]: "show" | "hide"; [EUnleashFlags.compatibilityV2ScanHand]: "show" | "hide";
[EUnleashFlags.preloadImages]: "yes" | "no"; [EUnleashFlags.preloadImages]: "yes" | "no";
[EUnleashFlags.scanHandTimeCompatibilityV2]: "v0" | "v1"; [EUnleashFlags.scanHandTimeCompatibilityV2]: "v0" | "v1";
[EUnleashFlags.compatibilityV2TimeForCameraInit]: string;
} }
/** /**

View File

@ -70,6 +70,7 @@ export const useUploadImage = ({
}; };
const result = await getLines(event.target.files[0]); const result = await getLines(event.target.files[0]);
const lines = result?.lines; const lines = result?.lines;
const reader = new FileReader(); const reader = new FileReader();

View File

@ -21,12 +21,15 @@ export const useSession = () => {
const [isError, setIsError] = useState(false); const [isError, setIsError] = useState(false);
const createSession = useCallback(async (source: ESourceAuthorization): Promise<ResponseCreate> => { const createSession = useCallback(async (source: ESourceAuthorization): Promise<ResponseCreate> => {
if (session[source]?.length) return { if (session[source]?.length) {
sessionId: session[source], localStorage.setItem(`${source}_sessionId`, session[source]);
status: "old" return {
sessionId: session[source],
status: "old"
}
}; };
try { try {
const session = await api.createSession({ const sessionFromServer = await api.createSession({
feature, feature,
locale: language, locale: language,
timezone, timezone,
@ -35,13 +38,13 @@ export const useSession = () => {
signDate: dateOfCheck.length ? dateOfCheck : undefined, signDate: dateOfCheck.length ? dateOfCheck : undefined,
utm utm
}); });
if (session?.sessionId?.length && session?.status === "success") { if (sessionFromServer?.sessionId?.length && sessionFromServer?.status === "success") {
dispatch(actions.session.update({ dispatch(actions.session.update({
session: session.sessionId, session: sessionFromServer.sessionId,
source source
})); }));
localStorage.setItem(`${source}_sessionId`, session.sessionId); localStorage.setItem(`${source}_sessionId`, sessionFromServer.sessionId);
return session return sessionFromServer
} }
setIsError(true); setIsError(true);
return { return {

View File

@ -1,14 +1,17 @@
export const webviewToSystemBrowser = (includeSystems: Array<"android" | "ios">) => { const ua = window.navigator.userAgent;
const ua = window.navigator.userAgent;
if ( export const isAndroid = /Android/.test(ua)
ua.includes("Instagram") ||
ua.includes("FBAN") || export const isWebView = () => {
ua.includes("FBAV") return ua.includes("Instagram") || ua.includes("FBAN") || ua.includes("FBAV") || ua.includes("FBIOS");
) {
if (includeSystems.includes("ios") && /iPad|iPhone|iPod/.test(ua)) {
window.location.href = "x-safari-" + window.location.href;
} else if (includeSystems.includes("android") && /Android/.test(ua)) {
window.location.href = "intent:" + window.location.href + "#Intent;end";
}
}
} }
export const webviewToSystemBrowser = (includeSystems: Array<"android" | "ios">) => {
if (!isWebView()) return;
if (includeSystems.includes("ios") && /iPad|iPhone|iPod/.test(ua)) {
window.location.href = "x-safari-" + window.location.href;
} else if (includeSystems.includes("android") && /Android/.test(ua)) {
window.location.href = "intent:" + window.location.href + "#Intent;end";
}
}