import React, { useState, useEffect, useRef } from "react"; import { View, ScrollView, Keyboard, Platform, KeyboardAvoidingView, TouchableWithoutFeedback, Image, TouchableOpacity, Alert, } from "react-native"; import { Button } from "~/components/ui/button"; import { Input } from "~/components/ui/input"; import { Label } from "~/components/ui/label"; import { Text } from "~/components/ui/text"; import { router } from "expo-router"; import { ROUTES } from "~/lib/routes"; import { useAuthWithProfile } from "~/lib/hooks/useAuthWithProfile"; import { AuthService } from "~/lib/services/authServices"; import BackButton from "~/components/ui/backButton"; import WalletService from "~/lib/services/walletService"; import { fullNameSchema, emailSchema, pinSchema, confirmPinSchema, addressSchema, validate, } from "~/lib/utils/validationSchemas"; import { FCMService } from "~/lib/services/fcmService"; import { useAuthStore } from "~/lib/stores/authStore"; import ScreenWrapper from "~/components/ui/ScreenWrapper"; import ModalToast from "~/components/ui/toast"; import { useTranslation } from "react-i18next"; import * as ImagePicker from "expo-image-picker"; import { Icons } from "~/assets/icons"; import { Plus } from "lucide-react-native"; import { uploadProfileImage } from "~/lib/services/profileImageService"; export default function PhoneSetup() { const [fullName, setFullName] = useState(""); const [email, setEmail] = useState(""); const [address, setAddress] = useState(""); const [pin, setPin] = useState(""); const [confirmPin, setConfirmPin] = useState(""); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const { t } = useTranslation(); const { user, clearPhoneAuth, refreshProfile, refreshWallet } = useAuthWithProfile(); const { signOut } = useAuthStore(); const [profileImage, setProfileImage] = useState(null); console.log("PHONE SETUP PAGE LOADED, user:", user?.uid); 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); 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); }; // Redirect if no user is authenticated useEffect(() => { // In dev, allow the fake emulator user through without redirecting if (__DEV__ && user?.uid === "dev-emulator-user") { return; } if (!user) { console.log("NO USER FOUND, redirecting to signin"); router.replace(ROUTES.SIGNIN); } }, [user]); const handleSelectProfileImage = async () => { try { const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync(); if (!permissionResult.granted) { Alert.alert( "Permission Required", "Please allow access to your photo library to select a profile picture." ); return; } const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, allowsEditing: true, aspect: [1, 1], quality: 0.8, }); if (!result.canceled && result.assets[0]) { setProfileImage(result.assets[0].uri); } } catch (e) { showToast("Error", "Failed to select image", "error"); } }; const handleCompleteSetup = async () => { Keyboard.dismiss(); // Dev-only shortcut: on emulator/dev builds, skip profile setup and go straight home if (__DEV__) { console.log( "DEV phone setup bypass: skipping profile creation and navigating to HOME" ); router.replace(ROUTES.HOME); return; } // Validate full name const fullNameResult = validate(fullNameSchema, fullName); if (!fullNameResult.success) { showToast("Error", fullNameResult.error, "warning"); return; } // Validate email const emailResult = validate(emailSchema, email); if (!emailResult.success) { showToast("Error", emailResult.error, "warning"); return; } // Validate PIN const pinResult = validate(pinSchema, pin); if (!pinResult.success) { showToast("Error", pinResult.error, "warning"); return; } // Validate confirm PIN const confirmPinResult = validate(confirmPinSchema(pin), confirmPin); if (!confirmPinResult.success) { showToast("Error", confirmPinResult.error, "warning"); return; } // Validate address (optional) const addressResult = validate(addressSchema, address); if (!addressResult.success) { showToast("Error", addressResult.error, "warning"); return; } if (!user) { showToast( t("phoneSetup.toastNoUserTitle"), t("phoneSetup.toastNoUser"), "error" ); return; } setLoading(true); setError(null); try { let photoUrl: string | undefined; if (profileImage) { try { photoUrl = await uploadProfileImage(user.uid, profileImage); } catch (e) { console.warn("Failed to upload profile image during setup", e); } } await AuthService.createUserProfile(user.uid, { fullName: fullName.trim(), phoneNumber: user.phoneNumber || undefined, address: address.trim() || undefined, email: email.trim(), pin: pin.trim(), signupType: "phone", // Track that this user signed up with phone createdAt: new Date(), updatedAt: new Date(), photoUrl, }); // Initialize FCM token for new user (Android only) if (Platform.OS === "android") { try { const fcmResult = await FCMService.initializeTokenForNewUser( user.uid ); if (fcmResult.success) { console.log("FCM token initialized for new user"); } else { console.warn("Failed to initialize FCM token:", fcmResult.error); // Don't fail the setup if FCM fails } } catch (fcmError) { console.error("Error initializing FCM token:", fcmError); // Don't fail the setup if FCM fails } } // Create wallet for the user await WalletService.createUserWallet(user.uid); console.log("User wallet created successfully"); // Clear phone auth state clearPhoneAuth(); // Refresh profile and wallet to update auth context await refreshProfile(); await refreshWallet(); router.replace(ROUTES.HOME); } catch (error) { console.error("Profile setup error:", error); setError( error instanceof Error ? error.message : "Failed to complete setup" ); showToast( t("phoneSetup.validationErrorTitle"), t("phoneSetup.toastSetupError"), "error" ); } finally { setLoading(false); } }; // Show errors useEffect(() => { if (error) { showToast(t("phoneSetup.toastSetupErrorTitle"), error, "error"); } }, [error]); useEffect(() => { return () => { if (toastTimeoutRef.current) { clearTimeout(toastTimeoutRef.current); } }; }, []); if (!user) { return null; // Redirect handled in effect above } const handleBackPress = () => { showToast("Cancel Setup", "Are you sure you want to cancel?", "warning"); // Give user time to see the toast, then handle navigation setTimeout(async () => { try { clearPhoneAuth(); await signOut(); router.replace(ROUTES.SIGNIN); } catch (error) { console.error("Error signing out:", error); router.replace(ROUTES.SIGNIN); } }, 1500); }; return ( {t("phoneSetup.title")} {t("phoneSetup.subtitle")} {profileImage ? ( ) : ( )} ); }