You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
10 KiB

2 weeks ago
import React, { useState, useEffect } from "react";
import {
View,
Text,
StyleSheet,
TextInput,
TouchableOpacity,
Image,
ActivityIndicator,
Modal,
SafeAreaView,
BackHandler,
Alert
} from "react-native";
import fontSize from "../../utils/fontsizeUtils";
import BackIcon from "../../components/BackIcon";
import {payApi} from "../../services/api/payApi";
import { useNavigation } from "@react-navigation/native";
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
2 weeks ago
import { useTranslation } from "react-i18next";
2 weeks ago
interface PhoneNumberInputModalProps {
isVisible: boolean;
onClose: () => void;
paymentParams: {
originalAmount: number;
amount: number;
currency: string;
payment_method: string;
selectedPriceLabel: string;
onCloses?: () => void;
} | null;
onSubmit: (phoneNumber: string) => Promise<void>;
onCloses?: () => void;
}
type RootStackParamList = {
2 weeks ago
Pay: { payUrl: string, method: string, order_id: string };
2 weeks ago
}
const PhoneNumberInputModal = ({
isVisible,
onClose,
paymentParams,
onSubmit,
onCloses,
}: PhoneNumberInputModalProps) => {
2 weeks ago
const { t } = useTranslation();
2 weeks ago
const [phoneNumber, setPhoneNumber] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const navigation =
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
useEffect(() => {
const backAction = () => {
if (isVisible) {
onClose();
return true;
}
return false;
};
const backHandler = BackHandler.addEventListener(
"hardwareBackPress",
backAction
);
return () => backHandler.remove();
}, [isVisible, onClose]);
const handlePaySubmit = async () => {
if (!paymentParams) return;
setIsSubmitting(true)
const data = {
amount: paymentParams.amount,
currency: paymentParams.currency,
payment_method: paymentParams.payment_method,
}
payApi.initiateRecharge(data).then((res) => {
console.log(res);
// 成功后关闭所有模态窗口
onClose();
if (onCloses) {
onCloses();
}
navigation.navigate("Pay", {
payUrl: res.payment.payment_url,
2 weeks ago
method: paymentParams.payment_method,
order_id: res.payment.order_id.toString(),
2 weeks ago
});
setIsSubmitting(false)
}).catch((err) => {
2 weeks ago
Alert.alert("Error", t('balance.phone_modal.payment_failed'));
2 weeks ago
setIsSubmitting(false)
})
};
return (
<Modal
visible={isVisible}
animationType="slide"
transparent={true}
onRequestClose={onClose}
presentationStyle="overFullScreen"
>
<SafeAreaView style={styles.modalContainer}>
<View style={styles.modalContent}>
<View style={styles.header}>
2 weeks ago
<Text style={styles.title}>{t('balance.phone_modal.title')}</Text>
2 weeks ago
<TouchableOpacity onPress={onClose} style={styles.backButton}>
<Text style={styles.backButtonText}>
<BackIcon size={fontSize(18)} />
</Text>
</TouchableOpacity>
</View>
<View style={styles.paymentConfirmContainer}>
{/* 充值金额信息 */}
<View style={styles.paymentSummaryCard}>
<Text style={styles.paymentSummaryTitle}>
2 weeks ago
{t('balance.phone_modal.recharge_summary')}
2 weeks ago
</Text>
<View style={styles.paymentSummaryRow}>
2 weeks ago
<Text style={styles.paymentSummaryLabel}>{t('balance.phone_modal.amount')}</Text>
2 weeks ago
<Text style={styles.paymentSummaryValue}>
{paymentParams?.selectedPriceLabel || ""}
</Text>
</View>
{paymentParams?.currency !== "FCFA" && (
<View style={styles.paymentSummaryRow}>
<Text style={styles.paymentSummaryLabel}>
2 weeks ago
{t('balance.phone_modal.converted_amount')}
2 weeks ago
</Text>
<Text style={styles.paymentSummaryValueHighlight}>
{paymentParams?.currency === "USD" ? "$" : "€"}
{paymentParams?.amount.toFixed(2) || "0.00"}
</Text>
</View>
)}
<View style={styles.paymentSummaryRow}>
<Text style={styles.paymentSummaryLabel}>
2 weeks ago
{t('balance.phone_modal.payment_method')}
2 weeks ago
</Text>
<Text style={styles.paymentSummaryValue}>
{paymentParams?.payment_method || "Non sélectionné"}
</Text>
</View>
</View>
{/* 电话号码输入 */}
{paymentParams?.payment_method === "mobile_money" && (
<>
<View style={styles.phoneInputContainer}>
<Text style={styles.phoneInputLabel}>
2 weeks ago
{t('balance.phone_modal.phone_number')}
2 weeks ago
</Text>
<View style={styles.phoneInputWrapper}>
<View style={styles.countryCodeContainer}>
<Text style={styles.countryCodeText}>+89</Text>
</View>
<TextInput
style={styles.phoneInput}
value={phoneNumber}
onChangeText={setPhoneNumber}
keyboardType="phone-pad"
2 weeks ago
placeholder={t('balance.phone_modal.enter_phone')}
2 weeks ago
placeholderTextColor="#999"
/>
</View>
</View>
<View style={styles.supportedOperatorsContainer}>
<Text style={styles.supportedOperatorsTitle}>
2 weeks ago
{t('balance.phone_modal.supported_operators')}
2 weeks ago
</Text>
<View style={styles.operatorsRow}>
<Image
source={require("../../../assets/img/image_7337a807.png")}
style={styles.operatorSmallIcon}
/>
<Image
source={require("../../../assets/img/image_96b927ad.png")}
style={styles.operatorSmallIcon}
/>
<Image
source={require("../../../assets/img/image_1fee7e8b.png")}
style={styles.operatorSmallIcon}
/>
</View>
</View>
</>
)}
{/* 支付按钮 */}
<TouchableOpacity
style={[
styles.payButton,
isSubmitting && styles.payButtonDisabled,
]}
onPress={handlePaySubmit}
disabled={isSubmitting}
>
{isSubmitting ? (
<ActivityIndicator size="small" color="#fff" />
) : (
<Text style={styles.payButtonText}>
2 weeks ago
{t('balance.phone_modal.pay')}{" "}
2 weeks ago
{paymentParams?.currency === "FCFA"
? paymentParams.originalAmount.toLocaleString() +
" " +
paymentParams.currency
: paymentParams?.currency === "USD"
? "$" + paymentParams?.amount.toFixed(2)
: paymentParams?.amount.toFixed(2) + " €"}
</Text>
)}
</TouchableOpacity>
</View>
</View>
</SafeAreaView>
</Modal>
);
};
const styles = StyleSheet.create({
modalContainer: {
flex: 1,
backgroundColor: "rgba(0, 0, 0, 0.5)",
justifyContent: "center",
alignItems: "center",
},
modalContent: {
height: "80%",
width: "100%",
backgroundColor: "#fff",
borderTopLeftRadius: 10,
borderTopRightRadius: 10,
marginTop: "auto",
},
header: {
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
padding: 24,
paddingBottom: 0,
position: "relative",
marginTop: 20,
marginBottom: 20,
},
title: {
fontSize: 24,
fontWeight: "700",
textTransform: "capitalize",
color: "black",
position: "absolute",
left: 0,
right: 0,
textAlign: "center",
},
backButton: {
position: "absolute",
left: 24,
zIndex: 1,
},
backButtonText: {
fontSize: fontSize(14),
color: "#007AFF",
fontWeight: "500",
},
paymentConfirmContainer: {
flex: 1,
padding: 20,
backgroundColor: "#fff",
},
paymentSummaryCard: {
backgroundColor: "#f5f9ff",
borderRadius: 10,
padding: 20,
marginBottom: 20,
},
paymentSummaryTitle: {
fontSize: fontSize(18),
fontWeight: "700",
marginBottom: 15,
color: "#333",
},
paymentSummaryRow: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 10,
},
paymentSummaryLabel: {
fontSize: fontSize(14),
color: "#666",
},
paymentSummaryValue: {
fontSize: fontSize(14),
fontWeight: "500",
color: "#333",
},
paymentSummaryValueHighlight: {
fontSize: fontSize(14),
fontWeight: "600",
color: "#ff5100",
},
phoneInputContainer: {
marginBottom: 20,
},
phoneInputLabel: {
fontSize: fontSize(16),
fontWeight: "500",
marginBottom: 10,
color: "#333",
},
phoneInputWrapper: {
flexDirection: "row",
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 25,
overflow: "hidden",
},
countryCodeContainer: {
backgroundColor: "#f5f5f5",
paddingHorizontal: 15,
justifyContent: "center",
borderRightWidth: 1,
borderRightColor: "#ddd",
},
countryCodeText: {
fontSize: fontSize(16),
color: "#333",
},
phoneInput: {
flex: 1,
height: 50,
paddingHorizontal: 15,
fontSize: fontSize(16),
color: "#333",
},
supportedOperatorsContainer: {
marginBottom: 30,
},
supportedOperatorsTitle: {
fontSize: fontSize(16),
fontWeight: "500",
marginBottom: 10,
color: "#333",
},
operatorsRow: {
flexDirection: "row",
alignItems: "center",
},
operatorSmallIcon: {
width: 70,
height: 26,
resizeMode: "contain",
marginRight: 15,
},
payButton: {
backgroundColor: "#002fa7",
borderRadius: 25,
height: 50,
justifyContent: "center",
alignItems: "center",
marginTop: 20,
},
payButtonDisabled: {
backgroundColor: "#8da0d4",
opacity: 0.7,
},
payButtonText: {
color: "white",
fontSize: fontSize(16),
fontWeight: "700",
},
});
export default PhoneNumberInputModal;