Browse Source

修改支付金额,货币转换

main
Your Name 3 weeks ago
parent
commit
bc18141cfc
  1. 43
      App.tsx
  2. 7
      app.json
  3. 9
      app/navigation/RootNavigation.ts
  4. 53
      app/screens/ProfileScreen.tsx
  5. 21
      app/screens/SearchResultScreen.tsx
  6. 59
      app/screens/pay/Pay.tsx
  7. 564
      app/screens/previewOrder/PaymentMethod.tsx
  8. 220
      app/screens/previewOrder/ShippingFee.tsx
  9. 6
      app/screens/previewOrder/perviewOrder.tsx
  10. 6
      app/services/api/payApi.ts

43
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 (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>

7
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": [

9
app/navigation/RootNavigation.ts

@ -0,0 +1,9 @@
import { createNavigationContainerRef } from '@react-navigation/native';
export const navigationRef = createNavigationContainerRef<any>();
export function navigate(name: string, params?: object) {
if (navigationRef.isReady()) {
navigationRef.navigate(name, params);
}
}

53
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 = () => {
<Text style={styles.uniqueHeaderTextStyle}>
{user?.username}
</Text>
<Text style={styles.elegantText}>ID: {user?.user_id}</Text>
<Text style={styles.elegantText}>
ID: {user?.user_id}
</Text>
</View>
<TouchableOpacity
style={styles.transactionSummaryBox}
@ -111,7 +114,9 @@ export const ProfileScreen = () => {
<View style={styles.promoCardContainerVip}>
<View style={styles.VipCard}>
<View style={styles.Vip}>
<Text style={styles.goldenItalicHeading}>VIP{user?.vip_level}</Text>
<Text style={styles.goldenItalicHeading}>
VIP{user?.vip_level}
</Text>
<Image
source={require("../../assets/img/折扣VIP1 (1).png")}
style={styles.VipImg}
@ -119,7 +124,9 @@ export const ProfileScreen = () => {
</View>
<View style={styles.progressBar}>
<View style={styles.progressBarFill}>
<Text style={styles.progressBarText}>40000/50000</Text>
<Text style={styles.progressBarText}>
40000/50000
</Text>
</View>
<View style={styles.progressBarLine}></View>
</View>
@ -132,7 +139,9 @@ export const ProfileScreen = () => {
</View>
<TouchableOpacity
style={styles.vipExplanationButton}
onPress={() => navigation.navigate("MemberIntroduction")}
onPress={() =>
navigation.navigate("MemberIntroduction")
}
>
<Text style={styles.vipExplanationButtonText}>
@ -161,7 +170,7 @@ export const ProfileScreen = () => {
</TouchableOpacity>
</View>
</View>
<View style={styles.notLoggedInContainer}>
<View style={styles.profileImageCircle}>
<Image
@ -169,7 +178,10 @@ export const ProfileScreen = () => {
style={styles.profileImage}
/>
</View>
<TouchableOpacity style={styles.loginButton} onPress={handleLogin}>
<TouchableOpacity
style={styles.loginButton}
onPress={handleLogin}
>
<Text style={styles.loginButtonText}></Text>
</TouchableOpacity>
</View>
@ -179,6 +191,14 @@ export const ProfileScreen = () => {
<View style={styles.verticalCenterImageGallery}>
<TouchableOpacity onPress={handleLogin}>
<Text></Text>
<TouchableOpacity
style={styles.loginButton}
onPress={() =>
Linking.openURL("exp://192.168.0.101:8084/--/payment-success")
}
>
<Text style={styles.loginButtonText}></Text>
</TouchableOpacity>
</TouchableOpacity>
</View>
@ -194,7 +214,9 @@ export const ProfileScreen = () => {
<Text style={styles.groupItemTitleText}></Text>
<TouchableOpacity
style={styles.groupItemTitleTextTout}
onPress={() => navigation.navigate("Status", { status: null })}
onPress={() =>
navigation.navigate("Status", { status: null })
}
>
<Text style={styles.groupItemTitleTextTout1}></Text>
<LeftArrowIcon size={fontSize(14)} color="#8f8684" />
@ -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
}
>
<View style={styles.groupItemContentIcon}>
<item.icon size={fontSize(38)} color="#707070" />
</View>
<Text style={styles.groupItemContentText}>{item.text}</Text>
<Text style={styles.groupItemContentText}>
{item.text}
</Text>
</TouchableOpacity>
))}
</View>
@ -234,7 +260,10 @@ export const ProfileScreen = () => {
style={styles.groupItemContentIcon}
onPress={() => navigation.navigate("BrowseHistoryScreen")}
>
<DocumentApprovedIcon size={fontSize(38)} color="#707070" />
<DocumentApprovedIcon
size={fontSize(38)}
color="#707070"
/>
</TouchableOpacity>
<Text style={styles.groupItemContentText}></Text>
</View>
@ -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: {

21
app/screens/SearchResultScreen.tsx

@ -518,16 +518,14 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp
/>
{searchText.length > 0 && (
<TouchableOpacity
onPress={() => setSearchText("")}
style={styles.clearButton}
onPress={() => setSearchText("")}
hitSlop={{ top: 10, right: 10, bottom: 10, left: 10 }}
>
<IconComponent name="close-circle" size={18} color="#999" />
</TouchableOpacity>
)}
</View>
<TouchableOpacity style={styles.searchButton} onPress={handleSearch}>
<Text style={styles.searchButtonText}>{t("cancel")}</Text>
</TouchableOpacity>
</View>
{/* 标签筛选 */}
@ -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,

59
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<PayScreenRouteProp>();
const navigation = useNavigation();
const {payUrl} = route.params;
const [payInfo, setPayInfo] = useState<PaymentInfoResponse>();
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 <View style={{ flex: 1 }}>
{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;
}}
/>

564
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;
}) => (
<View>
@ -108,18 +118,23 @@ const PaymentMethodItem = ({
/>
</View>
</TouchableOpacity>
{/* Show currency selector directly under PayPal when selected */}
{isSelected && option.label === "Paypal" && selectedCurrency && onSelectCurrency && exchangeRates && totalAmount && (
<CurrencySelector
selectedCurrency={selectedCurrency}
onSelectCurrency={onSelectCurrency}
exchangeRates={exchangeRates}
totalAmount={totalAmount}
convertedAmount={convertedAmount}
isConverting={isConverting}
/>
)}
{isSelected &&
option.label === "Paypal" &&
selectedCurrency &&
onSelectCurrency &&
exchangeRates &&
totalAmount && (
<CurrencySelector
selectedCurrency={selectedCurrency}
onSelectCurrency={onSelectCurrency}
exchangeRates={exchangeRates}
totalAmount={totalAmount}
convertedAmount={convertedAmount}
isConverting={isConverting}
/>
)}
</View>
);
@ -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) => (
<View style={styles.currencySelectorContainer}>
@ -166,15 +185,22 @@ const CurrencySelector = ({
<Text style={styles.currencyText}>EUR</Text>
</TouchableOpacity>
</View>
<View style={styles.totalContainer}>
{!isConverting && (
<Text style={styles.totalText}>
{selectedCurrency === "USD" ? "$" : "€"}{convertedAmount}
</Text>
{!isConverting && (
<Text style={styles.totalText}>
{selectedCurrency === "USD" ? "$" : "€"}
{convertedAmount
.reduce((acc, item) => acc + item.converted_amount, 0)
.toFixed(2)}
</Text>
)}
{isConverting && (
<ActivityIndicator size="small" color="#ff6000" style={styles.loadingIndicator} />
<ActivityIndicator
size="small"
color="#ff6000"
style={styles.loadingIndicator}
/>
)}
</View>
</View>
@ -206,14 +232,16 @@ export const PaymentMethod = () => {
const [loading, setLoading] = useState(false);
const { user } = useUserStore();
const [createOrderData, setCreateOrderData] = useState<createOrderDataType>();
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 = () => {
<BackIcon size={22} />
</TouchableOpacity>
<Text style={styles.headerTitle}></Text>
<View style={{ width: 20 }} />
</View>
{loading ? (
@ -476,8 +559,7 @@ export const PaymentMethod = () => {
currentTab === tab.id && styles.tabActive,
]}
onPress={() => {
setCurrentTab(tab.id)
setCurrentTab(tab.id);
}}
>
<Text
@ -567,7 +649,9 @@ export const PaymentMethod = () => {
</View>
<View style={styles.itemPrices}>
<Text style={styles.itemPrice}>${item?.total_price}</Text>
<Text style={styles.itemPrice}>
${item?.total_price}
</Text>
</View>
</View>
))}
@ -580,7 +664,16 @@ export const PaymentMethod = () => {
<Text></Text>
<View>
<Text>
{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}
</Text>
</View>
</View>
@ -588,8 +681,16 @@ export const PaymentMethod = () => {
<Text></Text>
<View>
<Text>
{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}
</Text>
</View>
</View>
@ -598,7 +699,16 @@ export const PaymentMethod = () => {
<Text></Text>
<View>
<Text>
{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}
</Text>
</View>
</View>
@ -617,86 +727,81 @@ export const PaymentMethod = () => {
Total
</Text>
{
selectedPayment === 'Paypal' && selectedCurrency !== user.currency && (
<View style={{flexDirection:'row'}}>
<Text
style={{
fontSize: fontSize(18),
fontWeight: "600",
color: "#151515",
textDecorationLine: 'line-through'
}}
>
{(
(previewOrder?.total_amount || 0) +
(createOrderData?.domestic_shipping_fee || 0) +
(createOrderData?.shipping_fee || 0)
).toFixed(2)}{" "}
{previewOrder?.currency}
</Text>
<Text
style={{
fontSize: fontSize(18),
fontWeight: "600",
color: "#ff6000",
marginLeft:10
}}
>
{convertedAmount}{selectedCurrency === "USD" ? "USD" : "EUR"}
</Text>
</View>
)
}
{
selectedPayment === 'Paypal' && selectedCurrency === user.currency && (
<View style={{flexDirection:'row'}}>
<Text
style={{
fontSize: fontSize(18),
fontWeight: "600",
color: "#ff6000",
}}
>
{(
(previewOrder?.total_amount || 0) +
(createOrderData?.domestic_shipping_fee || 0) +
(createOrderData?.shipping_fee || 0)
).toFixed(2)}{" "}
{previewOrder?.currency}
</Text>
</View>
)
}
{selectedPayment === "Paypal" &&
selectedCurrency !== user.currency && (
<View style={{ flexDirection: "row" }}>
<Text
style={{
fontSize: fontSize(18),
fontWeight: "600",
color: "#151515",
textDecorationLine: "line-through",
}}
>
{(
(previewOrder?.total_amount || 0) +
(createOrderData?.domestic_shipping_fee || 0) +
(createOrderData?.shipping_fee || 0)
).toFixed(2)}{" "}
{previewOrder?.currency}
</Text>
{
selectedPayment !== 'Paypal'&& (
<Text
style={{
fontSize: fontSize(18),
fontWeight: "600",
color: "#ff6000",
}}
>
<Text
style={{
fontSize: fontSize(18),
fontWeight: "600",
color: "#ff6000",
marginLeft: 10,
}}
>
{convertedAmount
.reduce(
(acc, item) => acc + item.converted_amount,
0
)
.toFixed(2)}
{selectedCurrency === "USD" ? "USD" : "EUR"}
</Text>
</View>
)}
{(
(previewOrder?.total_amount || 0) +
(createOrderData?.domestic_shipping_fee || 0) +
(createOrderData?.shipping_fee || 0)
).toFixed(2)}{" "}
{previewOrder?.currency}
</Text>
)
}
{selectedPayment === "Paypal" &&
selectedCurrency === user.currency && (
<View style={{ flexDirection: "row" }}>
<Text
style={{
fontSize: fontSize(18),
fontWeight: "600",
color: "#ff6000",
}}
>
{convertedAmount
.reduce(
(acc, item) => acc + item.converted_amount,
0
)
.toFixed(2)}
{selectedCurrency === "USD" ? "USD" : "EUR"}
</Text>
</View>
)}
{selectedPayment !== "Paypal" && (
<Text
style={{
fontSize: fontSize(18),
fontWeight: "600",
color: "#ff6000",
}}
>
{(
(previewOrder?.total_amount || 0) +
(createOrderData?.domestic_shipping_fee || 0) +
(createOrderData?.shipping_fee || 0)
).toFixed(2)}{" "}
{previewOrder?.currency}
</Text>
)}
</View>
</View>
</View>
@ -705,12 +810,17 @@ export const PaymentMethod = () => {
<View style={styles.bottomBar}>
<TouchableOpacity
style={styles.submitButton}
style={[
styles.submitButton,
(!selectedPayment || createLoading || isConverting) && styles.disabledButton
]}
onPress={handleSubmit}
disabled={!selectedPayment || createLoading}
disabled={!selectedPayment || createLoading || isConverting}
>
{createLoading ? (
<ActivityIndicator size="small" color="#fff" />
) : isConverting ? (
<Text style={styles.submitButtonText}>...</Text>
) : (
<Text style={styles.submitButtonText}></Text>
)}
@ -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',
},
});

220
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<NativeStackNavigationProp<RootStackParamList>>();
const navigation =
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
const route =
useRoute<RouteProp<Record<string, ShippingFeeParams>, string>>();
const {
@ -65,15 +65,16 @@ export const ShippingFee = () => {
const [selectedWarehouse, setSelectedWarehouse] = useState<Address>();
const [domesticShippingFeeData, setDomesticShippingFeeData] =
useState<DomesticShippingFeeData>();
const [isDomesticShippingLoading, setIsDomesticShippingLoading] = useState(false);
const [count,setCount] = useState<string>();
const [isDomesticShippingLoading, setIsDomesticShippingLoading] =
useState(false);
const [count, setCount] = useState<string>();
const [apiResponses, setApiResponses] = useState({
shippingFees: false,
domesticShippingFees: false
domesticShippingFees: false,
});
const { setOrderData ,orderData,items} = useCreateOrderStore();
const [countryCode,setCountryCode] = useState<number>();
const { setOrderData, orderData, items } = useCreateOrderStore();
const [countryCode, setCountryCode] = useState<number>();
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 = () => {
)}
<Text style={styles.shippingIcon}>{option.icon}</Text>
<Text style={styles.shippingLabel}>{option.label}</Text>
<Text style={styles.shippingDetail}>{option.detail}</Text>
<Text style={styles.shippingDetail}>
{option.detail}
</Text>
</TouchableOpacity>
))}
</View>
@ -275,7 +289,9 @@ export const ShippingFee = () => {
</View>
<View style={{ marginTop: 12 }}>
<View style={styles.selectBox}>
<Text style={styles.selectLabel}>Select a warehouse:</Text>
<Text style={styles.selectLabel}>
Select a warehouse:
</Text>
<TouchableOpacity
style={styles.selectWrapper}
onPress={() => setModalVisible(true)}
@ -311,13 +327,16 @@ export const ShippingFee = () => {
</TouchableOpacity>
</View>
<FlatList
data={freightForwarderAddress?.other_addresses || []}
data={
freightForwarderAddress?.other_addresses || []
}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<TouchableOpacity
style={[
styles.optionItem,
warehouse === item.country + "|" + item.city &&
warehouse ===
item.country + "|" + item.city &&
styles.selectedOption,
]}
onPress={() =>
@ -330,7 +349,8 @@ export const ShippingFee = () => {
<Text style={styles.optionText}>
{item.country + "|" + item.city}
</Text>
{warehouse === item.country + "|" + item.city && (
{warehouse ===
item.country + "|" + item.city && (
<Text style={styles.checkmark}></Text>
)}
</TouchableOpacity>
@ -345,18 +365,24 @@ export const ShippingFee = () => {
{warehouse && (
<View style={styles.shippingInfo}>
<Text style={styles.shippingInfoRow}>
<Text style={styles.shippingInfoLabel}>: </Text>
<Text style={styles.shippingInfoLabel}>
:{" "}
</Text>
<Text
style={{ flex: 1, textAlign: "left", marginLeft: 10 }}
style={{
flex: 1,
textAlign: "left",
marginLeft: 10,
}}
>
{shippingMethod === "sea"
? "45天"
: "20天"}
{shippingMethod === "sea" ? "45天" : "20天"}
</Text>
</Text>
<View style={styles.shippingInfoRow}>
<Text style={styles.shippingInfoLabel}>: </Text>
<Text style={styles.shippingInfoLabel}>
:{" "}
</Text>
<Text
style={{
color: "#ff6000",
@ -367,36 +393,71 @@ export const ShippingFee = () => {
}}
>
{isDomesticShippingLoading ? (
<Text style={{ color: "#ff6000",alignItems:"center" }}>{count} <ActivityIndicator size="small" color="#ff6000" style={{ marginLeft: 5 }} /></Text>
<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}
{domesticShippingFeeData?.total_shipping_fee ||
0}{" "}
{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> */}
{isDomesticShippingLoading ? (
<View style={styles.shippingInfoRow}>
<Text style={styles.shippingInfoLabel}>
:{" "}
</Text>
<Text
style={{
color: "#ff6000",
flex: 1,
textAlign: "left",
marginLeft: 10,
fontWeight: "600",
}}
>
{count}{" "}
<ActivityIndicator
size="small"
color="#ff6000"
style={{ marginLeft: 5 }}
/>
</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}{" "}
{userStore.user?.currency}
</Text>
</View>
)}
</View>
)}
</View>
@ -406,11 +467,16 @@ export const ShippingFee = () => {
<TouchableOpacity
style={[
styles.primaryButtonStyle,
(isDomesticShippingLoading || domesticShippingFeeData?.total_shipping_fee == null)
? styles.disabledButtonStyle : {}
isDomesticShippingLoading ||
domesticShippingFeeData?.total_shipping_fee == null
? styles.disabledButtonStyle
: {},
]}
onPress={handleSubmit}
disabled={isDomesticShippingLoading || domesticShippingFeeData?.total_shipping_fee == null}
disabled={
isDomesticShippingLoading ||
domesticShippingFeeData?.total_shipping_fee == null
}
>
<Text style={styles.buttonText}></Text>
</TouchableOpacity>
@ -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",

6
app/screens/previewOrder/perviewOrder.tsx

@ -181,7 +181,7 @@ export const PreviewOrder = () => {
<View style={styles.infoRow}>
<Text style={styles.infoLabel}></Text>
<Text style={styles.infoValue}>
{route.params.data.actual_amount || "N/A"} {user.currency}
{route.params.amount || "N/A"} {route.params.data.currency}
</Text>
</View>
@ -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}
</Text>
</View>
</View>
@ -203,7 +203,7 @@ export const PreviewOrder = () => {
<View style={styles.totalRow}>
<Text style={styles.totalLabel}></Text>
<Text style={styles.totalValue}>
{route.params.amount} {route.params.currency}
{route.params.data.actual_amount} {route.params.data.currency}
</Text>
</View>
</View>

6
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;
};
}

Loading…
Cancel
Save