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.

692 lines
22 KiB

import React from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
ActivityIndicator,
Modal,
FlatList,
SafeAreaView,
Alert,
Platform,
StatusBar,
} from "react-native";
import { useState, useEffect } from "react";
import fontSize from "../../utils/fontsizeUtils";
import LocationPinIcon from "../../components/LocationPinIcon";
import {
AddressDataItem,
OrderData,
Address,
CartShippingFeeData,
DomesticShippingFeeData,
} from "../../services/api/orders";
import usePreviewShippingStore from "../../store/previewShipping";
import { getSubjectTransLanguage } from "../../utils/languageUtils";
import BackIcon from "../../components/BackIcon";
import { useNavigation, useRoute, RouteProp } from "@react-navigation/native";
import useCreateOrderStore from "../../store/createOrder";
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
import useUserStore from "../../store/user";
import useBurialPointStore from "../../store/burialPoint";
import {getBurialPointData} from "../../store/burialPoint";
type RootStackParamList = {
ShippingFee: undefined;
PaymentMethod: { freight_forwarder_address_id: number };
};
type ShippingFeeParams = {
cart_item_id: {
items: any[];
cart_item_id: number;
};
};
export const ShippingFee = () => {
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
const route =
useRoute<RouteProp<Record<string, ShippingFeeParams>, string>>();
const {
fetchFreightForwarderAddress,
state,
calculateShippingFee,
calculateDomesticShippingFee,
} = usePreviewShippingStore();
const [shippingMethod, setShippingMethod] = useState("sea");
const [warehouse, setWarehouse] = useState<string>();
const [freightForwarderAddress, setFreightForwarderAddress] =
useState<AddressDataItem>();
const [shippingFeeData, setShippingFeeData] = useState<CartShippingFeeData>();
const [modalVisible, setModalVisible] = useState(false);
const [selectedWarehouseLabel, setSelectedWarehouseLabel] = useState("");
const [selectedWarehouse, setSelectedWarehouse] = useState<Address>();
const [domesticShippingFeeData, setDomesticShippingFeeData] =
useState<DomesticShippingFeeData>();
const [isDomesticShippingLoading, setIsDomesticShippingLoading] = useState(false);
const [count,setCount] = useState<string>();
const [apiResponses, setApiResponses] = useState({
shippingFees: false,
domesticShippingFees: false
});
const { setOrderData ,orderData,items} = useCreateOrderStore();
const [countryCode,setCountryCode] = useState<number>();
const userStore = useUserStore();
const { logShippingConfirm } = useBurialPointStore();
const getFreightForwarderAddress = async () => {
await fetchFreightForwarderAddress(0);
};
useEffect(() => {
getFreightForwarderAddress();
}, []);
useEffect(() => {
if (state.freightForwarderAddress) {
console.log(state.freightForwarderAddress.other_addresses);
setFreightForwarderAddress(state.freightForwarderAddress);
// 设置默认选择第一项
if (
state.freightForwarderAddress.other_addresses &&
state.freightForwarderAddress.other_addresses.length > 0
) {
const firstItem = state.freightForwarderAddress.other_addresses[0];
const label = firstItem.country + "|" + firstItem.city;
setWarehouse(label);
setSelectedWarehouseLabel(label);
setCountryCode(firstItem.country_code);
}
}
}, [state.freightForwarderAddress]);
useEffect(() => {
if (state.shippingFees) {
setShippingFeeData(state.shippingFees);
setCount('正在计算运费,请不要关闭app');
setApiResponses(prev => ({...prev, shippingFees: true}));
}
}, [state.shippingFees]);
useEffect(() => {
if (state.domesticShippingFees) {
setDomesticShippingFeeData(state.domesticShippingFees);
setApiResponses(prev => ({...prev, domesticShippingFees: true}));
}
}, [state.domesticShippingFees]);
// Effect to handle loading state based on both API responses
useEffect(() => {
if (apiResponses.shippingFees && apiResponses.domesticShippingFees) {
setIsDomesticShippingLoading(false);
}
}, [apiResponses]);
// Call changeCountryHandel when warehouse changes
useEffect(() => {
if (warehouse && freightForwarderAddress?.other_addresses) {
changeCountryHandel(warehouse);
}
}, [warehouse, freightForwarderAddress]);
const changeCountryHandel = async (value: string) => {
if (value && freightForwarderAddress?.other_addresses) {
const selectedWarehouse = freightForwarderAddress.other_addresses.find(
(item) => item.country + "|" + item.city === value
);
setSelectedWarehouse(selectedWarehouse);
if (selectedWarehouse && items) {
const data = {
items: items,
freight_forwarder_address_id: selectedWarehouse.address_id,
};
// Only calculate if we have the necessary data
if (data.items && data.freight_forwarder_address_id) {
// Set loading state to true before making API calls
setIsDomesticShippingLoading(true);
setCount('正在计算运费,请不要关闭app');
// Reset API response tracking
setApiResponses({
shippingFees: false,
domesticShippingFees: false
});
calculateShippingFee(data);
calculateDomesticShippingFee(data);
}
}
}
};
const handleSelectWarehouse = (countryCode: number, label: string) => {
setWarehouse(label);
setSelectedWarehouseLabel(label);
setCountryCode(countryCode);
setModalVisible(false);
};
const handleSubmit = () => {
if (!isDomesticShippingLoading && domesticShippingFeeData?.total_shipping_fee != null) {
setOrderData({
...orderData,
transport_type: shippingMethod === "sea" ? 0 : 1,
domestic_shipping_fee: domesticShippingFeeData?.total_shipping_fee,
shipping_fee: shippingMethod === "sea"
? shippingFeeData?.total_shipping_fee_sea
: shippingFeeData?.total_shipping_fee_air,
receiver_address:selectedWarehouseLabel
});
const data = {
shipping_method: shippingMethod === "sea" ? 0 : 1,
shipping_price_outside: shippingMethod === "sea"
? (shippingFeeData?.total_shipping_fee_sea || 0)
: (shippingFeeData?.total_shipping_fee_air || 0),
shipping_price_within: domesticShippingFeeData?.total_shipping_fee || 0,
currency: userStore.user?.currency || '',
forwarder_name: selectedWarehouse?.forwarder_name || '',
country_city: selectedWarehouseLabel,
timestamp: new Date().toISOString(),
}
logShippingConfirm(data,navigation.getState().routes[navigation.getState().index - 1]?.name as string)
console.log(getBurialPointData());
navigation.navigate("PaymentMethod", {freight_forwarder_address_id: selectedWarehouse?.address_id || 0});
}else{
Alert.alert("请选择运输方式");
}
};
return (
<SafeAreaView style={styles.safeArea}>
<StatusBar barStyle="dark-content" backgroundColor="#fff" />
<View style={styles.safeAreaContent}>
<View style={styles.container}>
<View style={styles.recipientFormContainer3}>
<View style={styles.titleContainer}>
<View style={styles.backIconContainer}>
<TouchableOpacity onPress={() => navigation.goBack()}>
<BackIcon size={20} />
</TouchableOpacity>
</View>
<Text style={styles.titleHeading}></Text>
</View>
{state.isLoading ? (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#f77f3a" />
</View>
) : (
<View style={styles.recipientFormContainer1}>
<View style={styles.section}>
<View style={styles.sectionHeader}>
<Text style={styles.sectionIcon}>🚢</Text>
<Text style={styles.sectionTitle}>Shipping Method</Text>
</View>
<View style={styles.shippingOptions}>
{[
{
id: "sea",
label: "Sea Shipping",
icon: "🚢",
detail: "Economical",
},
{
id: "air",
label: "Air Shipping",
icon: "✈",
detail: "Express",
},
].map((option, index) => (
<TouchableOpacity
key={option.id}
style={[
styles.shippingCard,
shippingMethod === option.id && styles.shippingCardSelected,
]}
onPress={() => {
setShippingMethod(option.id);
}}
>
{index === 0 && (
<View style={styles.locationPin}>
<LocationPinIcon size={20} />
</View>
)}
<Text style={styles.shippingIcon}>{option.icon}</Text>
<Text style={styles.shippingLabel}>{option.label}</Text>
<Text style={styles.shippingDetail}>{option.detail}</Text>
</TouchableOpacity>
))}
</View>
</View>
{/* Warehouse Selection */}
<View style={styles.section}>
<View style={styles.sectionHeader}>
<Text style={styles.sectionIcon}>🏭</Text>
<Text style={styles.sectionTitle}>Delivery Warehouse</Text>
</View>
<View style={{ marginTop: 12 }}>
<View style={styles.selectBox}>
<Text style={styles.selectLabel}>Select a warehouse:</Text>
<TouchableOpacity
style={styles.selectWrapper}
onPress={() => setModalVisible(true)}
>
<Text style={styles.selectedText}>
{selectedWarehouseLabel || "Select warehouse"}
</Text>
<Text style={styles.dropdownIcon}></Text>
</TouchableOpacity>
{/* Modal Dropdown */}
<Modal
visible={modalVisible}
transparent={true}
animationType="slide"
onRequestClose={() => setModalVisible(false)}
>
<TouchableOpacity
style={styles.modalOverlay}
activeOpacity={1}
onPress={() => setModalVisible(false)}
>
<View style={styles.modalContainer}>
<SafeAreaView style={styles.modalContent}>
<View style={styles.modalHeader}>
<Text style={styles.modalTitle}>
Select Warehouse
</Text>
<TouchableOpacity
onPress={() => setModalVisible(false)}
>
<Text style={styles.closeButton}>×</Text>
</TouchableOpacity>
</View>
<FlatList
data={freightForwarderAddress?.other_addresses || []}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<TouchableOpacity
style={[
styles.optionItem,
warehouse === item.country + "|" + item.city &&
styles.selectedOption,
]}
onPress={() =>
handleSelectWarehouse(
item.country_code,
item.country + "|" + item.city
)
}
>
<Text style={styles.optionText}>
{item.country + "|" + item.city}
</Text>
{warehouse === item.country + "|" + item.city && (
<Text style={styles.checkmark}></Text>
)}
</TouchableOpacity>
)}
/>
</SafeAreaView>
</View>
</TouchableOpacity>
</Modal>
</View>
{warehouse && (
<View style={styles.shippingInfo}>
<Text style={styles.shippingInfoRow}>
<Text style={styles.shippingInfoLabel}>: </Text>
<Text
style={{ flex: 1, textAlign: "left", marginLeft: 10 }}
>
{shippingMethod === "sea"
? "45天"
: "20天"}
</Text>
</Text>
<View style={styles.shippingInfoRow}>
<Text style={styles.shippingInfoLabel}>: </Text>
<Text
style={{
color: "#ff6000",
flex: 1,
textAlign: "left",
marginLeft: 10,
fontWeight: "600",
}}
>
{isDomesticShippingLoading ? (
<Text style={{ color: "#ff6000",alignItems:"center" }}>{count} <ActivityIndicator size="small" color="#ff6000" style={{ marginLeft: 5 }} /></Text>
) : (
<Text style={{ color: "#ff6000" }}>
{((domesticShippingFeeData?.total_shipping_fee || 0) + (shippingMethod === "sea"
? (shippingFeeData?.total_shipping_fee_sea || 0)
: (shippingFeeData?.total_shipping_fee_air || 0))).toFixed(2)} {''} {userStore.user?.currency}
</Text>
)}
</Text>
{/* <Text style={{ color: "#ff6000" }}>(Cash on Delivery)</Text> */}
</View>
{/*
<View style={styles.shippingInfoRow}>
<Text style={styles.shippingInfoLabel}>国际运费: </Text>
<Text
style={{
color: "#ff6000",
flex: 1,
textAlign: "left",
marginLeft: 10,
fontWeight: "600",
}}
>
{shippingMethod === "sea"
? shippingFeeData?.total_shipping_fee_sea
: shippingFeeData?.total_shipping_fee_air}
</Text>
</View> */}
</View>
)}
</View>
</View>
<View style={styles.submitButtonContainer}>
<TouchableOpacity
style={[
styles.primaryButtonStyle,
(isDomesticShippingLoading || domesticShippingFeeData?.total_shipping_fee == null)
? styles.disabledButtonStyle : {}
]}
onPress={handleSubmit}
disabled={isDomesticShippingLoading || domesticShippingFeeData?.total_shipping_fee == null}
>
<Text style={styles.buttonText}></Text>
</TouchableOpacity>
</View>
</View>
)}
</View>
</View>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: '#fff',
},
safeAreaContent: {
flex: 1,
paddingTop: Platform.OS === 'android' ? 0 : 0,
},
container: {
flex: 1,
backgroundColor: '#fff',
},
section: {
backgroundColor: "#fff",
borderRadius: 8,
paddingLeft: 16,
paddingRight: 16,
marginTop: 10,
},
sectionHeader: {
flexDirection: "row",
alignItems: "center",
paddingTop: 12,
paddingBottom: 12,
},
sectionIcon: { marginRight: 8, fontSize: fontSize(18) },
sectionTitle: { flex: 1, fontSize: fontSize(15), fontWeight: "500" },
sectionAction: {
color: "#ff6000",
fontSize: fontSize(13),
fontWeight: "500",
},
paymentOptions: {
marginTop: 12,
flexDirection: "column",
},
recipientInfo: {
backgroundColor: "#fff",
borderRadius: 8,
paddingHorizontal: 12,
paddingVertical: 12,
borderWidth: 1,
borderColor: "#ccc",
width: "100%",
marginBottom: 12,
flexDirection: "row",
alignItems: "center",
},
recipientInfoIcon: {
marginRight: 12,
},
recipientInfoText: {
flex: 1,
fontSize: fontSize(18),
},
addRecipient: {
borderWidth: 1,
borderColor: "#ccc",
padding: 12,
borderRadius: 6,
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
backgroundColor: "#fff",
},
addRecipientIcon: {
fontSize: fontSize(20),
color: "#ff6000",
marginRight: 6,
},
addRecipientText: { fontSize: fontSize(14), color: "#666" },
shippingOptions: {
flexDirection: "row",
gap: 10,
justifyContent: "space-between",
marginTop: 12,
},
shippingCard: {
flex: 1,
alignItems: "center",
padding: 12,
borderRadius: 6,
borderWidth: 1,
borderColor: "#e0e0e0",
backgroundColor: "#fff",
},
shippingCardSelected: { borderColor: "#ff6000", backgroundColor: "#fff" },
locationPin: {
position: "absolute",
top: 8,
right: 8,
zIndex: 1,
},
shippingIcon: { fontSize: fontSize(22), marginBottom: 6 },
shippingLabel: { fontSize: fontSize(14), fontWeight: "500" },
shippingDetail: { fontSize: fontSize(12), color: "#888", marginTop: 3 },
recipientFormContainer3: {
flex: 1,
flexDirection: "column",
alignItems: "stretch",
justifyContent: "flex-start",
backgroundColor: "#fff",
padding: 15,
},
recipientFormContainer1: {
width: "100%",
paddingBottom: 32,
},
border: {
height: 6,
backgroundColor: "#f5f5f5",
marginTop: 12,
},
selectBox: { marginBottom: 12 },
selectLabel: { fontSize: fontSize(14), marginBottom: 6, color: "#666" },
selectWrapper: {
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 6,
overflow: "hidden",
backgroundColor: "#fff",
padding: 12,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
},
selectedText: {
fontSize: fontSize(14),
color: "#333",
},
dropdownIcon: {
fontSize: fontSize(12),
color: "#666",
},
modalOverlay: {
flex: 1,
backgroundColor: "rgba(0,0,0,0.5)",
justifyContent: "flex-end",
},
modalContainer: {
backgroundColor: "white",
borderTopLeftRadius: 12,
borderTopRightRadius: 12,
height: "80%",
},
modalContent: {
width: "100%",
},
modalHeader: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
padding: 16,
borderBottomWidth: 1,
borderBottomColor: "#eee",
},
modalTitle: {
fontSize: fontSize(16),
fontWeight: "600",
},
closeButton: {
fontSize: fontSize(24),
color: "#666",
},
optionItem: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
padding: 16,
borderBottomWidth: 1,
borderBottomColor: "#eee",
},
selectedOption: {
backgroundColor: "#f0f0f0",
},
optionText: {
fontSize: fontSize(14),
},
checkmark: {
color: "#ff6000",
fontWeight: "bold",
},
shippingInfo: {
marginTop: 12,
padding: 12,
backgroundColor: "#f9f9f9",
borderRadius: 6,
},
shippingInfoRow: {
fontSize: fontSize(13),
marginBottom: 6,
color: "#333",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
},
shippingInfoLabel: {
color: "#777",
fontWeight: "500",
fontSize: fontSize(13),
},
loadingContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
backIconContainer: {
position: "absolute",
left: 0,
},
titleContainer: {
width: "100%",
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
position: "relative",
},
titleHeading: {
fontWeight: "600",
fontSize: 20,
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",
},
selectedCountryText: {
padding: 0,
margin: 0,
fontWeight: "500",
fontSize: 16,
lineHeight: 22,
fontFamily: "PingFang SC",
color: "#646472",
},
disabledButtonStyle: {
backgroundColor: "#ccc",
},
});