import React, { useEffect, useRef, useState } from "react"; import { View, Text, TouchableOpacity, Share, ActivityIndicator, Platform, } from "react-native"; import { ArrowLeft } from "lucide-react-native"; import ScreenWrapper from "~/components/ui/ScreenWrapper"; import { Button } from "~/components/ui/button"; import { router } from "expo-router"; import ModalToast from "~/components/ui/toast"; import { useTranslation } from "react-i18next"; import QRCode from "react-native-qrcode-svg"; import { useAuthWithProfile } from "~/lib/hooks/useAuthWithProfile"; import { UserQrService } from "~/lib/services/userQrService"; import { CameraView, useCameraPermissions, type BarcodeScanningResult, } from "expo-camera"; import { ROUTES } from "~/lib/routes"; import BackButton from "~/components/ui/backButton"; export default function QRScreen() { const { t } = useTranslation(); const { user, profile, wallet } = useAuthWithProfile(); const [activeTab, setActiveTab] = useState<"scan" | "my">("scan"); const [toastVisible, setToastVisible] = useState(false); const [toastTitle, setToastTitle] = useState(""); const [toastDescription, setToastDescription] = useState( undefined ); const [toastVariant, setToastVariant] = useState< "success" | "error" | "warning" | "info" >("info"); const toastTimeoutRef = useRef | null>(null); // Scanner state const [hasPermission, setHasPermission] = useState(null); const [scanned, setScanned] = useState(false); const [permission, requestPermission] = useCameraPermissions(); const displayName = profile?.fullName || user?.displayName || t("profile.usernamePlaceholder"); const phoneNumber = profile?.phoneNumber || (user as any)?.phoneNumber || ""; const accountId = wallet?.uid || user?.uid || ""; const [qrPayload, setQrPayload] = useState(null); const showToast = ( title: string, description?: string, variant: "success" | "error" | "warning" | "info" = "info" ) => { if (toastTimeoutRef.current) { clearTimeout(toastTimeoutRef.current); } setToastTitle(title); setToastDescription(description); setToastVariant(variant); setToastVisible(true); toastTimeoutRef.current = setTimeout(() => { setToastVisible(false); toastTimeoutRef.current = null; }, 2500); }; useEffect(() => { return () => { if (toastTimeoutRef.current) { clearTimeout(toastTimeoutRef.current); } }; }, []); // Sync camera permission state for Scan tab useEffect(() => { if (Platform.OS === "web") { setHasPermission(false); return; } if (!permission) { return; } setHasPermission(permission.granted); }, [permission]); useEffect(() => { let isMounted = true; const loadQr = async () => { if (!user?.uid) return; try { const payload = await UserQrService.getOrCreateProfileQr({ uid: user.uid, accountId, name: displayName, phoneNumber, }); if (isMounted) { setQrPayload(payload); } } catch (error) { console.error("[QRScreen] Failed to load/create profile QR", error); } }; loadQr(); return () => { isMounted = false; }; }, [user?.uid, accountId, displayName, phoneNumber]); const handleBarCodeScanned = ({ data }: BarcodeScanningResult) => { if (scanned) return; try { setScanned(true); const parsed = JSON.parse(data); if (!parsed || parsed.type !== "AMBA_PROFILE") { showToast( "Invalid QR", "This is not a valid Amba profile QR.", "error" ); setScanned(false); return; } const accountIdFromQr: string | undefined = parsed.accountId; const nameFromQr: string | undefined = parsed.name; const phoneNumberFromQr: string | undefined = parsed.phoneNumber; if (!phoneNumberFromQr) { showToast( "Invalid QR", "This profile QR does not contain a phone number.", "error" ); setScanned(false); return; } router.push({ pathname: ROUTES.SEND_OR_REQUEST_MONEY, params: { selectedContactId: accountIdFromQr || phoneNumberFromQr, selectedContactName: nameFromQr || "User", selectedContactPhone: phoneNumberFromQr, }, }); } catch (error) { console.warn("[QRScreen] Failed to parse QR payload", error); showToast("Scan failed", "Could not read this QR code.", "error"); setScanned(false); } }; const handleShare = async () => { try { await Share.share({ message: t("qrscreen.shareMessage"), }); } catch (error) { console.log("Error sharing QR:", error); showToast( t("qrscreen.toastErrorTitle"), t("qrscreen.toastShareError"), "error" ); } }; const handleClose = () => { router.back(); }; return ( {/* Top back button */} {/* Tabs - match KYC style */} { setActiveTab("scan"); setScanned(false); }} className={`flex-1 items-center py-2 rounded-full ${ activeTab === "scan" ? "bg-white" : "bg-transparent" }`} activeOpacity={0.8} > {t("qrscreen.scanTabLabel", "Scan QR")} setActiveTab("my")} className={`flex-1 items-center py-2 rounded-full ${ activeTab === "my" ? "bg-white" : "bg-transparent" }`} activeOpacity={0.8} > {t("qrscreen.myTabLabel", "My QR")} {/* Tab content */} {activeTab === "my" ? ( <> {qrPayload ? ( ) : ( {t("qrscreen.loadingLabel", "Preparing your QR code...")} )} ) : ( {Platform.OS === "web" ? ( QR scanning is not supported on web. Please use a mobile device. ) : hasPermission === null ? ( Requesting camera permission... ) : hasPermission === false ? ( Camera permission needed Please grant camera access to scan profile QR codes. ) : ( Scan profile QR code Align the QR code inside the frame. We will automatically select the account and take you to the amount screen. )} )} ); }