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.
382 lines
10 KiB
382 lines
10 KiB
3 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";
|
||
|
|
||
|
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 = {
|
||
|
Pay: { payUrl: string };
|
||
|
}
|
||
|
|
||
|
const PhoneNumberInputModal = ({
|
||
|
isVisible,
|
||
|
onClose,
|
||
|
paymentParams,
|
||
|
onSubmit,
|
||
|
onCloses,
|
||
|
}: PhoneNumberInputModalProps) => {
|
||
|
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,
|
||
|
});
|
||
|
|
||
|
setIsSubmitting(false)
|
||
|
}).catch((err) => {
|
||
|
Alert.alert("Error", '支付失败,请重试');
|
||
|
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}>
|
||
|
<Text style={styles.title}>Recharger</Text>
|
||
|
<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}>
|
||
|
Résumé de la recharge
|
||
|
</Text>
|
||
|
|
||
|
<View style={styles.paymentSummaryRow}>
|
||
|
<Text style={styles.paymentSummaryLabel}>Montant:</Text>
|
||
|
<Text style={styles.paymentSummaryValue}>
|
||
|
{paymentParams?.selectedPriceLabel || ""}
|
||
|
</Text>
|
||
|
</View>
|
||
|
|
||
|
{paymentParams?.currency !== "FCFA" && (
|
||
|
<View style={styles.paymentSummaryRow}>
|
||
|
<Text style={styles.paymentSummaryLabel}>
|
||
|
Montant converti:
|
||
|
</Text>
|
||
|
<Text style={styles.paymentSummaryValueHighlight}>
|
||
|
{paymentParams?.currency === "USD" ? "$" : "€"}
|
||
|
{paymentParams?.amount.toFixed(2) || "0.00"}
|
||
|
</Text>
|
||
|
</View>
|
||
|
)}
|
||
|
|
||
|
<View style={styles.paymentSummaryRow}>
|
||
|
<Text style={styles.paymentSummaryLabel}>
|
||
|
Méthode de paiement:
|
||
|
</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}>
|
||
|
Numéro de téléphone
|
||
|
</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"
|
||
|
placeholder="Entrez votre numéro"
|
||
|
placeholderTextColor="#999"
|
||
|
/>
|
||
|
</View>
|
||
|
</View>
|
||
|
|
||
|
<View style={styles.supportedOperatorsContainer}>
|
||
|
<Text style={styles.supportedOperatorsTitle}>
|
||
|
Opérateurs pris en charge
|
||
|
</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}>
|
||
|
PAYER{" "}
|
||
|
{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;
|