Untitled
unknown
plain_text
16 days ago
25 kB
3
Indexable
import React, { useState, useRef, useEffect, useCallback } from "react"; import { Image, SafeAreaView, ScrollView, StatusBar, Text, TouchableOpacity, View, KeyboardAvoidingView, Platform, Modal, } from "react-native"; import tw from "twrnc"; import { useFocusEffect } from "@react-navigation/native"; import Config from "../../config"; import { useNavigation } from "@react-navigation/native"; import { Ionicons } from "@expo/vector-icons"; import { TextInput } from "react-native-gesture-handler"; import { useSelector } from "react-redux"; import axios from "axios"; const CheckoutScreen = ({ route, visible }) => { const navigation = useNavigation(); const [modalVisible, setModalVisible] = useState(false); // Controls offer price modal const [selectedOption, setSelectedOption] = useState("suggested"); const [phoneNumber, setPhoneNumber] = useState(""); const token = useSelector((state) => state?.user?.token); const [otp, setOtp] = useState(["", "", "", ""]); const [countdown, setCountdown] = useState(59); const { checkoutData } = route.params || {}; const [timerExpired, setTimerExpired] = useState(false); const [focusedIndex, setFocusedIndex] = useState(null); const [otpRequested, setOtpRequested] = useState(false); const inputRefs = useRef([]); const [shippingAddress, setShippingAddress] = useState(null); const [billingAddress, setBillingAddress] = useState(null); const addressesRef = useRef({ shipping: null, billing: null }); const handleOtpRequest = () => { if (!otpRequested) { // Call your OTP request function setModalVisible(true); setOtpRequested(true); // Update state to change button text } else { // Submit the OTP handleSubmit(); setModalVisible(false); } }; const handlePhoneNumberChange = (text) => { // Remove non-numeric characters and limit to 10 digits const formattedText = text.replace(/\D/g, "").slice(0, 10); setPhoneNumber(formattedText); }; const handleBack = () => { navigation.goBack(); }; const handleSubmit = () => { // setModalVisible(false); // Close offer price modal // setSubmittedModalVisible(true); // Open offer submitted modal }; useFocusEffect( useCallback(() => { if (route.params?.selectedAddress && route.params?.addressType) { const address = route.params.selectedAddress; const addressType = route.params.addressType; const formattedAddress = formatAddress(address); // Update the ref for the specific address type addressesRef.current[addressType] = formattedAddress; // Update the state if (addressType === 'shipping') { setShippingAddress(formattedAddress); } else if (addressType === 'billing') { setBillingAddress(formattedAddress); } } // If addresses are not set yet, try to use the ones from ref if (!shippingAddress && addressesRef.current.shipping) { setShippingAddress(addressesRef.current.shipping); } if (!billingAddress && addressesRef.current.billing) { setBillingAddress(addressesRef.current.billing); } // If addresses are still not available, fetch from API if (!shippingAddress && !addressesRef.current.shipping) { fetchShippingAddress(); } if (!billingAddress && !addressesRef.current.billing) { fetchBillingAddress(); } return () => { }; }, [route.params, shippingAddress, billingAddress]) ); // Split the fetch functions const fetchShippingAddress = async () => { if (!token) return; try { const response = await axios.get(`${Config.API_BASE_URL}/shippingAddress`, { headers: { Authorization: `Bearer ${token}`, }, }); if (response.data?.addresses && response.data?.addresses.length > 0) { const formattedAddress = formatAddress(response.data.addresses[0]); addressesRef.current.shipping = formattedAddress; setShippingAddress(formattedAddress); } } catch (error) { console.error("Failed to fetch shipping address:", error); } }; const fetchBillingAddress = async () => { if (!token) return; try { const response = await axios.get(`${Config.API_BASE_URL}/billingAddress`, { headers: { Authorization: `Bearer ${token}`, }, }); if (response.data?.addresses && response.data?.addresses.length > 0) { const formattedAddress = formatAddress(response.data.addresses[0]); addressesRef.current.billing = formattedAddress; setBillingAddress(formattedAddress); } } catch (error) { console.error("Failed to fetch billing address:", error); } }; const formatAddress = (addressData) => { return { name: addressData.name || "User", phone: addressData.phoneNumber, address: `${addressData.address1}${addressData.address2 ? `, ${addressData.address2}` : ''}${addressData.landmark ? `, ${addressData.landmark}` : ''}`, }; }; useEffect(() => { if (countdown > 0) { const timer = setTimeout(() => { setCountdown(countdown - 1); }, 1000); return () => clearTimeout(timer); } else { setTimerExpired(true); } }, [countdown]); const handleOtpChange = (value, index) => { const newOtp = [...otp]; if (/^[0-9]?$/.test(value)) { newOtp[index] = value; setOtp(newOtp); if (value && index < 3) { inputRefs.current[index + 1].focus(); } else if (!value && index > 0) { inputRefs.current[index - 1].focus(); } } }; const handleResendCode = () => { setOtp(["", "", "", ""]); setCountdown(59); setTimerExpired(false); console.log("Resending OTP code"); inputRefs.current[0].focus(); }; const handleKeyPress = (e, index) => { if (e.nativeEvent.key === "Backspace" && !otp[index] && index > 0) { inputRefs.current[index - 1].focus(); } }; const handleFocus = (index) => { setFocusedIndex(index); }; const handleBlur = () => { setFocusedIndex(null); }; const promoCodeApplied = true; const promoCode = "SAVE10"; const promoDescription = "Get 10% off on your order"; return ( <SafeAreaView style={tw`flex-1 bg-white`}> <StatusBar backgroundColor="#FDE504" /> <KeyboardAvoidingView behavior={Platform.OS === "ios" ? "padding" : "height"} style={tw`flex-1`} > <View style={tw`bg-[#FDE504] h-[48px]`}> <View style={tw`flex-row items-center px-4 pt-4 ml-2 `}> <TouchableOpacity onPress={handleBack}> <Ionicons name="chevron-back" size={24} color="black" /> </TouchableOpacity> </View> </View> <View style={tw`px-5 py-3`}> <Text style={[tw`text-base `, { fontFamily: "Karla-Bold" }]}> Order Details </Text> </View> <ScrollView style={tw`flex-1`} contentContainerStyle={tw`pb-4 flex-grow`} > <View style={tw`w-full border-b-4 border-[#FFFBE1] mb-2`} /> <View style={tw`w-full py-[22px]`}> {/* Shipping Address Section */} <View style={tw`flex-row justify-between px-5`}> <Text style={[ tw`text-center text-neutral-900 text-base leading-tight`, { fontFamily: "Karla-Bold" }, ]} > Shipping Address </Text> {shippingAddress && ( <TouchableOpacity onPress={() => navigation.navigate("EditAddress", { type: "shipping" })} > <Text style={[ tw`text-center text-neutral-900 text-[12px] leading-tight`, { fontFamily: "Karla-Bold" }, ]} > Change </Text> </TouchableOpacity> )} </View> {shippingAddress ? ( <View style={tw`h-20 border rounded-[12px] border-gray-200 ml-[16px] mr-4 mt-[12px] mb-[22px] p-4 flex justify-start items-start`} > <Text style={[ tw`text-neutral-900 text-sm mb-2`, { fontFamily: "Karla-Bold" }, ]} > Phone - {shippingAddress.phone} </Text> <Text style={[ tw`text-neutral-400 text-xs `, { fontFamily: "Karla-Regular" }, ]} > {shippingAddress.address} </Text> </View> ) : ( <TouchableOpacity style={tw`h-20 border rounded-[12px] border-gray-200 ml-[16px] mr-4 mt-[12px] mb-[22px] p-4 flex-row justify-start items-center gap-[20px]`} onPress={() => navigation.navigate("AddAddress", { type: "shipping" })} > <Text style={tw`text-2xl text-[#1F2125] mr-4`}>+</Text> <Text style={tw`text-base text-black`}> Add Shipping Address </Text> </TouchableOpacity> )} {/* Billing Address Section */} <View style={tw`flex-row justify-between px-5`}> <Text style={[ tw`text-center text-neutral-900 text-base leading-tight`, { fontFamily: "Karla-Bold" }, ]} > Billing Address </Text> {billingAddress && ( <TouchableOpacity onPress={() => navigation.navigate("EditAddress", { type: "billing" })} > <Text style={[ tw`text-center text-neutral-900 text-[12px] leading-tight`, { fontFamily: "Karla-Bold" }, ]} > Change </Text> </TouchableOpacity> )} </View> {billingAddress ? ( <View style={tw`h-20 border rounded-[12px] border-gray-200 ml-[16px] mr-4 mt-[12px] mb-[22px] p-4 flex justify-start items-start`} > <Text style={[ tw`text-neutral-900 text-sm mb-2`, { fontFamily: "Karla-Bold" }, ]} > Phone - {billingAddress.phone} </Text> <Text style={[ tw`text-neutral-400 text-xs `, { fontFamily: "Karla-Regular" }, ]} > {billingAddress.address} </Text> </View> ) : ( <TouchableOpacity style={tw`h-15 border rounded-[12px] border-gray-200 ml-[16px] mr-4 mt-[12px] mb-[22px] p-4 flex-row justify-start items-center gap-[20px]`} onPress={() => navigation.navigate("AddAddress", { type: "billing" })} > <Text style={tw`text-3xl text-[#1F2125] mr-4`}>+</Text> <Text style={[ tw`text-base text-black`, { fontFamily: "Karla-Regular" }, ]} > Add Billing Address </Text> </TouchableOpacity> )} <View style={tw`w-full border-b-4 border-[#FFFBE1] mb-2`} /> </View> <View style={tw`w-full pb-[22px]`}> <View style={tw`flex-row justify-between px-5`}> <Text style={[ tw`text-center text-neutral-900 text-base leading-tight`, { fontFamily: "Karla-Bold" }, ]} > Payment Method </Text> <Text style={[ tw`text-center text-neutral-900 text-[12px] leading-tight`, { fontFamily: "Karla-Bold" }, ]} > See All </Text> </View> <View style={tw`h-20 border rounded-[12px] border-gray-200 ml-[16px] mr-4 mt-[12px] mb-[22px] p-4 flex-row justify-start items-center gap-[20px]`} > <View> <Image source={require("../../assets/checkout/mastercard.png")} style={tw`h-7 w-10`} /> </View> <View> <Text style={[ tw`text-neutral-900 text-sm mb-1`, { fontFamily: "Karla-Bold" }, ]} > Mastercard </Text> <Text style={[ tw`text-neutral-400 text-xs`, { fontFamily: "Karla-Regular" }, ]} > Checked Automatically </Text> </View> </View> <View style={tw`w-full border-b-4 border-[#FFFBE1] mb-2`} /> </View> <View style={tw`w-full pb-[22px]`}> <View style={tw`flex-row justify-between px-5`}> <Text style={[ tw`text-center text-neutral-900 text-base leading-tight`, { fontFamily: "Karla-Bold" }, ]} > Voucher </Text> </View> <View style={tw`w-full py-[12px]`}> {/* Promo Code Section */} {promoCodeApplied ? ( <View style={tw`h-15 border rounded-[12px] border-gray-200 ml-[16px] mr-4 mt-[12px] mb-[22px] p-4 flex-row justify-start items-center gap-[20px]`} > <View> <Image source={require("../../assets/checkout/Discount.png")} style={tw`h-5 w-5`} /> </View> <View> <Text style={[ tw`text-[#1F2125] text-sm mb-1`, { fontFamily: "Karla-Bold" }, ]} > One promo was applied </Text> </View> <View style={tw`flex-row items-center px-4 ml-12`}> <TouchableOpacity onPress={handleBack}> <Ionicons name="chevron-forward" size={24} color="black" /> </TouchableOpacity> </View> </View> ) : ( <TouchableOpacity style={tw`h-15 border rounded-[12px] border-gray-200 ml-[16px] mr-4 mt-[12px] mb-[22px] p-4 flex-row justify-start items-center gap-[20px]`} onPress={() => navigation.navigate("Coupons")} > <Text style={tw`text-3xl text-[#1F2125]`}>+</Text> <Text style={[ tw`text-base text-black`, { fontFamily: "Karla-Regular" }, ]} > Apply Promo Code </Text> </TouchableOpacity> )} </View> <View> <View style={tw`flex-row justify-between px-4 mt-[50px]`}> <Text style={[ tw`text-neutral-900 text-sm `, { fontFamily: "Karla-Regular" }, ]} > Unit Cost </Text> <Text style={[ tw`text-right text-neutral-900 text-sm leading-none`, { fontFamily: "Karla-Bold" }, ]} > {checkoutData?.totalAmount || "0"} د.إ </Text> </View> <View style={tw`flex-row justify-between px-4 mt-[11px]`}> <Text style={[ tw`text-neutral-900 text-sm `, { fontFamily: "Karla-Regular" }, ]} > Qty </Text> <Text style={[ tw`text-right text-neutral-900 text-sm leading-none`, { fontFamily: "Karla-Bold" }, ]} > {checkoutData?.totalQuantity || "0"} </Text> </View> <View style={tw`flex-row justify-between px-4 mt-[11px]`}> <Text style={[ tw`text-neutral-900 text-sm `, { fontFamily: "Karla-Regular" }, ]} > Discount </Text> <Text style={[ tw`text-right text-[#30BD75] text-sm leading-none`, { fontFamily: "Karla-Bold" }, ]} > {checkoutData?.discountAmount || "0"} د.إ - </Text> </View> <View style={tw`flex-row justify-between px-4 mt-[11px]`}> <Text style={[ tw`text-neutral-900 text-sm `, { fontFamily: "Karla-Regular" }, ]} > Shipping Cost </Text> <Text style={[ tw`text-right text-neutral-900 text-sm leading-none`, { fontFamily: "Karla-Bold" }, ]} > 20 د.إ </Text> </View> <View style={tw`border-t border-dashed border-gray-300 my-2 ml-4 mr-4 mt-[11px]`} /> <View style={tw`flex-row justify-between px-4 mt-[20px]`}> <Text style={[ tw`text-neutral-900 text-base `, { fontFamily: "Karla-Bold" }, ]} > Total </Text> <Text style={tw`text-right text-neutral-900 text-sm font-bold leading-none`} > {checkoutData?.finalTotal || "0"} د.إ </Text> </View> </View> </View> </ScrollView> <View style={tw`p-4`}> <TouchableOpacity style={tw`bg-[#FDE504] p-[15px] rounded-xl`}> <Text style={[ tw`text-center text-[16px]`, { fontFamily: "Karla-Bold" }, ]} > Checkout </Text> </TouchableOpacity> </View> </KeyboardAvoidingView> <Modal animationType="slide" transparent={true} visible={modalVisible} onRequestClose={() => setModalVisible(false)} > <View style={tw`flex-1 justify-end`}> <View style={tw`bg-black bg-opacity-50 absolute inset-0`} /> <View style={tw`items-center mb-4`}> <TouchableOpacity style={tw`bg-gray-300 rounded-full p-2 mt-2`} onPress={() => setModalVisible(false)} > <Ionicons name="close" size={20} color="#000" /> </TouchableOpacity> </View> <View style={tw`bg-white rounded-t-[20px] p-4 mt-[22px]`}> <View style={tw`mb-[12px]`}> <Text style={[tw`text-[22px] text-[#070707] mb-1`, { fontFamily: "Karla-Bold" }]}> Verify Your Phone Number </Text> <Text style={[tw`text-[14px] w-[328px] h-[44px]`, { fontFamily: "Karla-Regular" }]}> To use KUKU, we need to verify your phone number. We will never display this number publicly. </Text> </View> <View style={tw`flex-row border border-gray-200 rounded-[12px] px-4 items-center mb-5 bg-[#F7F7F7] h-[56px]`} > <View style={tw`flex-row items-center pr-2 border-r border-r-gray-200`} > <Image source={require("../../assets/login/uae-flag.png")} style={tw`w-4 h-2.5 mr-1`} /> <Text style={[tw`text-gray-700 text-sm mr-1`, { fontFamily: "Karla-Regular" }]}>+971</Text> <Ionicons name="chevron-down" size={12} color="#666" /> </View> <TextInput placeholder="Phone Number" style={[tw`flex-1 pl-2 text-gray-700 text-base`, { fontFamily: "Karla-Regular" }]} keyboardType="phone-pad" placeholderTextColor="#999" value={phoneNumber} onChangeText={handlePhoneNumberChange} maxLength={10} // Ensures max length of 10 /> </View> <View style={tw`flex-row justify-center gap-4 mb-4 mt-[16px]`}> {otp.map((digit, index) => ( <View key={index} style={[ tw`w-16 h-16 border-2 rounded-lg justify-center items-center `, { backgroundColor: "#F7F7F7", borderColor: digit || focusedIndex === index ? "#FFEB3B" : "#E0E0E0", }, ]} > <TextInput ref={(el) => (inputRefs.current[index] = el)} style={[ tw`text-xl font-bold w-full h-full`, { textAlign: "center", textAlignVertical: "start" }, ]} keyboardType="number-pad" maxLength={1} value={digit} onChangeText={(value) => handleOtpChange(value, index)} onKeyPress={(e) => handleKeyPress(e, index)} onFocus={() => handleFocus(index)} onBlur={handleBlur} selectTextOnFocus placeholder="0" placeholderTextColor="#e5e5e5" /> </View> ))} </View> {timerExpired ? ( <View style={tw`flex-row justify-center mb-8`}> <Text style={[tw`text-gray-500 text-sm`, { fontFamily: "Karla-Regular" }]}> Didn't received code?{" "} </Text> <TouchableOpacity onPress={handleResendCode}> <Text style={[tw`text-gray-800 text-sm`, { fontFamily: "Karla-SemiBold" }]}> Resend Code </Text> </TouchableOpacity> </View> ) : ( <Text style={[tw`text-center text-gray-800 w-[328px] h-[52px] mb-8`, { fontFamily: "Karla-Regular" }]} > You can resend code in {countdown} sec </Text> )} <TouchableOpacity style={tw`bg-[#FDE504] rounded-lg py-4 items-center mb-4 h-[56px]`} onPress={handleOtpRequest} > <Text style={tw`text-karla-700 font-medium text-[16px]`}> {otpRequested ? "Submit" : "Get OTP"} </Text> </TouchableOpacity> </View> </View> </Modal> </SafeAreaView> ); }; export default CheckoutScreen;
Editor is loading...
Leave a Comment