Mac 2 weeks ago
parent
commit
46aede5804
  1. 1
      FINAL_REDIRECT_FIX.md
  2. 6
      app.json
  3. 4
      app/screens/BalanceScreen/PhoneNumberInputModal.tsx
  4. 4
      app/screens/ProfileScreen.tsx
  5. 1248
      app/screens/banner/ShippingDetailsSection.tsx
  6. 64
      app/screens/loginList/index.tsx
  7. 75
      app/screens/pay/Pay.tsx
  8. 78
      app/screens/previewOrder/perviewOrder.tsx
  9. 4
      app/screens/productStatus/OrderDatails.tsx
  10. 12
      app/services/api/apiClient.ts
  11. 45
      app/services/api/payApi.ts
  12. 96
      package-lock.json
  13. 2
      package.json
  14. 552
      yarn.lock

1
FINAL_REDIRECT_FIX.md

@ -0,0 +1 @@

6
app.json

@ -7,7 +7,7 @@
"icon": "./assets/icon.png", "icon": "./assets/icon.png",
"userInterfaceStyle": "light", "userInterfaceStyle": "light",
"newArchEnabled": true, "newArchEnabled": true,
"scheme": "myapp", "scheme": "brainnelapp",
"owner":"brainnel", "owner":"brainnel",
"deepLinking": true, "deepLinking": true,
"splash": { "splash": {
@ -22,7 +22,7 @@
"CFBundleURLTypes": [ "CFBundleURLTypes": [
{ {
"CFBundleURLSchemes": [ "CFBundleURLSchemes": [
"myapp" "brainnelapp"
] ]
} }
] ]
@ -43,7 +43,7 @@
"action": "VIEW", "action": "VIEW",
"data": [ "data": [
{ {
"scheme": "myapp" "scheme": "brainnelapp"
} }
], ],
"category": [ "category": [

4
app/screens/BalanceScreen/PhoneNumberInputModal.tsx

@ -35,7 +35,7 @@ interface PhoneNumberInputModalProps {
} }
type RootStackParamList = { type RootStackParamList = {
Pay: { payUrl: string }; Pay: { payUrl: string, method: string, order_id: string };
} }
const PhoneNumberInputModal = ({ const PhoneNumberInputModal = ({
@ -87,6 +87,8 @@ const PhoneNumberInputModal = ({
navigation.navigate("Pay", { navigation.navigate("Pay", {
payUrl: res.payment.payment_url, payUrl: res.payment.payment_url,
method: paymentParams.payment_method,
order_id: res.payment.order_id.toString(),
}); });
setIsSubmitting(false) setIsSubmitting(false)

4
app/screens/ProfileScreen.tsx

@ -41,9 +41,13 @@ type RootStackParamList = {
}; };
export const ProfileScreen = () => { export const ProfileScreen = () => {
const handleLogin = async () => { const handleLogin = async () => {
navigation.navigate("Login"); navigation.navigate("Login");
}; };
const { user } = useUserStore(); const { user } = useUserStore();
const { t } = useTranslation(); const { t } = useTranslation();

1248
app/screens/banner/ShippingDetailsSection.tsx

File diff suppressed because it is too large Load Diff

64
app/screens/loginList/index.tsx

@ -9,7 +9,7 @@ import {
BackHandler, BackHandler,
Image, Image,
Modal, Modal,
SafeAreaView SafeAreaView,
} from "react-native"; } from "react-native";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
@ -18,6 +18,12 @@ import fontSize from "../../utils/fontsizeUtils";
import EmailLoginModal from "./EmailLoginModal"; import EmailLoginModal from "./EmailLoginModal";
import PhoneLoginModal from "./PhoneLoginModal"; import PhoneLoginModal from "./PhoneLoginModal";
import * as WebBrowser from "expo-web-browser";
import * as AuthSession from "expo-auth-session";
import * as Linking from "expo-linking";
import * as Google from "expo-auth-session/providers/google";
WebBrowser.maybeCompleteAuthSession();
type RootStackParamList = { type RootStackParamList = {
Login: undefined; Login: undefined;
@ -32,6 +38,12 @@ type LoginScreenProps = {
isModal?: boolean; isModal?: boolean;
}; };
const CLIENT_ID =
"529750832779-osemooqkar78m8lhrn9dvbvi98fr4g08.apps.googleusercontent.com"; // from Google Cloud
const REDIRECT_URI = AuthSession.makeRedirectUri({
native: "brainnelapp://redirect",
});
export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => { export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const navigation = const navigation =
@ -77,10 +89,31 @@ export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
} }
}; };
// 处理谷歌登录 const discovery = {
const handleGoogleLogin = async () => { authorizationEndpoint: "https://accounts.google.com/o/oauth2/v2/auth",
navigation.navigate("Google"); tokenEndpoint: "https://oauth2.googleapis.com/token",
revocationEndpoint: "https://oauth2.googleapis.com/revoke",
}; };
const [request, response, handleGoogleLogin] = AuthSession.useAuthRequest(
{
clientId: CLIENT_ID,
scopes: ["openid", "profile", "email"],
redirectUri: REDIRECT_URI,
responseType: AuthSession.ResponseType.Code,
},
discovery
);
React.useEffect(() => {
if (response?.type === "success") {
const { code } = response.params;
console.log("授权码:", code);
}
}, [response]);
// 处理谷歌登录
// const handleGoogleLogin = async () => {
// // navigation.navigate("Google");
// };
// 处理Facebook登录 // 处理Facebook登录
const handleFacebookLogin = () => { const handleFacebookLogin = () => {
@ -180,7 +213,7 @@ export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
{/* 登录按钮 */} {/* 登录按钮 */}
<TouchableOpacity <TouchableOpacity
style={styles.loginButton} style={styles.loginButton}
onPress={handleGoogleLogin} onPress={() => handleGoogleLogin()}
> >
<View style={styles.loginButtonIcon}> <View style={styles.loginButtonIcon}>
<Image <Image
@ -188,7 +221,9 @@ export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
style={{ width: 20, height: 20 }} style={{ width: 20, height: 20 }}
/> />
</View> </View>
<Text style={styles.loginButtonText}>{t("continueWithGoogle")}</Text> <Text style={styles.loginButtonText}>
{t("continueWithGoogle")}
</Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity <TouchableOpacity
@ -211,7 +246,9 @@ export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
<View style={[styles.loginButtonIcon, styles.appleIconBg]}> <View style={[styles.loginButtonIcon, styles.appleIconBg]}>
<Text>🍎</Text> <Text>🍎</Text>
</View> </View>
<Text style={styles.loginButtonText}>{t("continueWithApple")}</Text> <Text style={styles.loginButtonText}>
{t("continueWithApple")}
</Text>
</TouchableOpacity> </TouchableOpacity>
)} )}
@ -252,7 +289,8 @@ export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
{/* 服务条款 */} {/* 服务条款 */}
<View style={styles.termsContainer}> <View style={styles.termsContainer}>
<Text style={styles.terms}> <Text style={styles.terms}>
{t("termsText")} <Text style={styles.link}>{t("termsOfUse")}</Text> {t("termsText")}{" "}
<Text style={styles.link}>{t("termsOfUse")}</Text>
</Text> </Text>
<Text style={styles.terms}> <Text style={styles.terms}>
{t("and")} <Text style={styles.link}>{t("privacyPolicy")}</Text> {t("and")} <Text style={styles.link}>{t("privacyPolicy")}</Text>
@ -262,16 +300,10 @@ export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
</View> </View>
{/* 邮箱登录模态框 - 直接渲染 */} {/* 邮箱登录模态框 - 直接渲染 */}
<EmailLoginModal <EmailLoginModal visible={emailModalVisible} onClose={hideEmailModal} />
visible={emailModalVisible}
onClose={hideEmailModal}
/>
{/* 手机登录模态框 - 直接渲染 */} {/* 手机登录模态框 - 直接渲染 */}
<PhoneLoginModal <PhoneLoginModal visible={phoneModalVisible} onClose={hidePhoneModal} />
visible={phoneModalVisible}
onClose={hidePhoneModal}
/>
</SafeAreaView> </SafeAreaView>
); );
}; };

75
app/screens/pay/Pay.tsx

@ -1,6 +1,6 @@
import { View, StyleSheet, Alert } from "react-native"; import { View, StyleSheet, Alert } from "react-native";
import { useRoute, RouteProp, useNavigation } from "@react-navigation/native"; import { useRoute, RouteProp, useNavigation } from "@react-navigation/native";
import { useEffect, useState } from "react"; import { useEffect, useState, useRef } from "react";
import { payApi, PaymentInfoResponse } from "../../services/api/payApi"; import { payApi, PaymentInfoResponse } from "../../services/api/payApi";
import { WebView } from "react-native-webview"; import { WebView } from "react-native-webview";
import * as Linking from "expo-linking"; import * as Linking from "expo-linking";
@ -8,7 +8,7 @@ import { navigate, navigationRef } from "../../navigation/RootNavigation";
type PayScreenRouteProp = RouteProp< type PayScreenRouteProp = RouteProp<
{ {
Pay: { payUrl: string }; Pay: { payUrl: string; method: string; order_id: string };
}, },
"Pay" "Pay"
>; >;
@ -19,6 +19,63 @@ export const Pay = () => {
const navigation = useNavigation(); const navigation = useNavigation();
const { payUrl } = route.params; const { payUrl } = route.params;
const [payInfo, setPayInfo] = useState<PaymentInfoResponse>(); const [payInfo, setPayInfo] = useState<PaymentInfoResponse>();
const pollIntervalRef = useRef<NodeJS.Timeout | null>(null);
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
// 轮询 wavePay 状态
const pollWavePayStatus = () => {
payApi
.wavePay(route.params.order_id)
.then((res) => {
console.log(res);
if (res.pay_status === 1) {
safeNavigate("PaymentSuccessScreen", res);
// 支付状态为1,停止轮询和超时定时器
if (pollIntervalRef.current) {
clearInterval(pollIntervalRef.current);
pollIntervalRef.current = null;
}
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
timeoutRef.current = null;
}
}
})
.catch((error) => {
console.error("WavePay 轮询错误:", error);
});
};
// 开始轮询
const startPolling = () => {
// 立即执行一次
pollWavePayStatus();
// 设置轮询,每2秒执行一次
if (!pollIntervalRef.current) {
pollIntervalRef.current = setInterval(pollWavePayStatus, 2000);
}
// 设置50秒超时
if (!timeoutRef.current) {
timeoutRef.current = setTimeout(() => {
// 超时处理:停止轮询并导航到错误页面
stopPolling();
safeNavigate("PayError", {});
}, 50000); // 50秒
}
};
// 停止轮询
const stopPolling = () => {
if (pollIntervalRef.current) {
clearInterval(pollIntervalRef.current);
pollIntervalRef.current = null;
}
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
timeoutRef.current = null;
}
};
useEffect(() => { useEffect(() => {
// 设置处理深度链接的监听器 // 设置处理深度链接的监听器
@ -39,6 +96,8 @@ export const Pay = () => {
return () => { return () => {
// 清理订阅 // 清理订阅
subscription.remove(); subscription.remove();
// 清理轮询
stopPolling();
}; };
}, []); }, []);
@ -48,13 +107,11 @@ export const Pay = () => {
if (url && url.includes("payment_success=true")) { if (url && url.includes("payment_success=true")) {
// 如果网页URL中包含成功参数,可以在这里处理 // 如果网页URL中包含成功参数,可以在这里处理
Alert.alert("检测到支付成功!"); Alert.alert("检测到支付成功!");
// navigation.navigate('PaymentConfirmation');
} }
}; };
// 导航辅助函数,尝试使用多种方式导航 // 导航辅助函数,尝试使用多种方式导航
const safeNavigate = (routeName: string, params: any) => { const safeNavigate = (routeName: string, params: any) => {
try { try {
// 尝试使用组件内的navigation // 尝试使用组件内的navigation
// @ts-ignore 忽略可能的类型错误 // @ts-ignore 忽略可能的类型错误
@ -93,7 +150,14 @@ export const Pay = () => {
originWhitelist={["*"]} 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" 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) => { onShouldStartLoadWithRequest={(request) => {
// 检查URL是否包含支付成功的参数 // wave 轮询处理
if (route.params.method === "wave") {
// 开始轮询 wavePay 状态
startPolling();
}
// 检查URL是否包含支付成功的参数 paypal
if (route.params.method === "paypal") {
const { url } = request; const { url } = request;
if (url) { if (url) {
// 解析参数 // 解析参数
@ -127,6 +191,7 @@ export const Pay = () => {
// return false; // 不在WebView中加载 // return false; // 不在WebView中加载
} }
} }
}
// 允许所有其他请求 // 允许所有其他请求
return true; return true;

78
app/screens/previewOrder/perviewOrder.tsx

@ -1,4 +1,4 @@
import React from 'react'; import React from "react";
import { import {
View, View,
Text, Text,
@ -11,11 +11,16 @@ import {
Platform, Platform,
StatusBar, StatusBar,
SafeAreaView, SafeAreaView,
BackHandler BackHandler,
} from "react-native"; } from "react-native";
import useCreateOrderStore from "../../store/createOrder"; import useCreateOrderStore from "../../store/createOrder";
import BackIcon from "../../components/BackIcon"; import BackIcon from "../../components/BackIcon";
import { useNavigation, useRoute, RouteProp, useFocusEffect } from "@react-navigation/native"; import {
useNavigation,
useRoute,
RouteProp,
useFocusEffect,
} from "@react-navigation/native";
import { NativeStackNavigationProp } from "@react-navigation/native-stack"; import { NativeStackNavigationProp } from "@react-navigation/native-stack";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import useUserStore from "../../store/user"; import useUserStore from "../../store/user";
@ -34,7 +39,7 @@ type RootStackParamList = {
currency: string; currency: string;
amount: number; amount: number;
}; };
Pay: { payUrl: string }; Pay: { payUrl: string; method: string; order_id: string };
OrderDetails: { orderId?: number }; OrderDetails: { orderId?: number };
}; };
@ -70,9 +75,10 @@ export const PreviewOrder = () => {
}; };
// 添加返回键监听(Android) // 添加返回键监听(Android)
BackHandler.addEventListener('hardwareBackPress', onBackPress); BackHandler.addEventListener("hardwareBackPress", onBackPress);
return () => BackHandler.removeEventListener('hardwareBackPress', onBackPress); return () =>
BackHandler.removeEventListener("hardwareBackPress", onBackPress);
}, [navigation]) }, [navigation])
); );
@ -99,11 +105,16 @@ export const PreviewOrder = () => {
.getPayInfo(data) .getPayInfo(data)
.then((res) => { .then((res) => {
if (res.success) { if (res.success) {
logPreviewOrder(navigation.getState().routes[navigation.getState().index - 1]?.name as string); logPreviewOrder(
navigation.getState().routes[navigation.getState().index - 1]
?.name as string
);
console.log(getBurialPointData()); console.log(getBurialPointData());
navigation.replace("Pay", { navigation.replace("Pay", {
payUrl: res.payment_url, payUrl: res.payment_url,
method: route.params.payMethod,
order_id: route.params.data.order_id.toString(),
}); });
} }
}) })
@ -134,14 +145,18 @@ export const PreviewOrder = () => {
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<Text style={styles.titleHeading}>{t("order.preview.pay_now")}</Text> <Text style={styles.titleHeading}>
{t("order.preview.pay_now")}
</Text>
</View> </View>
<ScrollView style={styles.scrollContainer}> <ScrollView style={styles.scrollContainer}>
<View style={styles.mainContent}> <View style={styles.mainContent}>
{/* Payment Method Section */} {/* Payment Method Section */}
<View style={styles.section}> <View style={styles.section}>
<Text style={styles.sectionTitle}>{t("order.preview.payment_method")}</Text> <Text style={styles.sectionTitle}>
{t("order.preview.payment_method")}
</Text>
<View style={styles.paymentMethodContainer}> <View style={styles.paymentMethodContainer}>
<Text style={styles.paymentMethodText}> <Text style={styles.paymentMethodText}>
{route.params.payMethod} {route.params.payMethod}
@ -150,7 +165,9 @@ export const PreviewOrder = () => {
{showPhoneInput && ( {showPhoneInput && (
<View style={styles.phoneInputContainer}> <View style={styles.phoneInputContainer}>
<Text style={styles.phoneInputLabel}>{t("order.preview.enter_phone")}</Text> <Text style={styles.phoneInputLabel}>
{t("order.preview.enter_phone")}
</Text>
<TextInput <TextInput
style={styles.phoneInput} style={styles.phoneInput}
value={phoneNumber} value={phoneNumber}
@ -164,17 +181,23 @@ export const PreviewOrder = () => {
{/* Order Info Section */} {/* Order Info Section */}
<View style={styles.section}> <View style={styles.section}>
<Text style={styles.sectionTitle}>{t("order.preview.payment_info")}</Text> <Text style={styles.sectionTitle}>
{t("order.preview.payment_info")}
</Text>
<View style={styles.infoRow}> <View style={styles.infoRow}>
<Text style={styles.infoLabel}>{t("order.preview.name")}</Text> <Text style={styles.infoLabel}>
{t("order.preview.name")}
</Text>
<Text style={styles.infoValue}> <Text style={styles.infoValue}>
{route.params?.data.receiver_name || "N/A"} {route.params?.data.receiver_name || "N/A"}
</Text> </Text>
</View> </View>
<View style={styles.infoRow}> <View style={styles.infoRow}>
<Text style={styles.infoLabel}>{t("order.preview.phone")}</Text> <Text style={styles.infoLabel}>
{t("order.preview.phone")}
</Text>
<Text style={styles.infoValue}> <Text style={styles.infoValue}>
{route.params?.data.receiver_phone || "N/A"} {route.params?.data.receiver_phone || "N/A"}
</Text> </Text>
@ -190,14 +213,18 @@ export const PreviewOrder = () => {
)} )}
<View style={styles.infoRow}> <View style={styles.infoRow}>
<Text style={styles.infoLabel}>{t("order.preview.country")}</Text> <Text style={styles.infoLabel}>
{t("order.preview.country")}
</Text>
<Text style={styles.infoValue}> <Text style={styles.infoValue}>
{route.params?.data.receiver_country || "N/A"} {route.params?.data.receiver_country || "N/A"}
</Text> </Text>
</View> </View>
<View style={styles.infoRow}> <View style={styles.infoRow}>
<Text style={styles.infoLabel}>{t("order.preview.shipping_address")}</Text> <Text style={styles.infoLabel}>
{t("order.preview.shipping_address")}
</Text>
<Text style={styles.infoValue}> <Text style={styles.infoValue}>
{route.params?.data.receiver_address || "N/A"} {route.params?.data.receiver_address || "N/A"}
</Text> </Text>
@ -224,11 +251,16 @@ export const PreviewOrder = () => {
{/* Order Summary Section */} {/* Order Summary Section */}
<View style={styles.section}> <View style={styles.section}>
<Text style={styles.sectionTitle}>{t("order.preview.order_total")}</Text> <Text style={styles.sectionTitle}>
{t("order.preview.order_total")}
</Text>
<View style={styles.totalRow}> <View style={styles.totalRow}>
<Text style={styles.totalLabel}>{t("order.preview.total_amount")}</Text> <Text style={styles.totalLabel}>
{t("order.preview.total_amount")}
</Text>
<Text style={styles.totalValue}> <Text style={styles.totalValue}>
{route.params.data.actual_amount} {route.params.data.currency} {route.params.data.actual_amount}{" "}
{route.params.data.currency}
</Text> </Text>
</View> </View>
</View> </View>
@ -249,7 +281,9 @@ export const PreviewOrder = () => {
{loading ? ( {loading ? (
<ActivityIndicator size="small" color="#ffffff" /> <ActivityIndicator size="small" color="#ffffff" />
) : ( ) : (
<Text style={styles.buttonText}>{t("order.preview.confirm_payment")}</Text> <Text style={styles.buttonText}>
{t("order.preview.confirm_payment")}
</Text>
)} )}
</TouchableOpacity> </TouchableOpacity>
</View> </View>
@ -262,15 +296,15 @@ export const PreviewOrder = () => {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
safeArea: { safeArea: {
flex: 1, flex: 1,
backgroundColor: '#fff', backgroundColor: "#fff",
}, },
safeAreaContent: { safeAreaContent: {
flex: 1, flex: 1,
paddingTop: Platform.OS === 'android' ? 0 : 0, paddingTop: Platform.OS === "android" ? 0 : 0,
}, },
container: { container: {
flex: 1, flex: 1,
backgroundColor: '#fff', backgroundColor: "#fff",
}, },
scrollContainer: { scrollContainer: {
flex: 1, flex: 1,

4
app/screens/productStatus/OrderDatails.tsx

@ -284,6 +284,8 @@ export const OrderDetails = () => {
setShowPaymentModal(false); setShowPaymentModal(false);
navigation.navigate("Pay", { navigation.navigate("Pay", {
payUrl: res.payment_url, payUrl: res.payment_url,
method: selectedPayment,
order_id: orderDetails.order_id,
}); });
}else{ }else{
Alert.alert(t("error"), t("pay.payment_failed")); Alert.alert(t("error"), t("pay.payment_failed"));
@ -352,6 +354,8 @@ export const OrderDetails = () => {
// 打开支付页面 // 打开支付页面
navigation.navigate("Pay", { navigation.navigate("Pay", {
payUrl: response.payment_url, payUrl: response.payment_url,
method: paymentParams.payment_method,
order_id: orderDetails?.order_id || "",
}); });
} else { } else {
Alert.alert(t("error"), t("order.error.payment_update")); Alert.alert(t("error"), t("order.error.payment_update"));

12
app/services/api/apiClient.ts

@ -54,6 +54,7 @@ const apiClient: AxiosInstance = axios.create({
// 请求拦截器 // 请求拦截器
apiClient.interceptors.request.use( apiClient.interceptors.request.use(
async (config: InternalAxiosRequestConfig) => { async (config: InternalAxiosRequestConfig) => {
const baseUrl = config.baseURL || ''; const baseUrl = config.baseURL || '';
let fullUrl = baseUrl + config.url; let fullUrl = baseUrl + config.url;
if (config.params) { if (config.params) {
@ -61,6 +62,17 @@ apiClient.interceptors.request.use(
fullUrl += (fullUrl.includes('?') ? '&' : '?') + params.toString(); fullUrl += (fullUrl.includes('?') ? '&' : '?') + params.toString();
} }
// 根据平台设置请求方法大小写
if (config.method) {
if (Platform.OS === 'ios') {
// iOS使用小写方法
config.method = config.method.toLowerCase();
} else if (Platform.OS === 'android') {
// Android使用大写方法
config.method = config.method.toUpperCase();
}
}
// console.log("环境:", __DEV__ ? "开发环境" : "生产环境"); // console.log("环境:", __DEV__ ? "开发环境" : "生产环境");
// console.log("请求方法:", config.method); // console.log("请求方法:", config.method);
// console.log("完整URL:", fullUrl); // console.log("完整URL:", fullUrl);

45
app/services/api/payApi.ts

@ -1,4 +1,4 @@
import apiService from './apiClient'; import apiService from "./apiClient";
// 支付方式类型定义 // 支付方式类型定义
export interface PaymentMethod { export interface PaymentMethod {
@ -89,8 +89,7 @@ export interface RechargeRecommendAmountResponse {
currency: string; currency: string;
} }
export interface Transaction {
export interface Transaction {
transaction_id: string; transaction_id: string;
type: "order_payment"; // Assuming 'order_payment' is the only possible type for this dataset type: "order_payment"; // Assuming 'order_payment' is the only possible type for this dataset
amount: number; amount: number;
@ -107,10 +106,17 @@ export interface TransactionsResponse {
page_size: number; page_size: number;
} }
export interface WavePayResponse {
order_id: string;
pay_status: number;
}
export const payApi = { export const payApi = {
// 获取当前国家支付方式 // 获取当前国家支付方式
getCountryPaymentMethods: () => { getCountryPaymentMethods: () => {
return apiService.get<PaymentMethodsResponse>('/api/payment/country_payment_methods/'); return apiService.get<PaymentMethodsResponse>(
"/api/payment/country_payment_methods/"
);
}, },
// 获取支付信息 // 获取支付信息
@ -124,27 +130,44 @@ export const payApi = {
}, },
// 支付成功的回调 // 支付成功的回调
paySuccessCallback: (paymentId:string,PayerID:string) => { paySuccessCallback: (paymentId: string, PayerID: string) => {
return apiService.post<PaySuccessCallbackBody>(`/api/payment/paypal/execute/`,{paymentId,PayerID}); return apiService.post<PaySuccessCallbackBody>(
`/api/payment/paypal/execute/`,
{ paymentId, PayerID }
);
}, },
// 新增充值接口 // 新增充值接口
initiateRecharge: (data: RechargeInitiateBody) => { initiateRecharge: (data: RechargeInitiateBody) => {
return apiService.post<RechargeInitiateResponse>('/api/recharge/initiate/', data); return apiService.post<RechargeInitiateResponse>(
"/api/recharge/initiate/",
data
);
}, },
// 获取充值历史 // 获取充值历史
getRechargeHistory: () => { getRechargeHistory: () => {
return apiService.get<rechargeHistory[]>('/api/recharge/records/'); return apiService.get<rechargeHistory[]>("/api/recharge/records/");
}, },
//获取充值推荐金额 //获取充值推荐金额
getRechargeRecommendAmount: () => { getRechargeRecommendAmount: () => {
return apiService.get<RechargeRecommendAmountResponse>('/api/recharge/recommended-amounts/'); return apiService.get<RechargeRecommendAmountResponse>(
"/api/recharge/recommended-amounts/"
);
}, },
// 获取流水 // 获取流水
getTransactionHistory: (page:number,page_size:number) => { getTransactionHistory: (page: number, page_size: number) => {
return apiService.get<TransactionsResponse>(`/api/users/me/transactions/?page=${page}&page_size=${page_size}`); return apiService.get<TransactionsResponse>(
`/api/users/me/transactions/?page=${page}&page_size=${page_size}`
);
},
// wave 支付
wavePay: (order_id: string) => {
return apiService.get<WavePayResponse>(
`/api/orders/${order_id}/payment-status/`
);
}, },
}; };

96
package-lock.json generated

@ -10,6 +10,7 @@
"license": "0BSD", "license": "0BSD",
"dependencies": { "dependencies": {
"@expo/metro-runtime": "~4.0.1", "@expo/metro-runtime": "~4.0.1",
"@expo/vector-icons": "^14.1.0",
"@react-native-async-storage/async-storage": "1.23.1", "@react-native-async-storage/async-storage": "1.23.1",
"@react-native-community/checkbox": "^0.5.17", "@react-native-community/checkbox": "^0.5.17",
"@react-native-community/datetimepicker": "8.2.0", "@react-native-community/datetimepicker": "8.2.0",
@ -22,6 +23,7 @@
"expo": "~52.0.41", "expo": "~52.0.41",
"expo-auth-session": "~6.0.3", "expo-auth-session": "~6.0.3",
"expo-build-properties": "~0.13.3", "expo-build-properties": "~0.13.3",
"expo-crypto": "~14.0.2",
"expo-image": "~2.0.7", "expo-image": "~2.0.7",
"expo-image-picker": "~16.0.6", "expo-image-picker": "~16.0.6",
"expo-linear-gradient": "~14.0.2", "expo-linear-gradient": "~14.0.2",
@ -54,6 +56,7 @@
"react-native-swiper": "^1.6.0", "react-native-swiper": "^1.6.0",
"react-native-toast-message": "^2.3.0", "react-native-toast-message": "^2.3.0",
"react-native-vector-icons": "^10.2.0", "react-native-vector-icons": "^10.2.0",
"react-native-web": "~0.19.13",
"react-native-webview": "13.12.5", "react-native-webview": "13.12.5",
"zustand": "^5.0.4" "zustand": "^5.0.4"
}, },
@ -7519,6 +7522,15 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/css-in-js-utils": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz",
"integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==",
"license": "MIT",
"dependencies": {
"hyphenate-style-name": "^1.0.3"
}
},
"node_modules/css-to-react-native": { "node_modules/css-to-react-native": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmmirror.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz", "resolved": "https://registry.npmmirror.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
@ -9502,6 +9514,12 @@
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-loops": {
"version": "1.1.4",
"resolved": "https://registry.npmmirror.com/fast-loops/-/fast-loops-1.1.4.tgz",
"integrity": "sha512-8dbd3XWoKCTms18ize6JmQF1SFnnfj5s0B7rRry22EofgMu7B6LKHVh+XfFqFGsqnbH54xgeO83PzpKI+ODhlg==",
"license": "MIT"
},
"node_modules/fast-uri": { "node_modules/fast-uri": {
"version": "3.0.6", "version": "3.0.6",
"resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.0.6.tgz", "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.0.6.tgz",
@ -10326,6 +10344,12 @@
"node": ">=10.17.0" "node": ">=10.17.0"
} }
}, },
"node_modules/hyphenate-style-name": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz",
"integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==",
"license": "BSD-3-Clause"
},
"node_modules/i18next": { "node_modules/i18next": {
"version": "24.2.3", "version": "24.2.3",
"resolved": "https://registry.npmmirror.com/i18next/-/i18next-24.2.3.tgz", "resolved": "https://registry.npmmirror.com/i18next/-/i18next-24.2.3.tgz",
@ -10475,6 +10499,16 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/inline-style-prefixer": {
"version": "6.0.4",
"resolved": "https://registry.npmmirror.com/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz",
"integrity": "sha512-FwXmZC2zbeeS7NzGjJ6pAiqRhXR0ugUShSNb6GApMl6da0/XGc4MOJsoWAywia52EEWbXNSy0pzkwz/+Y+swSg==",
"license": "MIT",
"dependencies": {
"css-in-js-utils": "^3.1.0",
"fast-loops": "^1.1.3"
}
},
"node_modules/internal-ip": { "node_modules/internal-ip": {
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmmirror.com/internal-ip/-/internal-ip-4.3.0.tgz", "resolved": "https://registry.npmmirror.com/internal-ip/-/internal-ip-4.3.0.tgz",
@ -10607,18 +10641,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/internal-ip/node_modules/which": {
"version": "1.3.1",
"resolved": "https://registry.npmmirror.com/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"which": "bin/which"
}
},
"node_modules/internal-slot": { "node_modules/internal-slot": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.1.0.tgz", "resolved": "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.1.0.tgz",
@ -14876,6 +14898,38 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/react-native-web": {
"version": "0.19.13",
"resolved": "https://registry.npmmirror.com/react-native-web/-/react-native-web-0.19.13.tgz",
"integrity": "sha512-etv3bN8rJglrRCp/uL4p7l8QvUNUC++QwDbdZ8CB7BvZiMvsxfFIRM1j04vxNldG3uo2puRd6OSWR3ibtmc29A==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.6",
"@react-native/normalize-colors": "^0.74.1",
"fbjs": "^3.0.4",
"inline-style-prefixer": "^6.0.1",
"memoize-one": "^6.0.0",
"nullthrows": "^1.1.1",
"postcss-value-parser": "^4.2.0",
"styleq": "^0.1.3"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/react-native-web/node_modules/@react-native/normalize-colors": {
"version": "0.74.89",
"resolved": "https://registry.npmmirror.com/@react-native/normalize-colors/-/normalize-colors-0.74.89.tgz",
"integrity": "sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==",
"license": "MIT"
},
"node_modules/react-native-web/node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
"license": "MIT"
},
"node_modules/react-native-webview": { "node_modules/react-native-webview": {
"version": "13.12.5", "version": "13.12.5",
"resolved": "https://registry.npmmirror.com/react-native-webview/-/react-native-webview-13.12.5.tgz", "resolved": "https://registry.npmmirror.com/react-native-webview/-/react-native-webview-13.12.5.tgz",
@ -16404,6 +16458,12 @@
"integrity": "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==", "integrity": "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/styleq": {
"version": "0.1.3",
"resolved": "https://registry.npmmirror.com/styleq/-/styleq-0.1.3.tgz",
"integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==",
"license": "MIT"
},
"node_modules/sucrase": { "node_modules/sucrase": {
"version": "3.35.0", "version": "3.35.0",
"resolved": "https://registry.npmmirror.com/sucrase/-/sucrase-3.35.0.tgz", "resolved": "https://registry.npmmirror.com/sucrase/-/sucrase-3.35.0.tgz",
@ -17639,6 +17699,18 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/which": {
"version": "1.3.1",
"resolved": "https://registry.npmmirror.com/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"which": "bin/which"
}
},
"node_modules/which-boxed-primitive": { "node_modules/which-boxed-primitive": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", "resolved": "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",

2
package.json

@ -10,6 +10,7 @@
}, },
"dependencies": { "dependencies": {
"@expo/metro-runtime": "~4.0.1", "@expo/metro-runtime": "~4.0.1",
"@expo/vector-icons": "^14.1.0",
"@react-native-async-storage/async-storage": "1.23.1", "@react-native-async-storage/async-storage": "1.23.1",
"@react-native-community/checkbox": "^0.5.17", "@react-native-community/checkbox": "^0.5.17",
"@react-native-community/datetimepicker": "8.2.0", "@react-native-community/datetimepicker": "8.2.0",
@ -22,6 +23,7 @@
"expo": "~52.0.41", "expo": "~52.0.41",
"expo-auth-session": "~6.0.3", "expo-auth-session": "~6.0.3",
"expo-build-properties": "~0.13.3", "expo-build-properties": "~0.13.3",
"expo-crypto": "~14.0.2",
"expo-image": "~2.0.7", "expo-image": "~2.0.7",
"expo-image-picker": "~16.0.6", "expo-image-picker": "~16.0.6",
"expo-linear-gradient": "~14.0.2", "expo-linear-gradient": "~14.0.2",

552
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save