Browse Source

解决合并冲突

main
unknown 2 weeks ago
parent
commit
38bdb694ed
  1. 1
      app.json
  2. 7
      app/locales/en/translation.json
  3. 3
      app/locales/fr/translation.json
  4. 37
      app/screens/BalanceScreen/BalanceScreen.tsx
  5. 139
      app/screens/loginList/index.tsx
  6. 11
      app/screens/previewOrder/perviewOrder.tsx
  7. 434
      app/screens/productStatus/OrderDatails.tsx
  8. 6
      app/services/api/login.ts
  9. 5
      done.txt
  10. 19
      package-lock.json
  11. 2
      package.json
  12. 10
      yarn.lock

1
app.json

@ -59,6 +59,7 @@
},
"plugins": [
"expo-video",
"expo-apple-authentication",
[
"expo-build-properties",
{

7
app/locales/en/translation.json

@ -110,6 +110,10 @@
"login_required_subtitle": "Login to use chat features",
"login_now": "Login Now"
},
"login":{
"error":"Login failed, please try again",
"success":"Login successfully"
},
"banner": {
"today": "Today",
"shipping": {
@ -357,7 +361,8 @@
},
"order.preview": {
"login_required": "Please login first",
"payment_failed": "Payment failed",
"payment_failed": "Payment failed, please try again",
"Insufficient_balance": "Insufficient balance",
"pay_now": "Pay Now",
"payment_method": "Payment Method",
"enter_phone": "Please enter phone number",

3
app/locales/fr/translation.json

@ -293,6 +293,7 @@
"order.preview": {
"login_required": "Veuillez vous connecter d'abord",
"payment_failed": "Le paiement a échoué",
"Insufficient_balance": "Solde insuffisant",
"pay_now": "Payer maintenant",
"payment_method": "Mode de paiement",
"enter_phone": "Veuillez saisir le numéro de téléphone",
@ -324,6 +325,8 @@
},
"login": {
"logInOrSignUp": "Se connecter ou s'inscrire",
"error":"Échec de la connexion, veuillez réessayer",
"success":"Connexion réussie",
"phoneNumber": "Numéro de téléphone",
"enterPassword": "Veuillez réentrer votre mot de passe",
"passwordIncorrect": "Mot de passe incorrect, veuillez confirmer votre mot de passe.",

37
app/screens/BalanceScreen/BalanceScreen.tsx

@ -27,6 +27,7 @@ import BackIcon from "../../components/BackIcon";
import useUserStore from "../../store/user";
import { Transaction, payApi } from "../../services/api/payApi";
import { useTranslation } from "react-i18next";
import { userApi } from "../../services";
type BalanceScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
@ -35,7 +36,7 @@ type BalanceScreenNavigationProp = NativeStackNavigationProp<
export const BalanceScreen = () => {
const { t } = useTranslation();
const { user } = useUserStore();
const { user, setUser } = useUserStore();
const navigation = useNavigation<BalanceScreenNavigationProp>();
const [isModalVisible, setIsModalVisible] = useState(false);
const [rechargeHistory, setRechargeHistory] = useState<Transaction[]>([]);
@ -66,7 +67,7 @@ export const BalanceScreen = () => {
if (refresh) {
setRechargeHistory(response.items);
} else {
setRechargeHistory(prev => [...prev, ...response.items]);
setRechargeHistory((prev) => [...prev, ...response.items]);
}
setCurrentPage(page);
@ -85,6 +86,9 @@ export const BalanceScreen = () => {
useFocusEffect(
useCallback(() => {
userApi.getProfile().then((res) => {
setUser(res);
});
fetchRechargeHistory(1, true);
}, [])
);
@ -93,17 +97,12 @@ export const BalanceScreen = () => {
<View style={styles.transactionHistoryList} key={item.transaction_id}>
<View style={styles.transactionDetailsPanel}>
<View style={styles.transactionDetailsRow}>
<Text style={styles.transactionDescriptionBold}>
{item.type}
</Text>
<Text style={styles.transactionDescriptionBold}>{item.type}</Text>
<Text
style={[
styles.transactionAmountDisplay,
{
color:
Number(item.amount) < 0
? "#0035a4"
: "#ff5217",
color: Number(item.amount) < 0 ? "#0035a4" : "#ff5217",
},
]}
>
@ -111,12 +110,8 @@ export const BalanceScreen = () => {
</Text>
</View>
<View style={styles.transactionInfoRow}>
<Text style={styles.transactionDate}>
{item.timestamp}
</Text>
<Text style={styles.shipmentReference}>
{item.type}
</Text>
<Text style={styles.transactionDate}>{item.timestamp}</Text>
<Text style={styles.shipmentReference}>{item.type}</Text>
</View>
</View>
</View>
@ -150,7 +145,9 @@ export const BalanceScreen = () => {
<FlatList
data={rechargeHistory}
renderItem={renderTransactionItem}
keyExtractor={(item) => item.transaction_id.toString()}
keyExtractor={(item, index) =>
item.transaction_id.toString() + index
}
onEndReached={handleLoadMore}
onEndReachedThreshold={0.5}
ListFooterComponent={renderFooter}
@ -174,7 +171,9 @@ export const BalanceScreen = () => {
<View style={styles.totalBalanceCard}>
<View style={styles.cardContainer}>
<View style={styles.financialInfoContainer}>
<Text style={styles.largeBlackText}>{user?.balance}</Text>
<Text style={styles.largeBlackText}>
{user?.balance}
</Text>
<View style={styles.svgContainer}></View>
</View>
<View style={styles.totalSoldInfoContainer}>
@ -470,7 +469,7 @@ const styles = StyleSheet.create({
},
loaderContainer: {
paddingVertical: 20,
alignItems: 'center',
justifyContent: 'center',
alignItems: "center",
justifyContent: "center",
},
});

139
app/screens/loginList/index.tsx

@ -17,25 +17,32 @@ import type { NativeStackNavigationProp } from "@react-navigation/native-stack";
import fontSize from "../../utils/fontsizeUtils";
import EmailLoginModal from "./EmailLoginModal";
import PhoneLoginModal from "./PhoneLoginModal";
import { loginApi } from "../../services/api/login";
import { userApi } from "../../services";
import useUserStore from "../../store/user";
// 使用标准的ES6模块导入
import { GoogleSignin, GoogleSigninButton, statusCodes } from '@react-native-google-signin/google-signin';
// import {
// GoogleSignin,
// statusCodes,
// } from "@react-native-google-signin/google-signin";
const isDevelopment = __DEV__; // 开发模式检测
// 移出条件块,始终尝试配置 Google 登录
try {
// 配置 Google 登录
GoogleSignin.configure({
iosClientId: "YOUR_IOS_CLIENT_ID_HERE.apps.googleusercontent.com", // iOS CLIENT_ID
webClientId: "449517618313-av37nffa7rqkefu0ajh5auou3pb0mt51.apps.googleusercontent.com", // <-- 更新为此 Web Client ID
scopes: ['profile', 'email'],
offlineAccess: false, // <-- 确保为 false 或移除
forceCodeForRefreshToken: false, // <-- 确保为 false 或移除
});
} catch (error) {
console.log('Google Sign-in模块配置错误:', error); // 稍微修改了日志信息
}
// try {
// // 配置 Google 登录
// GoogleSignin.configure({
// iosClientId: "YOUR_IOS_CLIENT_ID_HERE.apps.googleusercontent.com", // iOS CLIENT_ID
// webClientId:
// "449517618313-av37nffa7rqkefu0ajh5auou3pb0mt51.apps.googleusercontent.com", // <-- 更新为此 Web Client ID
// scopes: ["profile", "email"],
// offlineAccess: false, // <-- 确保为 false 或移除
// forceCodeForRefreshToken: false, // <-- 确保为 false 或移除
// });
// } catch (error) {
// console.log("Google Sign-in模块配置错误:", error); // 稍微修改了日志信息
// }
type RootStackParamList = {
Login: undefined;
@ -51,6 +58,7 @@ type LoginScreenProps = {
};
export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
const { setUser } = useUserStore();
const { t } = useTranslation();
const navigation =
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
@ -97,63 +105,52 @@ export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
// 处理谷歌登录
const handleGoogleLogin = async () => {
try {
// 开发模式下的模拟登录
// 注释掉开发模式下的模拟登录,以便进行真实登录测试
/*
if (isDevelopment) {
console.log('开发模式:模拟Google登录成功');
const mockUserInfo = {
user: {
id: 'dev_user_123',
name: 'Test User',
email: 'test@example.com',
photo: null,
},
};
console.log('模拟用户信息:', mockUserInfo);
// 这里可以处理登录成功后的逻辑
// 比如导航到主页面或保存用户信息
// try {
// if (!GoogleSignin || typeof GoogleSignin.signIn !== "function") {
// console.log("Google Sign-in模块未正确初始化或配置失败");
// return;
// }
// await GoogleSignin.hasPlayServices();
// const userInfo = await GoogleSignin.signIn();
// console.log("Google 登录成功:", userInfo);
// try {
// const res = await loginApi.googleLogin(userInfo);
// const user = await userApi.getProfile();
// setUser(user);
// navigation.navigate("MainTabs", { screen: "Home" });
return;
}
*/
// 生产模式下的真实Google登录 (现在开发模式也会执行)
if (!GoogleSignin || typeof GoogleSignin.signIn !== 'function') {
console.log('Google Sign-in模块未正确初始化或配置失败');
return;
}
await GoogleSignin.hasPlayServices();
const userInfo = await GoogleSignin.signIn();
console.log('Google 登录成功:', userInfo);
// 这里可以处理登录成功后的逻辑
// 比如导航到主页面或保存用户信息
// navigation.navigate("MainTabs", { screen: "Home" });
} catch (error: any) {
console.log('Google 登录错误:', error);
// 开发模式下的错误处理
if (isDevelopment) {
console.log('开发模式:忽略Google登录错误,但已尝试真实登录'); // 修改日志,表明已尝试真实登录
return;
}
if (statusCodes && error.code === statusCodes.SIGN_IN_CANCELLED) {
console.log('用户取消登录');
} else if (statusCodes && error.code === statusCodes.IN_PROGRESS) {
console.log('登录正在进行中');
} else if (statusCodes && error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
console.log('Play Services 不可用');
} else {
console.log('其他错误:', error.message);
}
}
// } catch (err) {
// console.log("Google 登录失败:", err);
// navigation.navigate("Login");
// }
// // 这里可以处理登录成功后的逻辑
// // 比如导航到主页面或保存用户信息
// // navigation.navigate("MainTabs", { screen: "Home" });
// } catch (error: any) {
// console.log("Google 登录错误:", error);
// // 开发模式下的错误处理
// if (isDevelopment) {
// console.log("开发模式:忽略Google登录错误,但已尝试真实登录"); // 修改日志,表明已尝试真实登录
// return;
// }
// if (statusCodes && error.code === statusCodes.SIGN_IN_CANCELLED) {
// console.log("用户取消登录");
// } else if (statusCodes && error.code === statusCodes.IN_PROGRESS) {
// console.log("登录正在进行中");
// } else if (
// statusCodes &&
// error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE
// ) {
// console.log("Play Services 不可用");
// } else {
// console.log("其他错误:", error.message);
// navigation.navigate("Login");
// }
// }
};
// 处理Facebook登录
@ -263,7 +260,9 @@ export const LoginScreen = ({ onClose, isModal }: LoginScreenProps) => {
/>
</View>
<Text style={styles.loginButtonText}>
{isDevelopment ? '🧪 ' + t("continueWithGoogle") + ' (测试模式)' : t("continueWithGoogle")}
{isDevelopment
? "🧪 " + t("continueWithGoogle") + " (测试模式)"
: t("continueWithGoogle")}
</Text>
</TouchableOpacity>

11
app/screens/previewOrder/perviewOrder.tsx

@ -41,6 +41,7 @@ type RootStackParamList = {
};
Pay: { payUrl: string; method: string; order_id: string };
OrderDetails: { orderId?: number };
PaymentSuccessScreen: any;
};
export const PreviewOrder = () => {
@ -58,7 +59,7 @@ export const PreviewOrder = () => {
if (!user.user_id) {
return Alert.alert(t("order.preview.login_required"));
}
if (route.params.payMethod === "Brainnel Pay(Mobile Money)") {
if (route.params.payMethod === "mobile_money") {
setShowPhoneInput(true);
} else {
setShowPhoneInput(false);
@ -105,6 +106,14 @@ export const PreviewOrder = () => {
.getPayInfo(data)
.then((res) => {
if (res.success) {
if (route.params.payMethod === "balance") {
if (res.success) {
navigation.navigate("PaymentSuccessScreen", res);
return;
} else {
Alert.alert(t("order.preview.Insufficient_balance"));
}
}
logPreviewOrder(
navigation.getState().routes[navigation.getState().index - 1]
?.name as string

434
app/screens/productStatus/OrderDatails.tsx

@ -181,7 +181,7 @@ export const OrderDetails = () => {
{
OrderDetails: {
orderId: string;
status:number
status: number;
};
},
"OrderDetails"
@ -189,7 +189,8 @@ export const OrderDetails = () => {
>();
const [orderDetails, setOrderDetails] = useState<OrderDetailsType>();
const [isLoading, setIsLoading] = useState(true);
const { deleteOrder, changeOrder,updateOrderShippingInfo } = useOrderListStore();
const { deleteOrder, changeOrder, updateOrderShippingInfo } =
useOrderListStore();
const [showPaymentModal, setShowPaymentModal] = useState(false);
const [selectedPayment, setSelectedPayment] = useState<string | null>(null);
const [currentTab, setCurrentTab] = useState("online");
@ -205,16 +206,22 @@ export const OrderDetails = () => {
label: t("order.payment.offline"),
options: [
{ id: "cash", label: t("order.payment.cash") || "Cash", key: "cash" },
{ id: "bank", label: t("order.payment.bank") || "Bank Transfer", key: "bank" }
{
id: "bank",
label: t("order.payment.bank") || "Bank Transfer",
key: "bank",
},
],
},
]);
const [selectedCurrency, setSelectedCurrency] = useState("USD");
const [convertedAmount, setConvertedAmount] = useState<{
const [convertedAmount, setConvertedAmount] = useState<
{
converted_amount: number;
item_key: string;
original_amount: number;
}[]>([]);
}[]
>([]);
const [isConverting, setIsConverting] = useState(false);
const { user } = useUserStore();
const [isPaymentLoading, setIsPaymentLoading] = useState(false);
@ -247,22 +254,29 @@ export const OrderDetails = () => {
getOrderDetails();
// 获取支付方式
payApi.getCountryPaymentMethods().then((res) => {
payApi
.getCountryPaymentMethods()
.then((res) => {
if (res && res.current_country_methods) {
setPaymentMethods(res.current_country_methods);
// 更新在线支付选项
setTabs(prev => {
setTabs((prev) => {
const updatedTabs = [...prev];
const onlineTabIndex = updatedTabs.findIndex(tab => tab.id === "online");
const onlineTabIndex = updatedTabs.findIndex(
(tab) => tab.id === "online"
);
if (onlineTabIndex !== -1) {
// 将API返回的支付方式转换为选项格式
const options: PaymentOption[] = res.current_country_methods.map(method => ({
const options: PaymentOption[] = res.current_country_methods.map(
(method) => ({
id: method.key,
label: method.key.charAt(0).toUpperCase() + method.key.slice(1), // 首字母大写
key: method.key
}));
label:
method.key.charAt(0).toUpperCase() + method.key.slice(1), // 首字母大写
key: method.key,
})
);
updatedTabs[onlineTabIndex].options = options;
}
@ -270,7 +284,8 @@ export const OrderDetails = () => {
return updatedTabs;
});
}
}).catch(error => {
})
.catch((error) => {
console.error("获取支付方式失败:", error);
});
}, []);
@ -372,34 +387,64 @@ export const OrderDetails = () => {
order_id: orderDetails.order_id,
payment_method: selectedPayment,
currency: selectedPayment === "paypal" ? selectedCurrency : user.currency,
total_amount: selectedPayment === "paypal"
? convertedAmount.reduce((acc, item) => acc + item.converted_amount, 0)
total_amount:
selectedPayment === "paypal"
? convertedAmount.reduce(
(acc, item) => acc + item.converted_amount,
0
)
: orderDetails?.total_amount || 0,
actual_amount: selectedPayment === "paypal"
? convertedAmount.reduce((acc, item) => acc + item.converted_amount, 0)
actual_amount:
selectedPayment === "paypal"
? convertedAmount.reduce(
(acc, item) => acc + item.converted_amount,
0
)
: orderDetails?.actual_amount || 0,
shipping_fee: selectedPayment === "paypal"
? convertedAmount.find(item => item.item_key === "shipping_fee")?.converted_amount || 0
shipping_fee:
selectedPayment === "paypal"
? convertedAmount.find((item) => item.item_key === "shipping_fee")
?.converted_amount || 0
: orderDetails?.shipping_fee || 0,
domestic_shipping_fee: selectedPayment === "paypal"
? convertedAmount.find(item => item.item_key === "domestic_shipping_fee")?.converted_amount || 0
: orderDetails?.domestic_shipping_fee || 0
domestic_shipping_fee:
selectedPayment === "paypal"
? convertedAmount.find(
(item) => item.item_key === "domestic_shipping_fee"
)?.converted_amount || 0
: orderDetails?.domestic_shipping_fee || 0,
};
try {
await ordersApi.updateOrderPaymentMethod(paymentData)
await ordersApi.updateOrderPaymentMethod(paymentData);
const payData = {
order_id: orderDetails.order_id,
method: selectedPayment,
currency: selectedPayment === "paypal" ? selectedCurrency : user.currency,
amount: selectedPayment === "paypal"
? convertedAmount.reduce((acc, item) => acc + item.converted_amount, 0)
: orderDetails?.total_amount || 0
currency:
selectedPayment === "paypal" ? selectedCurrency : user.currency,
amount:
selectedPayment === "paypal"
? convertedAmount.reduce(
(acc, item) => acc + item.converted_amount,
0
)
: orderDetails?.total_amount || 0,
};
payApi
.getPayInfo(payData)
.then((res) => {
if (res.success) {
if (selectedPayment === "balance") {
setIsPaymentLoading(false);
setShowPaymentModal(false);
if (res.success) {
navigation.navigate("PaymentSuccessScreen", res);
return;
} else {
Alert.alert(t("order.preview.Insufficient_balance"));
return;
}
}
setIsPaymentLoading(false);
setShowPaymentModal(false);
navigation.navigate("Pay", {
@ -407,7 +452,7 @@ export const OrderDetails = () => {
method: selectedPayment,
order_id: orderDetails.order_id,
});
}else{
} else {
Alert.alert(t("error"), t("pay.payment_failed"));
}
})
@ -418,7 +463,6 @@ export const OrderDetails = () => {
.finally(() => {
setIsPaymentLoading(false);
});
} catch (error) {
Alert.alert(t("error"), t("order.error.payment_update"));
setIsPaymentLoading(false);
@ -433,10 +477,7 @@ export const OrderDetails = () => {
// 验证电话号码(添加更严格的验证)
if (!phoneNumber || phoneNumber.length < 8) {
Alert.alert(
t("error"),
t("order.error.invalid_phone")
);
Alert.alert(t("error"), t("order.error.invalid_phone"));
return;
}
@ -452,7 +493,7 @@ export const OrderDetails = () => {
actual_amount: paymentParams.amount,
shipping_fee: 0,
domestic_shipping_fee: 0,
phone: phoneNumber
phone: phoneNumber,
};
// 更新订单支付方式
@ -464,7 +505,7 @@ export const OrderDetails = () => {
method: paymentParams.payment_method,
currency: paymentParams.currency,
amount: paymentParams.amount,
phone: phoneNumber
phone: phoneNumber,
};
const response = await payApi.getPayInfo(payData);
@ -557,7 +598,9 @@ export const OrderDetails = () => {
<View style={styles.orderStatusContent}>
<View style={styles.orderStatusTitle}>
<OrderIcon size={20} color="#3D3D3D" />
<Text style={styles.orderStatusTitleText}>{t("order.status")}</Text>
<Text style={styles.orderStatusTitleText}>
{t("order.status")}
</Text>
</View>
<View style={styles.orderStatusContentPreview}>
@ -568,7 +611,7 @@ export const OrderDetails = () => {
t("order.status.waiting_shipment"),
t("order.status.in_transit"),
t("order.status.waiting_receipt"),
t("order.status.completed")
t("order.status.completed"),
]}
/>
</View>
@ -579,7 +622,9 @@ export const OrderDetails = () => {
<View style={styles.orderStatusContent}>
<View style={styles.orderStatusTitle}>
<InfoIcon size={20} color="#3D3D3D" />
<Text style={styles.orderStatusTitleText}>{t("order.information")}</Text>
<Text style={styles.orderStatusTitleText}>
{t("order.information")}
</Text>
</View>
<View style={styles.orderStatusContentPreview}>
<View style={styles.orderId}>
@ -589,15 +634,21 @@ export const OrderDetails = () => {
</Text>
</View>
<View style={styles.orderId}>
<Text style={styles.orderIdText}>{t("order.create_time")}</Text>
<Text style={styles.orderIdText}>
{t("order.create_time")}
</Text>
<Text style={styles.orderIdText1}>
{orderDetails.create_time}
</Text>
</View>
<View style={styles.orderId}>
<Text style={styles.orderIdText}>{t("order.shipping_type")}</Text>
<Text style={styles.orderIdText}>
{t("order.shipping_type")}
</Text>
<Text style={styles.orderIdText1}>
{orderDetails.shipping_type === 0 ? t("order.shipping.sea") : t("order.shipping.air")}
{orderDetails.shipping_type === 0
? t("order.shipping.sea")
: t("order.shipping.air")}
</Text>
</View>
</View>
@ -608,7 +659,9 @@ export const OrderDetails = () => {
<View style={styles.orderStatusContent}>
<View style={styles.orderStatusTitle}>
<AddressIcon size={22} color={"#3D3D3D"} />
<Text style={styles.orderStatusTitleText}>{t("order.delivery_info")}</Text>
<Text style={styles.orderStatusTitleText}>
{t("order.delivery_info")}
</Text>
</View>
<View style={styles.orderStatusContentPreview}>
<View style={styles.orderStatusContentPreviewInformation}>
@ -747,7 +800,9 @@ export const OrderDetails = () => {
<TouchableOpacity style={styles.addCard}>
<View style={styles.addCardBox}>
<CardIcon size={16} color="#0098ef" />
<Text style={styles.addCardText}>{t("order.add_to_cart")}</Text>
<Text style={styles.addCardText}>
{t("order.add_to_cart")}
</Text>
</View>
</TouchableOpacity>
</View>
@ -758,7 +813,9 @@ export const OrderDetails = () => {
<View style={styles.orderStatusContent}>
<View style={styles.orderStatusTitle}>
<PowerIcon size={20} color="#3D3D3D" />
<Text style={styles.orderStatusTitleText}>{t("order.price_details")}</Text>
<Text style={styles.orderStatusTitleText}>
{t("order.price_details")}
</Text>
</View>
<View style={styles.orderStatusContentPreview}>
{/* <View style={styles.orderId}>
@ -791,7 +848,8 @@ export const OrderDetails = () => {
</View>
<View>
<Text style={styles.orderRemakeText}>
+ ${orderDetails.shipping_fee} {t("order.estimated_shipping")}
+ ${orderDetails.shipping_fee}{" "}
{t("order.estimated_shipping")}
(COD)
</Text>
</View>
@ -806,7 +864,9 @@ export const OrderDetails = () => {
style={styles.bottomButton1}
onPress={() => setShowCancelModal(true)}
>
<Text style={styles.bottomButtonText1}>{t("order.cancel")}</Text>
<Text style={styles.bottomButtonText1}>
{t("order.cancel")}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.bottomButton}
@ -827,7 +887,9 @@ export const OrderDetails = () => {
callPhone("15903995548");
}}
>
<Text style={styles.bottomButtonText1}>{t("order.contact_shipping")}</Text>
<Text style={styles.bottomButtonText1}>
{t("order.contact_shipping")}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.bottomButton}
@ -836,31 +898,40 @@ export const OrderDetails = () => {
navigation.goBack();
}}
>
<Text style={styles.bottomButtonText}>{t("order.cancel")}</Text>
<Text style={styles.bottomButtonText}>
{t("order.cancel")}
</Text>
</TouchableOpacity>
</View>
)}
{/* 代收货 */}
{orderDetails.order_status === 2 && (
<View style={styles.bottomButtons}>
<TouchableOpacity style={styles.bottomButton1} onPress={() => {}}>
<Text style={styles.bottomButtonText1}>{t("order.check_logistics")}</Text>
<TouchableOpacity
style={styles.bottomButton1}
onPress={() => {}}
>
<Text style={styles.bottomButtonText1}>
{t("order.check_logistics")}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.bottomButton}
onPress={() => {
updateOrderShippingInfo(route.params.orderId,{
updateOrderShippingInfo(route.params.orderId, {
shipping_status: 0,
shipping_info: {
shipping_company: "string",
shipping_no: "string",
shipping_info: {}
}
shipping_info: {},
},
});
navigation.goBack();
}}
>
<Text style={styles.bottomButtonText}>{t("order.confirm_receipt")}</Text>
<Text style={styles.bottomButtonText}>
{t("order.confirm_receipt")}
</Text>
</TouchableOpacity>
</View>
)}
@ -874,21 +945,32 @@ export const OrderDetails = () => {
navigation.goBack();
}}
>
<Text style={styles.bottomButtonText1}>{t("order.cancel")}</Text>
<Text style={styles.bottomButtonText1}>
{t("order.cancel")}
</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.bottomButton}>
<Text style={styles.bottomButtonText}>{t("order.pay_now")}</Text>
<Text style={styles.bottomButtonText}>
{t("order.pay_now")}
</Text>
</TouchableOpacity>
</View>
)}
{/* 已取消 */}
{orderDetails.order_status === 4 && (
<View style={styles.bottomButtons}>
<TouchableOpacity style={styles.bottomButton1} onPress={() => {}}>
<Text style={styles.bottomButtonText1}>{t("order.add_to_cart")}</Text>
<TouchableOpacity
style={styles.bottomButton1}
onPress={() => {}}
>
<Text style={styles.bottomButtonText1}>
{t("order.add_to_cart")}
</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.bottomButton}>
<Text style={styles.bottomButtonText}>{t("order.reorder")}</Text>
<Text style={styles.bottomButtonText}>
{t("order.reorder")}
</Text>
</TouchableOpacity>
</View>
)}
@ -902,14 +984,16 @@ export const OrderDetails = () => {
visible={showPaymentModal}
transparent={true}
animationType="slide"
onRequestClose={() => setShowPaymentModal(false)}
>
<View style={styles.modalOverlay}>
<View style={styles.modalContent}>
<View style={styles.modalHeader}>
<Text style={styles.modalTitle}>{t("order.select_payment")}</Text>
<TouchableOpacity onPress={() => setShowPaymentModal(false)} style={styles.closeButtonContainer}>
<TouchableOpacity
onPress={() => setShowPaymentModal(false)}
style={styles.closeButtonContainer}
>
<Text style={styles.closeButtonText}>×</Text>
</TouchableOpacity>
</View>
@ -918,17 +1002,28 @@ export const OrderDetails = () => {
{tabs.map((tab) => (
<TouchableOpacity
key={tab.id}
style={[styles.tab, currentTab === tab.id && styles.tabActive]}
style={[
styles.tab,
currentTab === tab.id && styles.tabActive,
]}
onPress={() => setCurrentTab(tab.id)}
>
<Text style={[styles.tabText, currentTab === tab.id && styles.tabTextActive]}>
<Text
style={[
styles.tabText,
currentTab === tab.id && styles.tabTextActive,
]}
>
{tab.label}
</Text>
</TouchableOpacity>
))}
</View>
<ScrollView showsVerticalScrollIndicator={false} style={styles.paymentOptions}>
<ScrollView
showsVerticalScrollIndicator={false}
style={styles.paymentOptions}
>
{currentTab === "online" ? (
<>
{tabs
@ -947,7 +1042,8 @@ export const OrderDetails = () => {
/>
</View>
<Text style={styles.balanceText}>
{t("order.balance_remaining") || "Balance remaining"}
{t("order.balance_remaining") ||
"Balance remaining"}
{"\n"}
{user.balance}
{user.currency}
@ -960,39 +1056,74 @@ export const OrderDetails = () => {
style={{ width: 80, height: 30, resizeMode: 'contain', marginRight: 10 }}
/>
{option.key === "mobile_money" && (
<View style={styles.mobileMoneyTextContainer}>
{paymentMethods.find(method => method.key === option.key)?.value &&
Array.isArray(paymentMethods.find(method => method.key === option.key)?.value) ? (
(paymentMethods.find(method => method.key === option.key)?.value as string[]).map((item, index) => (
<View key={index} style={styles.mobileMoneyImgContainer}>
<View
style={styles.mobileMoneyTextContainer}
>
{paymentMethods.find(
(method) => method.key === option.key
)?.value &&
Array.isArray(
paymentMethods.find(
(method) => method.key === option.key
)?.value
) ? (
(
paymentMethods.find(
(method) =>
method.key === option.key
)?.value as string[]
).map((item, index) => (
<View
key={index}
style={
styles.mobileMoneyImgContainer
}
>
<Image
source={payMap(item) as any}
style={{ width: 60, height: 22, resizeMode: 'contain' }}
style={styles.mobileMoneyImg}
/>
</View>
))
) : (
<Text style={styles.mobileMoneyText}>
{paymentMethods.find(method => method.key === option.key)?.value as string}
</Text>
)
{
paymentMethods.find(
(method) =>
method.key === option.key
)?.value as string
}
</Text>
)}
</View>
)}
</View>
)}
</View>
</View>
<TouchableOpacity onPress={() => onSelectPayment(option.id)}>
<TouchableOpacity
onPress={() => onSelectPayment(option.id)}
>
<View style={styles.checkboxContainer}>
<CircleOutlineIcon
size={fontSize(24)}
strokeColor={selectedPayment === option.id ? "#007efa" : "#C6C6C6"}
fillColor={selectedPayment === option.id ? "#007efa" : "transparent"}
strokeColor={
selectedPayment === option.id
? "#007efa"
: "#C6C6C6"
}
fillColor={
selectedPayment === option.id
? "#007efa"
: "transparent"
}
/>
{selectedPayment === option.id && (
<View style={styles.checkmarkContainer}>
<CheckIcon size={fontSize(12)} color="#FFFFFF" />
<CheckIcon
size={fontSize(12)}
color="#FFFFFF"
/>
</View>
)}
</View>
@ -1000,24 +1131,29 @@ export const OrderDetails = () => {
</View>
{/* PayPal Currency Selection */}
{selectedPayment === "paypal" && option.id === "paypal" && isPaypalExpanded && (
{selectedPayment === "paypal" &&
option.id === "paypal" &&
isPaypalExpanded && (
<View style={styles.paypalExpandedContainer}>
<View style={styles.paypalCurrencyContainer}>
<Text style={styles.currencyTitle}>
{t("order.select_currency") || "Select Currency"}
{t("order.select_currency") ||
"Select Currency"}
</Text>
<View style={styles.currencyButtonsContainer}>
<TouchableOpacity
style={[
styles.currencyButton,
selectedCurrency === "USD" && styles.currencyButtonActive,
selectedCurrency === "USD" &&
styles.currencyButtonActive,
]}
onPress={() => onSelectCurrency("USD")}
>
<Text
style={[
styles.currencyButtonText,
selectedCurrency === "USD" && styles.currencyButtonTextActive,
selectedCurrency === "USD" &&
styles.currencyButtonTextActive,
]}
>
USD
@ -1026,14 +1162,16 @@ export const OrderDetails = () => {
<TouchableOpacity
style={[
styles.currencyButton,
selectedCurrency === "EUR" && styles.currencyButtonActive,
selectedCurrency === "EUR" &&
styles.currencyButtonActive,
]}
onPress={() => onSelectCurrency("EUR")}
>
<Text
style={[
styles.currencyButtonText,
selectedCurrency === "EUR" && styles.currencyButtonTextActive,
selectedCurrency === "EUR" &&
styles.currencyButtonTextActive,
]}
>
EUR
@ -1044,7 +1182,10 @@ export const OrderDetails = () => {
{/* 显示转换后的金额 */}
{isConverting ? (
<View style={styles.convertingContainer}>
<ActivityIndicator size="small" color="#007efa" />
<ActivityIndicator
size="small"
color="#007efa"
/>
<Text style={styles.convertingText}>
{t("order.converting") || "Converting..."}
</Text>
@ -1052,11 +1193,15 @@ export const OrderDetails = () => {
) : convertedAmount.length > 0 ? (
<View style={styles.convertedAmountContainer}>
<Text style={styles.convertedAmountLabel}>
{t("order.equivalent_amount") || "Equivalent Amount:"}
{t("order.equivalent_amount") ||
"Equivalent Amount:"}
</Text>
<Text style={styles.convertedAmountValue}>
{convertedAmount
.find((item) => item.item_key === "total_amount")
.find(
(item) =>
item.item_key === "total_amount"
)
?.converted_amount.toFixed(2)}{" "}
{selectedCurrency}
</Text>
@ -1096,15 +1241,22 @@ export const OrderDetails = () => {
<CircleOutlineIcon
size={fontSize(24)}
strokeColor={
selectedPayment === option.id ? "#007efa" : undefined
selectedPayment === option.id
? "#007efa"
: undefined
}
fillColor={
selectedPayment === option.id ? "#007efa" : undefined
selectedPayment === option.id
? "#007efa"
: undefined
}
/>
{selectedPayment === option.id && (
<View style={styles.checkmarkContainer}>
<CheckIcon size={fontSize(12)} color="#FFFFFF" />
<CheckIcon
size={fontSize(12)}
color="#FFFFFF"
/>
</View>
)}
</View>
@ -1128,7 +1280,8 @@ export const OrderDetails = () => {
<TouchableOpacity
style={[
styles.confirmButton,
(isConfirmButtonDisabled() || isPaymentLoading) && styles.confirmButtonDisabled,
(isConfirmButtonDisabled() || isPaymentLoading) &&
styles.confirmButtonDisabled,
]}
onPress={handlePaymentConfirm}
disabled={isConfirmButtonDisabled() || isPaymentLoading}
@ -1202,7 +1355,7 @@ export const OrderDetails = () => {
const styles = StyleSheet.create<Styles>({
safeArea: {
flex: 1,
backgroundColor: '#fff',
backgroundColor: "#fff",
},
safeAreaContent: {
flex: 1,
@ -1461,39 +1614,38 @@ const styles = StyleSheet.create<Styles>({
},
modalOverlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: "rgba(0, 0, 0, 0.5)",
justifyContent: "flex-end",
},
modalContent: {
backgroundColor: '#fff',
backgroundColor: "#fff",
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
padding: 20,
maxHeight: '80%',
maxHeight: "80%",
},
modalHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 20,
},
modalTitle: {
fontSize: fontSize(18),
fontWeight: '600',
fontWeight: "600",
},
closeButtonContainer: {
padding: 5,
},
closeButtonText: {
fontSize: fontSize(24),
color: '#999',
color: "#999",
},
tabContainer: {
flexDirection: 'row',
flexDirection: "row",
marginBottom: 15,
borderBottomWidth: 1,
borderBottomColor: '#f5f5f5',
borderBottomColor: "#f5f5f5",
},
tab: {
paddingVertical: 10,
@ -1502,31 +1654,31 @@ const styles = StyleSheet.create<Styles>({
},
tabActive: {
borderBottomWidth: 2,
borderBottomColor: '#FF5100',
borderBottomColor: "#FF5100",
},
tabText: {
fontSize: fontSize(16),
color: '#666',
color: "#666",
},
tabTextActive: {
color: '#FF5100',
fontWeight: '500',
color: "#FF5100",
fontWeight: "500",
},
paymentOptions: {
maxHeight: 300,
},
cardContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
padding: 15,
backgroundColor: '#F8F8F8',
backgroundColor: "#F8F8F8",
borderRadius: 8,
marginBottom: 10,
},
iconRow: {
flexDirection: 'row',
alignItems: 'center',
flexDirection: "row",
alignItems: "center",
flex: 1,
},
imageContainer: {
@ -1559,11 +1711,11 @@ const styles = StyleSheet.create<Styles>({
},
currencyTitle: {
fontSize: fontSize(14),
color: '#666',
color: "#666",
marginBottom: 10,
},
paypalExpandedContainer: {
backgroundColor: '#f8f8f8',
backgroundColor: "#f8f8f8",
borderRadius: 8,
marginTop: -5,
marginBottom: 10,
@ -1574,7 +1726,7 @@ const styles = StyleSheet.create<Styles>({
padding: 10,
},
currencyButtonsContainer: {
flexDirection: 'row',
flexDirection: "row",
marginBottom: 10,
},
currencyButton: {
@ -1582,30 +1734,30 @@ const styles = StyleSheet.create<Styles>({
paddingHorizontal: 15,
borderRadius: 20,
borderWidth: 1,
borderColor: '#ddd',
borderColor: "#ddd",
marginRight: 10,
},
currencyButtonActive: {
backgroundColor: '#FFF0E8',
borderColor: '#FF5100',
backgroundColor: "#FFF0E8",
borderColor: "#FF5100",
},
currencyButtonText: {
fontSize: fontSize(14),
color: '#333',
color: "#333",
},
currencyButtonTextActive: {
color: '#FF5100',
fontWeight: '600',
color: "#FF5100",
fontWeight: "600",
},
convertingContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-end',
flexDirection: "row",
alignItems: "center",
justifyContent: "flex-end",
marginTop: 10,
},
convertingText: {
fontSize: fontSize(14),
color: '#999',
color: "#999",
marginLeft: 10,
},
convertedAmountContainer: {
@ -1613,23 +1765,23 @@ const styles = StyleSheet.create<Styles>({
},
convertedAmountLabel: {
fontSize: fontSize(14),
color: '#666',
color: "#666",
marginBottom: 5,
},
convertedAmountValue: {
fontSize: fontSize(16),
fontWeight: '600',
color: '#FF5100',
fontWeight: "600",
color: "#FF5100",
},
actionButtonsContainer: {
marginTop: 20,
paddingTop: 20,
borderTopWidth: 1,
borderTopColor: '#f5f5f5',
borderTopColor: "#f5f5f5",
},
actionButtons: {
flexDirection: 'row',
justifyContent: 'space-between',
flexDirection: "row",
justifyContent: "space-between",
},
cancelButton: {
flex: 1,
@ -1637,28 +1789,28 @@ const styles = StyleSheet.create<Styles>({
marginRight: 10,
borderRadius: 25,
borderWidth: 1,
borderColor: '#999',
alignItems: 'center',
borderColor: "#999",
alignItems: "center",
},
confirmButton: {
flex: 1,
padding: 15,
marginLeft: 10,
borderRadius: 25,
backgroundColor: '#FF5100',
alignItems: 'center',
backgroundColor: "#FF5100",
alignItems: "center",
},
confirmButtonDisabled: {
backgroundColor: '#ccc',
backgroundColor: "#ccc",
},
buttonTextDark: {
fontSize: fontSize(16),
color: '#666',
color: "#666",
},
buttonTextWhite: {
fontSize: fontSize(16),
color: '#fff',
fontWeight: '600',
color: "#fff",
fontWeight: "600",
},
operatorImage: {
width: 80,

6
app/services/api/login.ts

@ -0,0 +1,6 @@
import apiService from "./apiClient";
export const loginApi = {
googleLogin: (data: any) =>
apiService.post("/api/users/auth/callback/google", data),
};

5
done.txt

@ -0,0 +1,5 @@
1. 余额支付 (订单详情,支付)
2. 查看物流
3. 取消订单
4. 运费计算
5. 询盘的图搜转成base64

19
package-lock.json generated

@ -39,6 +39,7 @@
"react-i18next": "^15.4.1",
"react-native": "0.76.9",
"react-native-dropdown-picker": "^5.4.6",
"react-native-fbsdk-next": "^13.4.1",
"react-native-gesture-handler": "~2.20.2",
"react-native-image-viewing": "^0.2.2",
"react-native-image-zoom-viewer": "^3.0.1",
@ -14505,6 +14506,24 @@
"react-native": "*"
}
},
"node_modules/react-native-fbsdk-next": {
"version": "13.4.1",
"resolved": "https://registry.npmmirror.com/react-native-fbsdk-next/-/react-native-fbsdk-next-13.4.1.tgz",
"integrity": "sha512-Cto+oF0FJyvxKDjKyLKI5DgnLCeeRlXvVQb8qw0XesT1Xune1ijDWAnvt9fy6wXJ4G7K510xKkcSUsbK/KyPhg==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"peerDependencies": {
"expo": ">=47.0.0",
"react-native": ">=0.63.3"
},
"peerDependenciesMeta": {
"expo": {
"optional": true
}
}
},
"node_modules/react-native-gesture-handler": {
"version": "2.20.2",
"resolved": "https://registry.npmmirror.com/react-native-gesture-handler/-/react-native-gesture-handler-2.20.2.tgz",

2
package.json

@ -27,6 +27,7 @@
"axios": "^1.8.4",
"events": "^3.3.0",
"expo": "~52.0.41",
"expo-apple-authentication": "~7.1.3",
"expo-auth-session": "~6.0.3",
"expo-build-properties": "~0.13.3",
"expo-crypto": "~14.0.2",
@ -44,6 +45,7 @@
"react-i18next": "^15.4.1",
"react-native": "0.76.9",
"react-native-dropdown-picker": "^5.4.6",
"react-native-fbsdk-next": "^13.4.1",
"react-native-gesture-handler": "~2.20.2",
"react-native-image-viewing": "^0.2.2",
"react-native-image-zoom-viewer": "^3.0.1",

10
yarn.lock

@ -4805,6 +4805,11 @@ expect@^29.0.0, expect@^29.7.0:
jest-message-util "^29.7.0"
jest-util "^29.7.0"
expo-apple-authentication@~7.1.3:
version "7.1.3"
resolved "https://registry.npmmirror.com/expo-apple-authentication/-/expo-apple-authentication-7.1.3.tgz#3d4ec9fa29ff336eba9b280e7db110639ae7e020"
integrity sha512-TRaF513oDGjGx3hRiAwkMiSnKLN8BIR9Se5Gi3ttz2UUgP9y+tNHV6Ji6/oztJo9ON7zerHg2mn5Y+3B8c2vTQ==
expo-application@~6.0.2:
version "6.0.2"
resolved "https://registry.npmmirror.com/expo-application/-/expo-application-6.0.2.tgz"
@ -7812,6 +7817,11 @@ react-native-dropdown-picker@^5.4.6:
resolved "https://registry.npmmirror.com/react-native-dropdown-picker/-/react-native-dropdown-picker-5.4.6.tgz"
integrity sha512-T1XBHbE++M6aRU3wFYw3MvcOuabhWZ29RK/Ivdls2r1ZkZ62iEBZknLUPeVLMX3x6iUxj4Zgr3X2DGlEGXeHsA==
react-native-fbsdk-next@^13.4.1:
version "13.4.1"
resolved "https://registry.npmmirror.com/react-native-fbsdk-next/-/react-native-fbsdk-next-13.4.1.tgz"
integrity sha512-Cto+oF0FJyvxKDjKyLKI5DgnLCeeRlXvVQb8qw0XesT1Xune1ijDWAnvt9fy6wXJ4G7K510xKkcSUsbK/KyPhg==
react-native-gesture-handler@~2.20.2:
version "2.20.2"
resolved "https://registry.npmmirror.com/react-native-gesture-handler/-/react-native-gesture-handler-2.20.2.tgz"

Loading…
Cancel
Save