diff --git a/App.tsx b/App.tsx index f65497c..8772722 100644 --- a/App.tsx +++ b/App.tsx @@ -7,11 +7,13 @@ import useBurialPointStore from "./app/store/burialPoint"; import { AuthProvider, useAuth } from "./app/contexts/AuthContext"; import { GestureHandlerRootView } from "react-native-gesture-handler"; import { AppNavigator } from "./app/navigation/AppNavigator"; -import { View, ActivityIndicator } from "react-native"; +import { View, ActivityIndicator, Alert } from "react-native"; import AsyncStorage from "@react-native-async-storage/async-storage"; import "./app/i18n"; +import * as Linking from 'expo-linking'; - +// 定义全局事件处理支付成功 +export const PAYMENT_SUCCESS_EVENT = 'PAYMENT_SUCCESS_EVENT'; function AppContent() { const { setUser } = useUserStore(); @@ -47,6 +49,43 @@ function AppContent() { initApp(); }, []); + // 添加深度链接处理 + useEffect(() => { + // 处理深度链接 + const handleDeepLink = ({ url }: { url: string }) => { + console.log('Global deep link received:', url); + if ( + url.startsWith('myapp://payment-success') || + url.startsWith('exp://192.168.0.101:8084/--/payment-success') + ) { + // 解析参数 + const parsed = Linking.parse(url); + const params = parsed.queryParams || {}; + const paymentId = params.paymentId || ''; + const token = params.token || ''; + const payerId = params.PayerID || ''; + + Alert.alert( + '支付成功!', + `支付ID: ${paymentId}\nToken: ${token}\nPayerID: ${payerId}` + ); + // 这里可以做页面跳转或业务处理 + } + }; + + // 注册深度链接监听器 + const subscription = Linking.addEventListener('url', handleDeepLink); + + // 处理应用冷启动的深度链接 + Linking.getInitialURL().then((url) => { + if (url && url.startsWith('myapp://payment-success')) { + handleDeepLink({ url }); + } + }); + + return () => subscription.remove(); + }, []); + if (isLoading) { return ( diff --git a/app.json b/app.json index 63c42f3..2634e13 100644 --- a/app.json +++ b/app.json @@ -7,7 +7,8 @@ "icon": "./assets/icon.png", "userInterfaceStyle": "light", "newArchEnabled": true, - "scheme": "auth0sample", + "scheme": "myapp", + "deepLinking": true, "splash": { "image": "./assets/splash-icon.png", "resizeMode": "contain", @@ -20,7 +21,7 @@ "CFBundleURLTypes": [ { "CFBundleURLSchemes": [ - "auth0sample" + "myapp" ] } ] @@ -41,7 +42,7 @@ "action": "VIEW", "data": [ { - "scheme": "auth0sample" + "scheme": "myapp" } ], "category": [ diff --git a/app/navigation/RootNavigation.ts b/app/navigation/RootNavigation.ts new file mode 100644 index 0000000..130125c --- /dev/null +++ b/app/navigation/RootNavigation.ts @@ -0,0 +1,9 @@ +import { createNavigationContainerRef } from '@react-navigation/native'; + +export const navigationRef = createNavigationContainerRef(); + +export function navigate(name: string, params?: object) { + if (navigationRef.isReady()) { + navigationRef.navigate(name, params); + } +} \ No newline at end of file diff --git a/app/screens/ProfileScreen.tsx b/app/screens/ProfileScreen.tsx index 94c3a20..7bad836 100644 --- a/app/screens/ProfileScreen.tsx +++ b/app/screens/ProfileScreen.tsx @@ -10,6 +10,7 @@ import { Platform, StatusBar, SafeAreaView, + Linking, } from "react-native"; import SettingsIcon from "../components/SettingsIcon"; import fontSize from "../utils/fontsizeUtils"; @@ -87,7 +88,9 @@ export const ProfileScreen = () => { {user?.username} - ID: {user?.user_id} + + ID: {user?.user_id} + { - VIP{user?.vip_level} + + VIP{user?.vip_level} + { - 40000/50000 + + 40000/50000 + @@ -132,7 +139,9 @@ export const ProfileScreen = () => { navigation.navigate("MemberIntroduction")} + onPress={() => + navigation.navigate("MemberIntroduction") + } > 了解更多 @@ -161,7 +170,7 @@ export const ProfileScreen = () => { - + { style={styles.profileImage} /> - + 立即登录 @@ -179,6 +191,14 @@ export const ProfileScreen = () => { 登录 + + Linking.openURL("exp://192.168.0.101:8084/--/payment-success") + } + > + 测试支付回调 + @@ -194,7 +214,9 @@ export const ProfileScreen = () => { 订单标题 navigation.navigate("Status", { status: null })} + onPress={() => + navigation.navigate("Status", { status: null }) + } > 全部 @@ -208,14 +230,18 @@ export const ProfileScreen = () => { style={styles.groupItemContent} onPress={() => item.status !== null - ? navigation.navigate("Status", { status: item.status }) + ? navigation.navigate("Status", { + status: item.status, + }) : null } > - {item.text} + + {item.text} + ))} @@ -234,7 +260,10 @@ export const ProfileScreen = () => { style={styles.groupItemContentIcon} onPress={() => navigation.navigate("BrowseHistoryScreen")} > - + 游览历史 @@ -275,7 +304,7 @@ const styles = StyleSheet.create({ }, safeAreaContent: { flex: 1, - paddingTop: Platform.OS === 'android' ? 0 : 0, + paddingTop: Platform.OS === "android" ? 0 : 0, }, flexColumnContainer1: { flex: 1, @@ -457,7 +486,7 @@ const styles = StyleSheet.create({ right: 19, backgroundColor: "#3A3128", borderRadius: 10, - marginBottom: Platform.OS === 'ios' ? -18 : -15, + marginBottom: Platform.OS === "ios" ? -18 : -15, zIndex: 1, }, promoCardContainer2: { diff --git a/app/screens/SearchResultScreen.tsx b/app/screens/SearchResultScreen.tsx index d6e2420..44e5452 100644 --- a/app/screens/SearchResultScreen.tsx +++ b/app/screens/SearchResultScreen.tsx @@ -518,16 +518,14 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp /> {searchText.length > 0 && ( setSearchText("")} style={styles.clearButton} + onPress={() => setSearchText("")} + hitSlop={{ top: 10, right: 10, bottom: 10, left: 10 }} > )} - - {t("cancel")} - {/* 标签筛选 */} @@ -805,7 +803,6 @@ const styles = StyleSheet.create({ paddingHorizontal: 8, height: widthUtils(40, 40).height, marginHorizontal: 8, - position: "relative", }, searchInput: { flex: 1, @@ -813,14 +810,18 @@ const styles = StyleSheet.create({ fontSize: isSmallScreen ? 14 : 16, color: "#333", height: widthUtils(40, 40).height, - paddingRight: 32, + paddingRight: 30, }, clearButton: { position: "absolute", - right: 8, - top: "50%", - transform: [{ translateY: -9 }], - padding: 4, + right: 10, + top: '50%', + marginTop: -10, + width: 20, + height: 20, + alignItems: 'center', + justifyContent: 'center', + zIndex: 20, }, searchButton: { paddingVertical: 4, diff --git a/app/screens/pay/Pay.tsx b/app/screens/pay/Pay.tsx index 8c88280..dccd5e4 100644 --- a/app/screens/pay/Pay.tsx +++ b/app/screens/pay/Pay.tsx @@ -1,8 +1,10 @@ -import { View, StyleSheet } from 'react-native'; -import { useRoute, RouteProp } from '@react-navigation/native'; +import { View, StyleSheet, Alert } from 'react-native'; +import { useRoute, RouteProp, useNavigation } from '@react-navigation/native'; import { useEffect, useState } from 'react'; import { payApi, PaymentInfoResponse } from '../../services/api/payApi'; import { WebView } from "react-native-webview"; +import * as Linking from 'expo-linking'; +import { navigate } from '../../navigation/RootNavigation'; type PayScreenRouteProp = RouteProp<{ Pay: { payUrl: string }; @@ -11,17 +13,46 @@ type PayScreenRouteProp = RouteProp<{ export const Pay = () => { const [loading, setLoading] = useState(true); const route = useRoute(); + const navigation = useNavigation(); const {payUrl} = route.params; const [payInfo, setPayInfo] = useState(); useEffect(() => { console.log(route.params); - console.log(payUrl); - },[]) + // 设置处理深度链接的监听器 + const handleDeepLink = ({ url }: { url: string }) => { + console.log('Deep link received:', url); + if ( + url.startsWith('myapp://payment-success') || + url.startsWith('exp://192.168.0.101:8084/--/payment-success') + ) { + const parsed = Linking.parse(url); + const params = parsed.queryParams || {}; + navigate('PaymentSuccessScreen', params); + } + }; + + // 添加深度链接事件监听器 + const subscription = Linking.addEventListener('url', handleDeepLink); + + return () => { + // 清理订阅 + subscription.remove(); + }; + }, []); + const handleNavigationStateChange = (navState: any) => { console.log(navState); + + // 检查URL是否包含支付成功的回调参数 + const { url } = navState; + if (url && url.includes('payment_success=true')) { + // 如果网页URL中包含成功参数,可以在这里处理 + Alert.alert('检测到支付成功!'); + // navigation.navigate('PaymentConfirmation'); + } } return {payUrl ? ( @@ -38,9 +69,25 @@ export const Pay = () => { originWhitelist={['*']} userAgent="Mozilla/5.0 (Linux; Android 10; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Mobile Safari/537.36" onShouldStartLoadWithRequest={(request) => { - console.log(request); + console.log('Load request:', request); + + // 检查URL是否是支付成功的深度链接 + const { url } = request; + if ( + url && ( + url.startsWith('myapp://payment-success') || + url.startsWith('exp://192.168.0.101:8084/--/payment-success') + ) + ) { + // 解析参数 + const parsed = Linking.parse(url); + const params = parsed.queryParams || {}; + // 跳转到支付成功页面 + navigate('PaymentSuccessScreen', params); + return false; // 不在WebView中加载 + } - // 允许所有请求 + // 允许所有其他请求 return true; }} /> diff --git a/app/screens/previewOrder/PaymentMethod.tsx b/app/screens/previewOrder/PaymentMethod.tsx index e64f1ff..53579ea 100644 --- a/app/screens/previewOrder/PaymentMethod.tsx +++ b/app/screens/previewOrder/PaymentMethod.tsx @@ -9,7 +9,7 @@ import { Alert, ActivityIndicator, StatusBar, - SafeAreaView + SafeAreaView, } from "react-native"; import { payApi, PaymentMethodsResponse } from "../../services/api/payApi"; import fontSize from "../../utils/fontsizeUtils"; @@ -22,13 +22,14 @@ import { useRoute, RouteProp } from "@react-navigation/native"; import useUserStore from "../../store/user"; import { createOrderDataType } from "../../types/createOrder"; import useBurialPointStore from "../../store/burialPoint"; -import {getBurialPointData} from "../../store/burialPoint"; +import { getBurialPointData } from "../../store/burialPoint"; import { ordersApi, - OrderData, CreateOrderRequest, Order, + OrderData, + CreateOrderRequest, + Order, } from "../../services/api/orders"; - // Define route params type type PaymentMethodRouteParams = { freight_forwarder_address_id?: number; @@ -36,7 +37,12 @@ type PaymentMethodRouteParams = { // Define the root navigation params type RootStackParamList = { - PreviewOrder: {data:Order,payMethod:string,currency:string,amount:number}; + PreviewOrder: { + data: Order; + payMethod: string; + currency: string; + amount: number; + }; Pay: { order_id: string }; ShippingFee: { freight_forwarder_address_id?: number }; PaymentMethod: { freight_forwarder_address_id?: number }; @@ -79,7 +85,11 @@ const PaymentMethodItem = ({ eur: number; }; totalAmount?: number; - convertedAmount?: number; + convertedAmount?: { + converted_amount: number; + item_key: string; + original_amount: number; + }[]; isConverting?: boolean; }) => ( @@ -108,18 +118,23 @@ const PaymentMethodItem = ({ /> - + {/* Show currency selector directly under PayPal when selected */} - {isSelected && option.label === "Paypal" && selectedCurrency && onSelectCurrency && exchangeRates && totalAmount && ( - - )} + {isSelected && + option.label === "Paypal" && + selectedCurrency && + onSelectCurrency && + exchangeRates && + totalAmount && ( + + )} ); @@ -132,7 +147,11 @@ interface CurrencySelectorProps { eur: number; }; totalAmount: number; - convertedAmount?: number; + convertedAmount?: { + converted_amount: number; + item_key: string; + original_amount: number; + }[]; isConverting?: boolean; } @@ -141,7 +160,7 @@ const CurrencySelector = ({ onSelectCurrency, exchangeRates, totalAmount, - convertedAmount = 0, + convertedAmount = [], isConverting = false, }: CurrencySelectorProps) => ( @@ -166,15 +185,22 @@ const CurrencySelector = ({ EUR - + - {!isConverting && ( - - {selectedCurrency === "USD" ? "$" : "€"}{convertedAmount} - + {!isConverting && ( + + {selectedCurrency === "USD" ? "$" : "€"} + {convertedAmount + .reduce((acc, item) => acc + item.converted_amount, 0) + .toFixed(2)} + )} {isConverting && ( - + )} @@ -206,14 +232,16 @@ export const PaymentMethod = () => { const [loading, setLoading] = useState(false); const { user } = useUserStore(); const [createOrderData, setCreateOrderData] = useState(); - const { items, orderData,setOrderData,resetOrder } = useCreateOrderStore(); + const { items, orderData, setOrderData, resetOrder } = useCreateOrderStore(); const [selectedCurrency, setSelectedCurrency] = useState("USD"); - const [convertedAmount, setConvertedAmount] = useState(0); + const [convertedAmount, setConvertedAmount] = useState< + { converted_amount: number; item_key: string; original_amount: number }[] + >([]); const [isConverting, setIsConverting] = useState(false); const [createLoading, setCreateLoading] = useState(false); const [exchangeRates] = useState({ - usd: 580.00, - eur: 655.96 + usd: 580.0, + eur: 655.96, }); const [totalAmount, setTotalAmount] = useState(121.97); const { logPaymentConfirm } = useBurialPointStore(); @@ -222,56 +250,54 @@ export const PaymentMethod = () => { }; const onSelectPayment = (paymentId: string) => { - if(paymentId === "Paypal"){ + if (paymentId === "Paypal") { setIsConverting(true); - const data = { - from_currency: user.currency, - to_currency: selectedCurrency, - amounts:[ - { - - } - ] - } - payApi.convertCurrency({ + const data = { from_currency: user.currency, to_currency: selectedCurrency, - amount: ( - (previewOrder?.total_amount || 0) + - (createOrderData?.domestic_shipping_fee || 0) + - (createOrderData?.shipping_fee || 0) - ), - }).then((res) => { - setConvertedAmount(res.converted_amount); - setIsConverting(false); - }).catch(error => { - console.error("Currency conversion failed:", error); - setIsConverting(false); - }); + amounts: { + total_amount: previewOrder?.total_amount || 0, + domestic_shipping_fee: createOrderData?.domestic_shipping_fee || 0, + shipping_fee: createOrderData?.shipping_fee || 0, + }, + }; + payApi + .convertCurrency(data) + .then((res) => { + setConvertedAmount(res.converted_amounts_list); + setIsConverting(false); + }) + .catch((error) => { + console.error("Currency conversion failed:", error); + setIsConverting(false); + }); } - + setSelectedPayment(paymentId); }; - const onSelectCurrency = (currency: string) => { + const onSelectCurrency = (currency: string) => { setSelectedCurrency(currency); - // Call the API to convert the currency setIsConverting(true); - payApi.convertCurrency({ + const data = { from_currency: user.currency, to_currency: currency, - amount: ( - (previewOrder?.total_amount || 0) + - (createOrderData?.domestic_shipping_fee || 0) + - (createOrderData?.shipping_fee || 0) - ), - }).then((res) => { - setConvertedAmount(res.converted_amount); - setIsConverting(false); - }).catch(error => { - console.error("Currency conversion failed:", error); - setIsConverting(false); - }); + amounts: { + total_amount: previewOrder?.total_amount || 0, + domestic_shipping_fee: createOrderData?.domestic_shipping_fee || 0, + shipping_fee: createOrderData?.shipping_fee || 0, + }, + }; + payApi + .convertCurrency(data) + .then((res) => { + setConvertedAmount(res.converted_amounts_list); + setIsConverting(false); + }) + .catch((error) => { + console.error("Currency conversion failed:", error); + setIsConverting(false); + }); }; const getPaymentMethods = async () => { @@ -371,7 +397,7 @@ export const PaymentMethod = () => { attribute_name: attr.attribute_name, attribute_value: attr.value, })), - sku_image:item.sku_image_url, + sku_image: item.sku_image_url, quantity: item.quantity, unit_price: item.unit_price, total_price: item.total_price, @@ -379,67 +405,125 @@ export const PaymentMethod = () => { if (createOrderData) { createOrderData.items = items; createOrderData.payment_method = selectedPayment; - createOrderData.total_amount = selectedPayment === 'Paypal' ? convertedAmount : - Number(((previewOrder?.total_amount || 0) + (orderData?.domestic_shipping_fee || 0) - + (orderData?.shipping_fee || 0)).toFixed(2)); - createOrderData.actual_amount = selectedPayment === 'Paypal' ? convertedAmount : - Number(((previewOrder?.total_amount || 0) + (orderData?.domestic_shipping_fee || 0) - + (orderData?.shipping_fee || 0)).toFixed(2)); - createOrderData.currency = selectedPayment === 'Paypal' ? selectedCurrency : user.currency; + createOrderData.total_amount = + selectedPayment === "Paypal" + ? convertedAmount.reduce( + (acc, item) => acc + item.converted_amount, + 0 + ) + : Number( + ( + (previewOrder?.total_amount || 0) + + (orderData?.domestic_shipping_fee || 0) + + (orderData?.shipping_fee || 0) + ).toFixed(2) + ); + createOrderData.actual_amount = + selectedPayment === "Paypal" + ? convertedAmount.reduce( + (acc, item) => acc + item.converted_amount, + 0 + ) + : Number( + ( + (previewOrder?.total_amount || 0) + + (orderData?.domestic_shipping_fee || 0) + + (orderData?.shipping_fee || 0) + ).toFixed(2) + ); + createOrderData.currency = + selectedPayment === "Paypal" ? selectedCurrency : user.currency; + + createOrderData.domestic_shipping_fee = + selectedPayment === "Paypal" + ? convertedAmount.find( + (item) => item.item_key === "domestic_shipping_fee" + )?.converted_amount || 0 + : orderData?.domestic_shipping_fee; + createOrderData.shipping_fee = + selectedPayment === "Paypal" + ? convertedAmount.find( + (item) => item.item_key === "shipping_fee" + )?.converted_amount || 0 + : orderData?.shipping_fee; } setOrderData(createOrderData || {}); const data = { pay_method: selectedPayment, - offline_payment: currentTab === 'offline' ? 0 : 1, - all_price: selectedPayment === 'Paypal' ? convertedAmount : - Number(((previewOrder?.total_amount || 0) + (orderData?.domestic_shipping_fee || 0) - + (orderData?.shipping_fee || 0)).toFixed(2)), - all_quantity:previewOrder?.items?.reduce((acc,item) => acc + item.quantity,0), + offline_payment: currentTab === "offline" ? 0 : 1, + all_price: + selectedPayment === "Paypal" + ? convertedAmount.reduce( + (acc, item) => acc + item.converted_amount, + 0 + ) + : Number( + ( + (previewOrder?.total_amount || 0) + + (orderData?.domestic_shipping_fee || 0) + + (orderData?.shipping_fee || 0) + ).toFixed(2) + ), + all_quantity: previewOrder?.items?.reduce( + (acc, item) => acc + item.quantity, + 0 + ), currency: selectedCurrency, shipping_method: orderData?.transport_type || 0, shipping_price_outside: orderData?.shipping_fee || 0, shipping_price_within: orderData?.domestic_shipping_fee || 0, timestamp: new Date().toISOString(), - pay_product:JSON.stringify(previewOrder?.items.map(item => { - return { - offer_id: item.offer_id, - price: item.unit_price, - all_price: previewOrder.total_amount, - currency: previewOrder.currency, + pay_product: JSON.stringify( + previewOrder?.items.map((item) => { + return { + offer_id: item.offer_id, + price: item.unit_price, + all_price: + convertedAmount.find((item) => item.item_key === "total_amount") + ?.converted_amount || 0, + currency: previewOrder.currency, - sku: item.attributes.map(sku => { - return { - sku_id: item.sku_id, - value: sku.value - }; - }), - quantity: item.quantity, - product_name: item.product_name, - timestamp: new Date(), - product_img: item.sku_image_url - }; - })) - - } - logPaymentConfirm(data,navigation.getState().routes[navigation.getState().index - 1]?.name as string) + sku: item.attributes.map((sku) => { + return { + sku_id: item.sku_id, + value: sku.value, + }; + }), + quantity: item.quantity, + product_name: item.product_name, + timestamp: new Date(), + product_img: item.sku_image_url, + }; + }) + ), + }; + logPaymentConfirm( + data, + navigation.getState().routes[navigation.getState().index - 1] + ?.name as string + ); console.log(getBurialPointData()); - - setCreateLoading(true) + + setCreateLoading(true); try { - const res = await ordersApi.createOrder(createOrderData as CreateOrderRequest) - setCreateLoading(false) - navigation.navigate("PreviewOrder",{data:res,payMethod:selectedPayment,currency:selectedCurrency,amount:convertedAmount}); - resetOrder() - }catch(e) { - setCreateLoading(false) - Alert.alert('Error', 'Failed to get preview order'); - }finally { - setCreateLoading(false) + const res = await ordersApi.createOrder( + createOrderData as CreateOrderRequest + ); + setCreateLoading(false); + navigation.navigate("PreviewOrder", { + data: res, + payMethod: selectedPayment, + currency: selectedCurrency, + amount: convertedAmount.find((item) => item.item_key === "total_amount")?.converted_amount || 0, + }); + resetOrder(); + } catch (e) { + setCreateLoading(false); + Alert.alert("Error", "Failed to get preview order"); + } finally { + setCreateLoading(false); } - - - }; return ( @@ -454,7 +538,6 @@ export const PaymentMethod = () => { 付款方式 - {loading ? ( @@ -476,8 +559,7 @@ export const PaymentMethod = () => { currentTab === tab.id && styles.tabActive, ]} onPress={() => { - - setCurrentTab(tab.id) + setCurrentTab(tab.id); }} > { - ${item?.total_price} + + ${item?.total_price} + ))} @@ -580,7 +664,16 @@ export const PaymentMethod = () => { 商品总价 - {previewOrder?.total_amount || 0} {previewOrder?.currency} + {selectedPayment === "Paypal" + ? convertedAmount.find( + (item) => item.item_key === "total_amount" + )?.converted_amount || 0 + : previewOrder?.total_amount || 0}{" "} + {selectedPayment === "Paypal" + ? selectedCurrency === "USD" + ? "USD" + : "EUR" + : previewOrder?.currency} @@ -588,8 +681,16 @@ export const PaymentMethod = () => { 中国运费 - {createOrderData?.domestic_shipping_fee || 0}{" "} - {previewOrder?.currency} + {selectedPayment === "Paypal" + ? convertedAmount.find( + (item) => item.item_key === "domestic_shipping_fee" + )?.converted_amount || 0 + : orderData?.domestic_shipping_fee || 0}{" "} + {selectedPayment === "Paypal" + ? selectedCurrency === "USD" + ? "USD" + : "EUR" + : previewOrder?.currency} @@ -598,7 +699,16 @@ export const PaymentMethod = () => { 预计国际运费 - {createOrderData?.shipping_fee || 0} {previewOrder?.currency} + {selectedPayment === "Paypal" + ? convertedAmount.find( + (item) => item.item_key === "shipping_fee" + )?.converted_amount || 0 + : orderData?.shipping_fee || 0}{" "} + {selectedPayment === "Paypal" + ? selectedCurrency === "USD" + ? "USD" + : "EUR" + : previewOrder?.currency} @@ -617,86 +727,81 @@ export const PaymentMethod = () => { Total - { - selectedPayment === 'Paypal' && selectedCurrency !== user.currency && ( - - - - {( - (previewOrder?.total_amount || 0) + - (createOrderData?.domestic_shipping_fee || 0) + - (createOrderData?.shipping_fee || 0) - ).toFixed(2)}{" "} - {previewOrder?.currency} - - - - {convertedAmount}{selectedCurrency === "USD" ? "USD" : "EUR"} - - - ) - } - - - { - selectedPayment === 'Paypal' && selectedCurrency === user.currency && ( - - - - {( - (previewOrder?.total_amount || 0) + - (createOrderData?.domestic_shipping_fee || 0) + - (createOrderData?.shipping_fee || 0) - ).toFixed(2)}{" "} - {previewOrder?.currency} - - - - - ) - } - + {selectedPayment === "Paypal" && + selectedCurrency !== user.currency && ( + + + {( + (previewOrder?.total_amount || 0) + + (createOrderData?.domestic_shipping_fee || 0) + + (createOrderData?.shipping_fee || 0) + ).toFixed(2)}{" "} + {previewOrder?.currency} + - { - selectedPayment !== 'Paypal'&& ( - + + {convertedAmount + .reduce( + (acc, item) => acc + item.converted_amount, + 0 + ) + .toFixed(2)} + {selectedCurrency === "USD" ? "USD" : "EUR"} + + + )} - {( - (previewOrder?.total_amount || 0) + - (createOrderData?.domestic_shipping_fee || 0) + - (createOrderData?.shipping_fee || 0) - ).toFixed(2)}{" "} - {previewOrder?.currency} - - ) - } + {selectedPayment === "Paypal" && + selectedCurrency === user.currency && ( + + + {convertedAmount + .reduce( + (acc, item) => acc + item.converted_amount, + 0 + ) + .toFixed(2)} + {selectedCurrency === "USD" ? "USD" : "EUR"} + + + )} + {selectedPayment !== "Paypal" && ( + + {( + (previewOrder?.total_amount || 0) + + (createOrderData?.domestic_shipping_fee || 0) + + (createOrderData?.shipping_fee || 0) + ).toFixed(2)}{" "} + {previewOrder?.currency} + + )} @@ -705,12 +810,17 @@ export const PaymentMethod = () => { {createLoading ? ( + ) : isConverting ? ( + 转换中... ) : ( 提交订单 )} @@ -724,7 +834,7 @@ export const PaymentMethod = () => { const styles = StyleSheet.create({ safeArea: { flex: 1, - backgroundColor: '#fff', + backgroundColor: "#fff", }, safeAreaContent: { flex: 1, @@ -732,7 +842,7 @@ const styles = StyleSheet.create({ }, container: { flex: 1, - backgroundColor: '#fff', + backgroundColor: "#fff", }, sectionHeader: { flexDirection: "row", @@ -818,7 +928,6 @@ const styles = StyleSheet.create({ borderRadius: 4, marginRight: 8, marginBottom: 4, - }, operatorText: { fontSize: fontSize(12), @@ -850,13 +959,11 @@ const styles = StyleSheet.create({ justifyContent: "center", position: "relative", backgroundColor: "#fff", - }, backIconContainer: { position: "absolute", left: 15, backgroundColor: "#fff", - }, titleHeading: { fontWeight: "600", @@ -864,7 +971,6 @@ const styles = StyleSheet.create({ lineHeight: 22, fontFamily: "PingFang SC", color: "black", - }, // Order Summary Styles section: { @@ -1096,8 +1202,8 @@ const styles = StyleSheet.create({ borderTopWidth: 1, borderTopColor: "#EEEEEE", paddingTop: 10, - flexDirection: 'row', - alignItems: 'center', + flexDirection: "row", + alignItems: "center", }, totalText: { fontSize: fontSize(16), @@ -1108,23 +1214,28 @@ const styles = StyleSheet.create({ marginLeft: 10, }, header: { - flexDirection: 'row', - alignItems: 'center', + flexDirection: "row", + alignItems: "center", + justifyContent: "center", padding: 10, + position: "relative", }, backButton: { padding: 5, + position: "absolute", + left: 10, + zIndex: 1, }, headerTitle: { - fontSize: fontSize(18), - fontWeight: '600', - marginLeft: 10, + fontSize: fontSize(20), + fontWeight: "600", + textAlign: "center", }, paymentContainer: { padding: 15, }, tabs: { - flexDirection: 'row', + flexDirection: "row", marginBottom: 15, }, tab: { @@ -1134,24 +1245,27 @@ const styles = StyleSheet.create({ }, tabActive: { borderBottomWidth: 2, - borderBottomColor: '#FF5100', + borderBottomColor: "#FF5100", }, bottomBar: { padding: 15, borderTopWidth: 1, - borderTopColor: '#f5f5f5', + borderTopColor: "#f5f5f5", }, submitButton: { - width: '100%', + width: "100%", height: 50, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: '#FF5100', + justifyContent: "center", + alignItems: "center", + backgroundColor: "#FF5100", borderRadius: 25, }, submitButtonText: { - color: 'white', + color: "white", fontSize: fontSize(16), - fontWeight: '600', + fontWeight: "600", + }, + disabledButton: { + backgroundColor: '#ccc', }, }); diff --git a/app/screens/previewOrder/ShippingFee.tsx b/app/screens/previewOrder/ShippingFee.tsx index 7d7945d..add1639 100644 --- a/app/screens/previewOrder/ShippingFee.tsx +++ b/app/screens/previewOrder/ShippingFee.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React from "react"; import { View, Text, @@ -26,11 +26,11 @@ 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 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"; +import { getBurialPointData } from "../../store/burialPoint"; type RootStackParamList = { ShippingFee: undefined; PaymentMethod: { freight_forwarder_address_id: number }; @@ -42,9 +42,9 @@ type ShippingFeeParams = { }; }; - export const ShippingFee = () => { - const navigation = useNavigation>(); + const navigation = + useNavigation>(); const route = useRoute, string>>(); const { @@ -65,15 +65,16 @@ export const ShippingFee = () => { const [selectedWarehouse, setSelectedWarehouse] = useState
(); const [domesticShippingFeeData, setDomesticShippingFeeData] = useState(); - const [isDomesticShippingLoading, setIsDomesticShippingLoading] = useState(false); - const [count,setCount] = useState(); + const [isDomesticShippingLoading, setIsDomesticShippingLoading] = + useState(false); + const [count, setCount] = useState(); const [apiResponses, setApiResponses] = useState({ shippingFees: false, - domesticShippingFees: false + domesticShippingFees: false, }); - const { setOrderData ,orderData,items} = useCreateOrderStore(); - const [countryCode,setCountryCode] = useState(); + const { setOrderData, orderData, items } = useCreateOrderStore(); + const [countryCode, setCountryCode] = useState(); const userStore = useUserStore(); const { logShippingConfirm } = useBurialPointStore(); const getFreightForwarderAddress = async () => { @@ -87,7 +88,7 @@ export const ShippingFee = () => { useEffect(() => { if (state.freightForwarderAddress) { console.log(state.freightForwarderAddress.other_addresses); - + setFreightForwarderAddress(state.freightForwarderAddress); // 设置默认选择第一项 if ( @@ -106,15 +107,15 @@ export const ShippingFee = () => { useEffect(() => { if (state.shippingFees) { setShippingFeeData(state.shippingFees); - setCount('正在计算运费,请不要关闭app'); - setApiResponses(prev => ({...prev, shippingFees: true})); + setCount("正在计算运费,请不要关闭app"); + setApiResponses((prev) => ({ ...prev, shippingFees: true })); } }, [state.shippingFees]); useEffect(() => { if (state.domesticShippingFees) { setDomesticShippingFeeData(state.domesticShippingFees); - setApiResponses(prev => ({...prev, domesticShippingFees: true})); + setApiResponses((prev) => ({ ...prev, domesticShippingFees: true })); } }, [state.domesticShippingFees]); @@ -145,18 +146,18 @@ export const ShippingFee = () => { 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'); + setCount("正在计算运费,请不要关闭app"); // Reset API response tracking setApiResponses({ shippingFees: false, - domesticShippingFees: false + domesticShippingFees: false, }); - + calculateShippingFee(data); calculateDomesticShippingFee(data); } @@ -164,7 +165,7 @@ export const ShippingFee = () => { } }; - const handleSelectWarehouse = (countryCode: number, label: string) => { + const handleSelectWarehouse = (countryCode: number, label: string) => { setWarehouse(label); setSelectedWarehouseLabel(label); setCountryCode(countryCode); @@ -172,35 +173,45 @@ export const ShippingFee = () => { }; const handleSubmit = () => { - if (!isDomesticShippingLoading && domesticShippingFeeData?.total_shipping_fee != null) { + 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 + 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_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 || '', + 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) + }; + 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{ + + navigation.navigate("PaymentMethod", { + freight_forwarder_address_id: selectedWarehouse?.address_id || 0, + }); + } else { Alert.alert("请选择运输方式"); } - }; return ( @@ -248,7 +259,8 @@ export const ShippingFee = () => { key={option.id} style={[ styles.shippingCard, - shippingMethod === option.id && styles.shippingCardSelected, + shippingMethod === option.id && + styles.shippingCardSelected, ]} onPress={() => { setShippingMethod(option.id); @@ -261,7 +273,9 @@ export const ShippingFee = () => { )} {option.icon} {option.label} - {option.detail} + + {option.detail} + ))} @@ -275,7 +289,9 @@ export const ShippingFee = () => { - Select a warehouse: + + Select a warehouse: + setModalVisible(true)} @@ -311,13 +327,16 @@ export const ShippingFee = () => { index.toString()} renderItem={({ item }) => ( @@ -330,7 +349,8 @@ export const ShippingFee = () => { {item.country + "|" + item.city} - {warehouse === item.country + "|" + item.city && ( + {warehouse === + item.country + "|" + item.city && ( )} @@ -345,18 +365,24 @@ export const ShippingFee = () => { {warehouse && ( - 预计到达时间: + + 预计到达时间:{" "} + - {shippingMethod === "sea" - ? "45天" - : "20天"} + {shippingMethod === "sea" ? "45天" : "20天"} - 总运费: + + 国内运费:{" "} + { }} > {isDomesticShippingLoading ? ( - {count} + + {count}{" "} + + ) : ( - {((domesticShippingFeeData?.total_shipping_fee || 0) + (shippingMethod === "sea" - ? (shippingFeeData?.total_shipping_fee_sea || 0) - : (shippingFeeData?.total_shipping_fee_air || 0))).toFixed(2)} {''} {userStore.user?.currency} + {domesticShippingFeeData?.total_shipping_fee || + 0}{" "} + {userStore.user?.currency} )} - - {/* (Cash on Delivery) */} - {/* - - 国际运费: - - {shippingMethod === "sea" - ? shippingFeeData?.total_shipping_fee_sea - : shippingFeeData?.total_shipping_fee_air} - - - */} + {isDomesticShippingLoading ? ( + + + 国际运费:{" "} + + + {count}{" "} + + + + ) : ( + + + 国际运费:{" "} + + + {shippingMethod === "sea" + ? shippingFeeData?.total_shipping_fee_sea + : shippingFeeData?.total_shipping_fee_air}{" "} + {userStore.user?.currency} + + + )} )} @@ -406,11 +467,16 @@ export const ShippingFee = () => { 提交 @@ -427,15 +493,15 @@ export const ShippingFee = () => { const styles = StyleSheet.create({ safeArea: { flex: 1, - backgroundColor: '#fff', + backgroundColor: "#fff", }, safeAreaContent: { flex: 1, - paddingTop: Platform.OS === 'android' ? 0 : 0, + paddingTop: Platform.OS === "android" ? 0 : 0, }, container: { flex: 1, - backgroundColor: '#fff', + backgroundColor: "#fff", }, section: { backgroundColor: "#fff", diff --git a/app/screens/previewOrder/perviewOrder.tsx b/app/screens/previewOrder/perviewOrder.tsx index 913aba1..49c3ac2 100644 --- a/app/screens/previewOrder/perviewOrder.tsx +++ b/app/screens/previewOrder/perviewOrder.tsx @@ -181,7 +181,7 @@ export const PreviewOrder = () => { 订单金额 - {route.params.data.actual_amount || "N/A"} {user.currency} + {route.params.amount || "N/A"} {route.params.data.currency} @@ -192,7 +192,7 @@ export const PreviewOrder = () => { route.params.data.domestic_shipping_fee + route.params.data.shipping_fee ).toFixed(2) || "N/A"}{" "} - {user.currency} + {route.params.data.currency} @@ -203,7 +203,7 @@ export const PreviewOrder = () => { 总金额 - {route.params.amount} {route.params.currency} + {route.params.data.actual_amount} {route.params.data.currency} diff --git a/app/services/api/payApi.ts b/app/services/api/payApi.ts index 5ad7be6..7e1a9f3 100644 --- a/app/services/api/payApi.ts +++ b/app/services/api/payApi.ts @@ -33,7 +33,11 @@ export interface PayInfoBody { export interface ConvertCurrencyBody { from_currency: string; to_currency: string; - amount: number; + amounts: { + total_amount?: number; + domestic_shipping_fee?: number; + shipping_fee?: number; + }; }