|
|
|
@ -1,5 +1,6 @@
|
|
|
|
|
// 余额管理
|
|
|
|
|
import React, { useState, useEffect } from "react"; |
|
|
|
|
|
|
|
|
|
import React, { useState, useCallback, useRef } from "react"; |
|
|
|
|
import { |
|
|
|
|
View, |
|
|
|
|
Text, |
|
|
|
@ -11,7 +12,11 @@ import {
|
|
|
|
|
SafeAreaView, |
|
|
|
|
StatusBar, |
|
|
|
|
Platform, |
|
|
|
|
FlatList, |
|
|
|
|
ActivityIndicator, |
|
|
|
|
} from "react-native"; |
|
|
|
|
import { useFocusEffect } from "@react-navigation/native"; |
|
|
|
|
|
|
|
|
|
import fontSize from "../../utils/fontsizeUtils"; |
|
|
|
|
import widthUtils from "../../utils/widthUtils"; |
|
|
|
|
import { useNavigation } from "@react-navigation/native"; |
|
|
|
@ -20,7 +25,7 @@ import { RootStackParamList } from "../../navigation/types";
|
|
|
|
|
import RechargeScreen from "./RechargeScreen"; |
|
|
|
|
import BackIcon from "../../components/BackIcon"; |
|
|
|
|
import useUserStore from "../../store/user"; |
|
|
|
|
import { rechargeHistory, payApi } from "../../services/api/payApi"; |
|
|
|
|
import { Transaction, payApi } from "../../services/api/payApi"; |
|
|
|
|
import { useTranslation } from "react-i18next"; |
|
|
|
|
|
|
|
|
|
type BalanceScreenNavigationProp = NativeStackNavigationProp< |
|
|
|
@ -33,7 +38,11 @@ export const BalanceScreen = () => {
|
|
|
|
|
const { user } = useUserStore(); |
|
|
|
|
const navigation = useNavigation<BalanceScreenNavigationProp>(); |
|
|
|
|
const [isModalVisible, setIsModalVisible] = useState(false); |
|
|
|
|
const [rechargeHistory, setRechargeHistory] = useState<rechargeHistory[]>([]); |
|
|
|
|
const [rechargeHistory, setRechargeHistory] = useState<Transaction[]>([]); |
|
|
|
|
const [currentPage, setCurrentPage] = useState(1); |
|
|
|
|
const [loading, setLoading] = useState(false); |
|
|
|
|
const [hasMore, setHasMore] = useState(true); |
|
|
|
|
const pageSize = 10; |
|
|
|
|
|
|
|
|
|
const handleOpenModal = () => { |
|
|
|
|
setIsModalVisible(true); |
|
|
|
@ -43,13 +52,84 @@ export const BalanceScreen = () => {
|
|
|
|
|
setIsModalVisible(false); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
const fetchRechargeHistory = async () => { |
|
|
|
|
const response = await payApi.getRechargeHistory(); |
|
|
|
|
setRechargeHistory(response); |
|
|
|
|
}; |
|
|
|
|
fetchRechargeHistory(); |
|
|
|
|
}, []); |
|
|
|
|
const fetchRechargeHistory = async (page: number, refresh = false) => { |
|
|
|
|
if (loading || (!hasMore && !refresh)) return; |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
setLoading(true); |
|
|
|
|
const response = await payApi.getTransactionHistory(page, pageSize); |
|
|
|
|
|
|
|
|
|
if (response.items.length < pageSize) { |
|
|
|
|
setHasMore(false); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (refresh) { |
|
|
|
|
setRechargeHistory(response.items); |
|
|
|
|
} else { |
|
|
|
|
setRechargeHistory(prev => [...prev, ...response.items]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
setCurrentPage(page); |
|
|
|
|
} catch (error) { |
|
|
|
|
console.error("Failed to fetch transaction history:", error); |
|
|
|
|
} finally { |
|
|
|
|
setLoading(false); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const handleLoadMore = () => { |
|
|
|
|
if (!loading && hasMore) { |
|
|
|
|
fetchRechargeHistory(currentPage + 1); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
useFocusEffect( |
|
|
|
|
useCallback(() => { |
|
|
|
|
fetchRechargeHistory(1, true); |
|
|
|
|
}, []) |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const renderTransactionItem = ({ item }: { item: Transaction }) => ( |
|
|
|
|
<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.transactionAmountDisplay, |
|
|
|
|
{ |
|
|
|
|
color: |
|
|
|
|
Number(item.amount) < 0 |
|
|
|
|
? "#0035a4" |
|
|
|
|
: "#ff5217", |
|
|
|
|
}, |
|
|
|
|
]} |
|
|
|
|
> |
|
|
|
|
{item.amount} {item.currency} |
|
|
|
|
</Text> |
|
|
|
|
</View> |
|
|
|
|
<View style={styles.transactionInfoRow}> |
|
|
|
|
<Text style={styles.transactionDate}> |
|
|
|
|
{item.timestamp} |
|
|
|
|
</Text> |
|
|
|
|
<Text style={styles.shipmentReference}> |
|
|
|
|
{item.type} |
|
|
|
|
</Text> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const renderFooter = () => { |
|
|
|
|
if (!loading) return null; |
|
|
|
|
return ( |
|
|
|
|
<View style={styles.loaderContainer}> |
|
|
|
|
<ActivityIndicator size="small" color="#FF8000" /> |
|
|
|
|
</View> |
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<SafeAreaView style={styles.safeArea}> |
|
|
|
@ -62,98 +142,76 @@ export const BalanceScreen = () => {
|
|
|
|
|
> |
|
|
|
|
<BackIcon size={fontSize(22)} /> |
|
|
|
|
</TouchableOpacity> |
|
|
|
|
<Text style={styles.headerTitle}>{t('balance.screen.title')}</Text> |
|
|
|
|
<Text style={styles.headerTitle}>{t("balance.screen.title")}</Text> |
|
|
|
|
<View style={styles.placeholder} /> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
<ScrollView style={styles.container}> |
|
|
|
|
<View style={styles.balanceCard}> |
|
|
|
|
<View style={styles.sunriseGradientContainer}> |
|
|
|
|
<View style={styles.timeContainer}> |
|
|
|
|
<View style={styles.timeContainer2}></View> |
|
|
|
|
</View> |
|
|
|
|
<View style={styles.balanceWidget}> |
|
|
|
|
<Text style={styles.balanceText}>{t('balance.screen.balance_card')}</Text> |
|
|
|
|
<Image |
|
|
|
|
source={require("../../../assets/img/image_11d1b9c.png")} |
|
|
|
|
style={styles.balanceImage} |
|
|
|
|
/> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
<View style={styles.balanceDetailsContainer}> |
|
|
|
|
<View style={styles.totalBalanceCard}> |
|
|
|
|
<View style={styles.cardContainer}> |
|
|
|
|
<View style={styles.financialInfoContainer}> |
|
|
|
|
<Text style={styles.largeBlackText}>{user?.balance}</Text> |
|
|
|
|
<View style={styles.svgContainer}></View> |
|
|
|
|
<View style={styles.container}> |
|
|
|
|
<FlatList |
|
|
|
|
data={rechargeHistory} |
|
|
|
|
renderItem={renderTransactionItem} |
|
|
|
|
keyExtractor={(item) => item.transaction_id.toString()} |
|
|
|
|
onEndReached={handleLoadMore} |
|
|
|
|
onEndReachedThreshold={0.5} |
|
|
|
|
ListFooterComponent={renderFooter} |
|
|
|
|
ListHeaderComponent={() => ( |
|
|
|
|
<View style={styles.balanceCard}> |
|
|
|
|
<View style={styles.sunriseGradientContainer}> |
|
|
|
|
<View style={styles.timeContainer}> |
|
|
|
|
<View style={styles.timeContainer2}></View> |
|
|
|
|
</View> |
|
|
|
|
<View style={styles.totalSoldInfoContainer}> |
|
|
|
|
<Text style={styles.totalSoldeText}> |
|
|
|
|
{t('balance.screen.total_balance')} ({user?.currency}) |
|
|
|
|
<View style={styles.balanceWidget}> |
|
|
|
|
<Text style={styles.balanceText}> |
|
|
|
|
{t("balance.screen.balance_card")} |
|
|
|
|
</Text> |
|
|
|
|
{/* <View style={styles.totalBalanceInfoContainer}> |
|
|
|
|
<View style={styles.verticalCenteredTextBox}> |
|
|
|
|
<Text style={styles.highlightedText}>50,000</Text> |
|
|
|
|
<Text style={styles.expirationInfo}> |
|
|
|
|
Bientôt expiré (FCFA) |
|
|
|
|
</Text> |
|
|
|
|
<Image |
|
|
|
|
source={require("../../../assets/img/image_11d1b9c.png")} |
|
|
|
|
style={styles.balanceImage} |
|
|
|
|
/> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
<View style={styles.balanceDetailsContainer}> |
|
|
|
|
<View style={styles.totalBalanceCard}> |
|
|
|
|
<View style={styles.cardContainer}> |
|
|
|
|
<View style={styles.financialInfoContainer}> |
|
|
|
|
<Text style={styles.largeBlackText}>{user?.balance}</Text> |
|
|
|
|
<View style={styles.svgContainer}></View> |
|
|
|
|
</View> |
|
|
|
|
<View style={styles.deadlineInfoContainer}> |
|
|
|
|
<Text style={styles.deadlineText}>2025-05-09</Text> |
|
|
|
|
<Text style={styles.expirationInfo}>Date limite</Text> |
|
|
|
|
<View style={styles.totalSoldInfoContainer}> |
|
|
|
|
<Text style={styles.totalSoldeText}> |
|
|
|
|
{t("balance.screen.total_balance")} ({user?.currency}) |
|
|
|
|
</Text> |
|
|
|
|
</View> |
|
|
|
|
</View> */} |
|
|
|
|
</View> |
|
|
|
|
<View |
|
|
|
|
style={[ |
|
|
|
|
styles.buttonContainer, |
|
|
|
|
{ backgroundColor: "#FF8000", alignSelf: "center" }, |
|
|
|
|
]} |
|
|
|
|
> |
|
|
|
|
<TouchableOpacity |
|
|
|
|
style={styles.button} |
|
|
|
|
onPress={handleOpenModal} |
|
|
|
|
> |
|
|
|
|
<Text style={styles.buttonText}> |
|
|
|
|
{t("balance.screen.recharge_now")} |
|
|
|
|
</Text> |
|
|
|
|
</TouchableOpacity> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
<View |
|
|
|
|
style={[ |
|
|
|
|
styles.buttonContainer, |
|
|
|
|
{ backgroundColor: "#FF8000", alignSelf: "center" }, |
|
|
|
|
]} |
|
|
|
|
> |
|
|
|
|
<TouchableOpacity |
|
|
|
|
style={styles.button} |
|
|
|
|
onPress={handleOpenModal} |
|
|
|
|
> |
|
|
|
|
<Text style={styles.buttonText}>{t('balance.screen.recharge_now')}</Text> |
|
|
|
|
</TouchableOpacity> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
<View style={styles.transactionDetailsContainer}> |
|
|
|
|
<View style={styles.balanceDetailContainer}> |
|
|
|
|
<Text style={styles.balanceDetailTitle}>{t('balance.screen.balance_detail')}</Text> |
|
|
|
|
<View style={styles.transactionDetailsContainer1}> |
|
|
|
|
{rechargeHistory.map((item) => ( |
|
|
|
|
<View style={styles.transactionHistoryList} key={item.recharge_id}> |
|
|
|
|
{/* Repeated Transaction Details */} |
|
|
|
|
<View style={styles.transactionDetailsPanel}> |
|
|
|
|
<View style={styles.transactionDetailsRow}> |
|
|
|
|
<Text style={styles.transactionDescriptionBold}> |
|
|
|
|
{item.payment_method} |
|
|
|
|
</Text> |
|
|
|
|
<Text style={styles.transactionAmountDisplay}> |
|
|
|
|
{item.amount} {item.currency} |
|
|
|
|
</Text> |
|
|
|
|
</View> |
|
|
|
|
<View style={styles.transactionInfoRow}> |
|
|
|
|
<Text style={styles.transactionDate}> |
|
|
|
|
{item.create_time} |
|
|
|
|
</Text> |
|
|
|
|
<Text style={styles.shipmentReference}> |
|
|
|
|
{item.transaction_id} |
|
|
|
|
</Text> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
{/* Additional transaction panels can be added here */} |
|
|
|
|
</View> |
|
|
|
|
))} |
|
|
|
|
<View style={styles.transactionDetailsContainer}> |
|
|
|
|
<View style={styles.balanceDetailContainer}> |
|
|
|
|
<Text style={styles.balanceDetailTitle}> |
|
|
|
|
{t("balance.screen.balance_detail")} |
|
|
|
|
</Text> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
</ScrollView> |
|
|
|
|
)} |
|
|
|
|
/> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
<Modal |
|
|
|
|
animationType="slide" |
|
|
|
@ -364,7 +422,6 @@ const styles = StyleSheet.create({
|
|
|
|
|
transactionAmountDisplay: { |
|
|
|
|
fontSize: fontSize(24), |
|
|
|
|
fontWeight: "bold", |
|
|
|
|
color: "#002fa7", |
|
|
|
|
}, |
|
|
|
|
transactionInfoRow: { |
|
|
|
|
flexDirection: "row", |
|
|
|
@ -411,4 +468,9 @@ const styles = StyleSheet.create({
|
|
|
|
|
borderTopLeftRadius: 20, |
|
|
|
|
borderTopRightRadius: 20, |
|
|
|
|
}, |
|
|
|
|
loaderContainer: { |
|
|
|
|
paddingVertical: 20, |
|
|
|
|
alignItems: 'center', |
|
|
|
|
justifyContent: 'center', |
|
|
|
|
}, |
|
|
|
|
}); |
|
|
|
|