You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

918 lines
28 KiB

import React from "react";
import {
View,
Text,
TextInput,
Image,
TouchableOpacity,
StyleSheet,
KeyboardAvoidingView,
Platform,
ActivityIndicator,
4 weeks ago
Modal,
FlatList,
Dimensions,
3 weeks ago
StatusBar,
SafeAreaView,
ScrollView
} from "react-native";
import { useState } from "react";
3 weeks ago
import AsyncStorage from "@react-native-async-storage/async-storage";
import BackIcon from "../../components/BackIcon";
import { useNavigation, useRoute, RouteProp } from "@react-navigation/native";
import { AddressItem } from "../../services/api/addressApi";
import { useAddressStore } from "../../store/address";
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
4 weeks ago
import { settingApi } from "../../services/api/setting";
import flagMap from "../../utils/flagMap";
import useCreateOrderStore from "../../store/createOrder";
type RootStackParamList = {
4 weeks ago
AddRess: { address?: AddressItem; cart_item_id?: number | string };
AddressList: undefined;
4 weeks ago
ShippingFee: { cart_item_id : {}};
};
type AddRessRouteProp = RouteProp<RootStackParamList, "AddRess">;
4 weeks ago
export const PreviewAddress = () => {
const {
defaultAddress,
fetchDefaultAddress,
loading,
} = useAddressStore();
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
const route = useRoute<AddRessRouteProp>();
const [open, setOpen] = useState(false);
const [value, setValue] = useState<string | null>(null);
4 weeks ago
const [items, setItems] = useState<{label: string; value: string}[]>([]);
const [selectedCountryLabel, setSelectedCountryLabel] = useState<string>("");
const [countryList, setCountryList] = useState<any[]>([]);
const { setOrderData ,orderData} = useCreateOrderStore();
const [formData, setFormData] = useState({
receiver_first_name: "",
receiver_last_name: "",
country: "",
receiver_phone: "",
receiver_phone_again: "",
whatsapp_phone: "",
is_default: false,
});
const [selectedCountry, setSelectedCountry] = useState<any>(null);
const [isDefault, setIsDefault] = useState(false);
const [copyPhoneToWhatsApp, setCopyPhoneToWhatsApp] = useState(false);
const [phoneNumbersMatch, setPhoneNumbersMatch] = useState(true);
const [errors, setErrors] = useState<Record<string, string>>({});
// 获取选中的国家数据
const fetchSelectedCountry = async () => {
try {
const countryData = await AsyncStorage.getItem("@selected_country");
if (countryData) {
const parsedData = JSON.parse(countryData);
setSelectedCountry(parsedData);
setValue(parsedData.name);
}
} catch (error) {
console.error("Error fetching selected country:", error);
}
};
// 初始化加载
React.useEffect(() => {
fetchSelectedCountry();
fetchDefaultAddress();
// 如果有路由参数中的地址,优先使用它
if (route.params?.address) {
setFormData({
...route.params.address,
receiver_phone_again: route.params.address.receiver_phone,
is_default: Boolean(route.params.address.is_default),
});
// 设置国家下拉框的默认值为地址的country
setValue(route.params.address.country || null);
}
}, []);
4 weeks ago
// 当countryList加载完成后,设置选中的国家标签
React.useEffect(() => {
4 weeks ago
if (countryList.length > 0) {
// 如果有路由参数中的地址
const addressFromRoute = route.params?.address;
if (addressFromRoute && addressFromRoute.country) {
const selectedCountry = countryList.find(item =>
item.name_en === addressFromRoute.country ||
item.value === addressFromRoute.country
);
if (selectedCountry) {
setSelectedCountryLabel(selectedCountry.label);
setValue(selectedCountry.value);
}
}
// 如果没有路由参数但有默认地址
else if (defaultAddress && defaultAddress.country && !route.params?.address) {
const selectedCountry = countryList.find(item =>
item.name_en === defaultAddress.country ||
item.value === defaultAddress.country
);
if (selectedCountry) {
setSelectedCountryLabel(selectedCountry.label);
setValue(selectedCountry.value);
}
}
}
4 weeks ago
}, [countryList, route.params?.address, defaultAddress]);
// 监听手机号码变化,如果勾选了复制选项则自动更新 WhatsApp 号码
React.useEffect(() => {
if (copyPhoneToWhatsApp) {
setFormData((prev) => ({
...prev,
whatsapp_phone: prev.receiver_phone,
}));
}
}, [formData.receiver_phone, copyPhoneToWhatsApp]);
// 监听手机号码变化,验证两次输入是否一致
React.useEffect(() => {
if (formData.receiver_phone && formData.receiver_phone_again) {
setPhoneNumbersMatch(
formData.receiver_phone === formData.receiver_phone_again
);
} else {
setPhoneNumbersMatch(true);
}
}, [formData.receiver_phone, formData.receiver_phone_again]);
4 weeks ago
// 监听defaultAddress变化
React.useEffect(() => {
if (defaultAddress && !route.params?.address) {
setFormData({
receiver_first_name: defaultAddress.receiver_first_name || "",
receiver_last_name: defaultAddress.receiver_last_name || "",
country: defaultAddress.country || "",
receiver_phone: defaultAddress.receiver_phone || "",
receiver_phone_again: defaultAddress.receiver_phone || "",
whatsapp_phone: defaultAddress.whatsapp_phone || "",
is_default: Boolean(defaultAddress.is_default),
});
setValue(defaultAddress.country || null);
}
}, [defaultAddress, route.params?.address]);
React.useEffect(() => {
settingApi.getCountryList().then((res) => {
const formattedCountries = res.map((item) => ({
label: `${item.name_en} (${item.country})`,
value: item.name.toString(),
flag: flagMap.get(item.name_en),
name_en: item.name_en,
country: item.country
}));
setItems(formattedCountries);
setCountryList(formattedCountries);
});
}, []);
const validateForm = () => {
const newErrors: Record<string, string> = {};
if (!formData.receiver_first_name) {
newErrors.receiver_first_name = "请输入名";
}
if (!formData.receiver_last_name) {
newErrors.receiver_last_name = "请输入姓";
}
if (!formData.receiver_phone) {
newErrors.receiver_phone = "请输入手机号码";
}
if (!formData.receiver_phone_again) {
newErrors.receiver_phone_again = "请再次输入手机号码";
}
if (formData.receiver_phone !== formData.receiver_phone_again) {
newErrors.receiver_phone_again = "两次输入的手机号码不一致";
}
if (!formData.whatsapp_phone) {
newErrors.whatsapp_phone = "请输入WhatsApp号码";
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = async () => {
4 weeks ago
if (validateForm()) {
console.log(defaultAddress);
setOrderData({
...orderData,
address_id: defaultAddress?.address_id,
});
navigation.navigate("ShippingFee",{
cart_item_id: route.params,
});
}
};
4 weeks ago
const handleCountrySelect = (item: any) => {
setValue(item.value);
setSelectedCountryLabel(item.label);
setOpen(false);
};
return (
3 weeks ago
<SafeAreaView style={[styles.safeArea]}>
<StatusBar barStyle="dark-content" backgroundColor="#fff" />
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={styles.safeAreaContent}
>
<ScrollView style={styles.container} contentContainerStyle={styles.scrollContainer}>
3 weeks ago
{loading ? (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#f77f3a" />
</View>
) : (
<View style={styles.recipientFormContainer3}>
<View>
<View style={styles.recipientFormContainer1}>
<View style={styles.recipientFormContainer2}>
<View style={styles.titleContainer}>
<View style={styles.backIconContainer}>
<TouchableOpacity onPress={() => navigation.goBack()}>
<BackIcon size={20} />
</TouchableOpacity>
</View>
3 weeks ago
<Text style={styles.titleHeading}></Text>
</View>
3 weeks ago
<View style={styles.recipientInfoForm}>
<View style={styles.recipientInfoHeadingContainer}>
<Text style={styles.recipientInfoHeading}></Text>
<TouchableOpacity onPress={() => navigation.navigate("AddressList")}>
<Text style={styles.recipientInfoHeadingEmit}></Text>
</TouchableOpacity>
</View>
3 weeks ago
<View style={styles.contactFormContainer}>
{/* First Name Field */}
<View style={styles.formFieldContainer}>
<View style={styles.flexRowCentered}>
3 weeks ago
<Text style={styles.elegantTextSnippet}></Text>
<Text style={styles.redTextHeading}>*</Text>
</View>
<TextInput
3 weeks ago
style={styles.pingFangText}
placeholder="请输入名"
value={formData.receiver_first_name}
onChangeText={(text) =>
setFormData({
...formData,
3 weeks ago
receiver_first_name: text,
})
}
4 weeks ago
editable={false}
/>
3 weeks ago
{errors.receiver_first_name && (
<Text style={styles.errorText}>
3 weeks ago
{errors.receiver_first_name}
</Text>
)}
</View>
3 weeks ago
{/* Last Name Field */}
<View style={styles.lastNameInputContainer}>
<View style={styles.flexRowCentered}>
3 weeks ago
<Text style={styles.elegantTextSnippet}></Text>
<Text style={styles.redAsteriskTextStyle}>*</Text>
</View>
<TextInput
3 weeks ago
style={styles.pingFangText}
placeholder="请输入姓"
value={formData.receiver_last_name}
onChangeText={(text) =>
3 weeks ago
setFormData({ ...formData, receiver_last_name: text })
}
editable={false}
/>
{errors.receiver_last_name && (
<Text style={styles.errorText}>
{errors.receiver_last_name}
</Text>
)}
</View>
{/* 国家 */}
<View style={styles.lastNameInputContainer}>
<View style={styles.flexRowCentered}>
<Text style={styles.elegantTextSnippet}></Text>
</View>
<TouchableOpacity
style={styles.countrySelectorButton}
onPress={() => setOpen(true)}
disabled={true}
>
{selectedCountryLabel ? (
<Text style={styles.selectedCountryText}>{selectedCountryLabel}</Text>
) : (
<Text style={styles.placeholderStyle}></Text>
)}
<Text style={styles.dropdownArrow}></Text>
</TouchableOpacity>
</View>
{/* Phone Number Section */}
<View style={styles.formContainer}>
<View style={styles.verticalCenteredColumn}>
<View style={styles.lastNameInputContainer1}>
<View style={styles.flexRowCentered}>
<Text style={styles.elegantTextSnippet}>
</Text>
<Text style={styles.redAsteriskTextStyle}>*</Text>
</View>
<TextInput
style={styles.pingFangText1}
placeholder="请输入手机号码"
value={formData.receiver_phone}
onChangeText={(text) =>
setFormData({
...formData,
receiver_phone: text,
})
}
editable={false}
/>
{errors.receiver_phone && (
<Text style={styles.errorText}>
{errors.receiver_phone}
</Text>
)}
</View>
<View style={styles.lastNameInputContainer1}>
<View style={styles.flexRowCentered}>
<Text style={styles.elegantTextSnippet}>
</Text>
<Text style={styles.redAsteriskTextStyle}>*</Text>
</View>
<TextInput
style={styles.pingFangText1}
placeholder="请再次输入手机号码"
value={formData.receiver_phone_again}
onChangeText={(text) =>
setFormData({
...formData,
receiver_phone_again: text,
})
}
editable={false}
/>
{errors.receiver_phone_again && (
<Text style={styles.errorText}>
{errors.receiver_phone_again}
</Text>
)}
</View>
{!phoneNumbersMatch && (
<Text style={styles.errorText}>
</Text>
)}
</View>
</View>
{/* WhatsApp Field */}
<View style={styles.lastNameInputContainer}>
<View style={styles.flexRowCentered}>
<Text style={styles.elegantTextSnippet}>WhatsApp</Text>
<Text style={styles.redTextHeading}>*</Text>
</View>
<TextInput
style={styles.pingFangText}
placeholder="请输入WhatsApp号码"
value={formData.whatsapp_phone}
onChangeText={(text) =>
setFormData({ ...formData, whatsapp_phone: text })
}
4 weeks ago
editable={false}
/>
3 weeks ago
{errors.whatsapp_phone && (
<Text style={styles.errorText}>
3 weeks ago
{errors.whatsapp_phone}
</Text>
)}
</View>
3 weeks ago
<View style={styles.copyContainer}>
<TouchableOpacity
style={styles.checkboxContainer}
onPress={() =>
setCopyPhoneToWhatsApp(!copyPhoneToWhatsApp)
}
>
<View
style={[
styles.checkbox,
copyPhoneToWhatsApp && styles.checked,
]}
>
{copyPhoneToWhatsApp && (
<Text style={styles.checkmark}></Text>
)}
</View>
<Text style={styles.checkboxLabel}>
WhatsApp号码
</Text>
</TouchableOpacity>
</View>
{/* Default Setting Section */}
{/* <View style={styles.defaultSettingSection}>
<Text style={styles.defaultTextDisplayStyle}>
</Text>
3 weeks ago
<Switch
value={formData.is_default}
onValueChange={() =>
setFormData({
...formData,
is_default: !formData.is_default,
})
}
trackColor={{ false: "#767577", true: "#81b0ff" }}
thumbColor={formData.is_default ? "#002fa7" : "#f4f3f4"}
ios_backgroundColor="#3e3e3e"
/>
</View> */}
</View>
</View>
3 weeks ago
{/* Submit Button */}
<View style={styles.submitButtonContainer}>
<TouchableOpacity
3 weeks ago
style={styles.primaryButtonStyle}
onPress={handleSubmit}
>
3 weeks ago
<Text style={styles.buttonText}></Text>
</TouchableOpacity>
</View>
</View>
</View>
3 weeks ago
</View>
</View>
)}
<Modal
visible={open}
animationType="slide"
transparent={true}
onRequestClose={() => setOpen(false)}
>
<View style={styles.modalContainer}>
<View style={styles.modalContent}>
<View style={styles.modalHeader}>
<Text style={styles.modalTitle}></Text>
<TouchableOpacity onPress={() => setOpen(false)}>
<Text style={styles.closeButton}></Text>
</TouchableOpacity>
</View>
3 weeks ago
<FlatList
data={countryList}
keyExtractor={(item) => item.value}
renderItem={({ item }) => (
<TouchableOpacity
style={styles.countryItem}
onPress={() => handleCountrySelect(item)}
>
{item.flag && (
<Image
source={item.flag}
style={styles.flagImage}
/>
)}
<Text style={styles.countryItemText}>{item.label}</Text>
{value === item.value && (
<Text style={styles.checkIcon}></Text>
)}
</TouchableOpacity>
)}
style={styles.flatList}
contentContainerStyle={styles.flatListContent}
/>
</View>
</View>
3 weeks ago
</Modal>
</ScrollView>
</KeyboardAvoidingView>
3 weeks ago
</SafeAreaView>
);
};
const styles = StyleSheet.create({
3 weeks ago
safeArea: {
flex: 1,
backgroundColor: '#fff',
},
safeAreaContent: {
flex: 1,
paddingTop: Platform.OS === 'android' ? 0 : 0,
3 weeks ago
},
container: {
flex: 1,
3 weeks ago
backgroundColor: '#fff',
},
scrollContainer: {
flexGrow: 1,
paddingBottom: 20,
},
recipientFormContainer3: {
flex: 1,
flexDirection: "column",
alignItems: "stretch",
justifyContent: "flex-start",
},
loadingContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
recipientFormContainer1: {
width: "100%",
padding: 15,
paddingBottom: 32,
},
recipientFormContainer2: {
width: "100%",
flexDirection: "column",
alignItems: "stretch",
justifyContent: "flex-start",
},
titleContainer: {
width: "100%",
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
position: "relative",
},
backIconContainer: {
position: "absolute",
left: 0,
},
titleHeading: {
fontWeight: "600",
fontSize: 20,
lineHeight: 22,
fontFamily: "PingFang SC",
color: "black",
},
recipientInfoForm: {
marginTop: 35,
},
recipientInfoHeadingContainer: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
},
recipientInfoHeading: {
padding: 0,
margin: 0,
fontWeight: "500",
fontSize: 18,
lineHeight: 22,
fontFamily: "PingFang SC",
color: "black",
},
recipientInfoHeadingEmit:{
padding: 0,
margin: 0,
fontWeight: "500",
fontSize: 18,
lineHeight: 22,
fontFamily: "PingFang SC",
color: "#ff731e",
textDecorationLine: "underline",
},
contactFormContainer: {
width: "100%",
marginTop: 9,
},
formFieldContainer: {
width: "100%",
padding: 6,
paddingLeft: 8,
paddingBottom: 10,
backgroundColor: "white",
borderWidth: 1,
borderColor: "#dbdce0",
borderRadius: 5,
},
flexRowCentered: {
flexDirection: "row",
alignItems: "center",
justifyContent: "flex-start",
},
elegantTextSnippet: {
padding: 0,
margin: 0,
fontWeight: "500",
fontSize: 12,
fontFamily: "PingFang SC",
color: "#646472",
},
redTextHeading: {
padding: 0,
margin: 0,
marginLeft: 1,
fontWeight: "500",
fontSize: 18,
lineHeight: 22,
fontFamily: "PingFang SC",
color: "#fe1e00",
},
pingFangText: {
padding: 0,
margin: 0,
marginTop: -2,
fontWeight: "400",
fontSize: 16,
lineHeight: 22,
fontFamily: "PingFang SC",
color: "#807e7e",
},
pingFangText1: {
padding: 0,
margin: 0,
marginTop: -2,
fontWeight: "400",
fontSize: 16,
lineHeight: 22,
fontFamily: "PingFang SC",
color: "#807e7e",
},
copyContainer: {
marginTop: 10,
flexDirection: "row",
alignItems: "center",
},
checkboxContainer: {
flexDirection: "row",
alignItems: "center",
},
checkbox: {
width: 15,
height: 15,
borderWidth: 1,
borderColor: "#dbdce0",
borderRadius: 4,
marginRight: 8,
justifyContent: "center",
alignItems: "center",
},
checked: {
backgroundColor: "#002fa7",
borderColor: "#002fa7",
},
checkmark: {
color: "white",
fontSize: 12,
},
checkboxLabel: {
fontSize: 14,
color: "#646472",
fontFamily: "PingFang SC",
},
lastNameInputContainer: {
width: "100%",
padding: 6,
paddingLeft: 8,
paddingBottom: 10,
marginTop: 12,
backgroundColor: "white",
borderWidth: 1,
borderColor: "#dbdce0",
borderRadius: 5,
},
lastNameInputContainer1: {
width: "100%",
padding: 6,
paddingLeft: 8,
paddingBottom: 10,
backgroundColor: "white",
borderTopWidth: 1,
borderColor: "#dbdce0",
},
redAsteriskTextStyle: {
padding: 0,
margin: 0,
marginLeft: 1,
fontWeight: "500",
fontSize: 18,
lineHeight: 22,
fontFamily: "PingFang SC",
color: "#fe1e00",
},
formContainer: {
flexDirection: "column",
alignItems: "stretch",
justifyContent: "center",
width: "100%",
marginTop: 12,
backgroundColor: "white",
borderWidth: 1,
borderColor: "#dbdce0",
},
optionListDropdown: {},
verticalCenteredColumn: {
flexDirection: "column",
alignItems: "stretch",
justifyContent: "center",
marginTop: -1,
},
phoneNumberContainer: {
flexDirection: "row",
alignItems: "center",
justifyContent: "flex-start",
height: 60,
paddingRight: 8,
paddingLeft: 8,
backgroundColor: "white",
borderWidth: 1,
borderColor: "#dbdce0",
},
mobilePhoneNumberLabel: {
padding: 0,
margin: 0,
fontWeight: "500",
fontSize: 14,
fontFamily: "PingFang SC",
color: "#807e7e",
},
mobilePhoneNumberLabel1: {
padding: 0,
margin: 0,
fontWeight: "500",
fontSize: 14,
fontFamily: "PingFang SC",
color: "#807e7e",
},
phoneNumberPromptContainer: {
flexDirection: "row",
alignItems: "center",
justifyContent: "flex-start",
height: 60,
paddingRight: 8,
paddingLeft: 8,
marginTop: -1,
backgroundColor: "white",
borderWidth: 1,
borderColor: "#dbdce0",
borderBottomLeftRadius: 5,
borderBottomRightRadius: 5,
},
defaultSettingSection: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
width: "100%",
marginTop: 15.5,
gap: 8,
},
defaultTextDisplayStyle: {
padding: 0,
margin: 0,
fontWeight: "500",
fontSize: 16,
lineHeight: 22,
fontFamily: "PingFang SC",
color: "black",
},
submitButtonContainer: {
paddingRight: 11,
paddingLeft: 11,
marginTop: 60,
},
primaryButtonStyle: {
width: "100%",
height: 50,
justifyContent: "center",
alignItems: "center",
fontWeight: "600",
fontSize: 16,
lineHeight: 22,
fontFamily: "PingFang SC",
color: "white",
backgroundColor: "#002fa7",
borderWidth: 0,
borderRadius: 25,
},
buttonText: {
color: "white",
fontWeight: "600",
fontSize: 16,
lineHeight: 22,
fontFamily: "PingFang SC",
},
4 weeks ago
selectedCountryText: {
padding: 0,
margin: 0,
fontWeight: "500",
fontSize: 16,
lineHeight: 22,
fontFamily: "PingFang SC",
color: "#646472",
},
4 weeks ago
modalContainer: {
flex: 1,
justifyContent: "flex-end",
backgroundColor: "rgba(0, 0, 0, 0.5)",
},
modalContent: {
backgroundColor: "white",
4 weeks ago
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
width: "100%",
height: Dimensions.get('window').height * 0.8,
display: "flex",
flexDirection: "column",
},
modalHeader: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
padding: 15,
borderBottomWidth: 1,
borderBottomColor: "#dbdce0",
},
4 weeks ago
modalTitle: {
fontWeight: "600",
fontSize: 18,
lineHeight: 22,
fontFamily: "PingFang SC",
color: "black",
},
closeButton: {
fontWeight: "500",
fontSize: 16,
4 weeks ago
lineHeight: 22,
fontFamily: "PingFang SC",
color: "#ff731e",
textDecorationLine: "underline",
},
countryItem: {
padding: 15,
borderBottomWidth: 1,
borderBottomColor: "#dbdce0",
flexDirection: "row",
alignItems: "center",
},
4 weeks ago
countryItemText: {
fontSize: 16,
color: "#333",
4 weeks ago
flex: 1,
},
4 weeks ago
errorText: {
color: "#fe1e00",
fontSize: 12,
marginTop: 4,
fontFamily: "PingFang SC",
},
4 weeks ago
countrySelectorButton: {
padding: 10,
borderWidth: 1,
borderColor: "#dbdce0",
borderRadius: 5,
4 weeks ago
marginTop: 5,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
},
placeholderStyle: {
color: "#807e7e",
fontSize: 16,
},
4 weeks ago
flagImage: {
width: 24,
height: 16,
marginRight: 10,
},
4 weeks ago
dropdownArrow: {
fontSize: 12,
4 weeks ago
color: "#807e7e",
},
flatList: {
flex: 1,
height: "100%",
},
flatListContent: {
flexGrow: 1,
},
checkIcon: {
color: "#002fa7",
fontSize: 18,
fontWeight: "bold",
},
});