231 lines
6.9 KiB
TypeScript
231 lines
6.9 KiB
TypeScript
import React, { useCallback, useState } from 'react';
|
|
import {
|
|
View,
|
|
Text,
|
|
SafeAreaView,
|
|
FlatList,
|
|
TouchableOpacity,
|
|
Modal,
|
|
TextInput,
|
|
KeyboardAvoidingView,
|
|
Platform,
|
|
Pressable,
|
|
} from 'react-native';
|
|
// import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
|
import { Header } from '@components';
|
|
import { useAppTheme } from '@theme';
|
|
import { getStyles } from './walletScreen.styles';
|
|
import { WalletTransaction } from '@interfaces';
|
|
import { useAppDispatch, useAppSelector } from '@store';
|
|
import { getAllWalletTransactions, initializeWalletTopUpThunk } from './thunk';
|
|
import { useFocusEffect } from '@react-navigation/native';
|
|
import { getWalletBalanceThunk } from '../accountScreen';
|
|
import { useStripePayment } from '../checkoutPaymentScreen/hooks/useStripePayment';
|
|
import { useTopUp } from './hooks/useTopUp';
|
|
// import { addMoneyThunk } from './thunk'; // wire this up to your actual top-up API
|
|
|
|
const WalletScreen = () => {
|
|
const { colors } = useAppTheme();
|
|
const styles = getStyles(colors);
|
|
|
|
const dispatch = useAppDispatch();
|
|
const { walletTransactions } = useAppSelector(state => state.wallet);
|
|
const { wallet } = useAppSelector(state => state.account);
|
|
|
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
|
const [amount, setAmount] = useState('');
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
const [error, setError] = useState('');
|
|
const { topUpCardPayment, isPaymentProcessing } = useTopUp();
|
|
|
|
useFocusEffect(
|
|
useCallback(() => {
|
|
dispatch(getAllWalletTransactions());
|
|
dispatch(getWalletBalanceThunk());
|
|
}, []),
|
|
);
|
|
|
|
const openModal = () => {
|
|
setAmount('');
|
|
setError('');
|
|
setIsModalVisible(true);
|
|
};
|
|
|
|
const closeModal = () => {
|
|
if (isSubmitting) return;
|
|
setIsModalVisible(false);
|
|
};
|
|
|
|
const handleAmountChange = (text: string) => {
|
|
// allow only digits and a single decimal point
|
|
const sanitized = text.replace(/[^0-9.]/g, '');
|
|
setAmount(sanitized);
|
|
if (error) setError('');
|
|
};
|
|
|
|
const handleTopUp = async () => {
|
|
const numericAmount = parseFloat(amount);
|
|
|
|
if (!amount || isNaN(numericAmount) || numericAmount <= 0) {
|
|
setError('Please enter a valid amount');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
setIsSubmitting(true);
|
|
const payload = {
|
|
amount: numericAmount,
|
|
paymentMethod: 'CARD'
|
|
}
|
|
|
|
const response = await dispatch(initializeWalletTopUpThunk(payload)).unwrap();
|
|
const success = await topUpCardPayment(response);
|
|
setIsSubmitting(false);
|
|
setIsModalVisible(false);
|
|
setAmount('');
|
|
} catch (e) {
|
|
setIsSubmitting(false);
|
|
setError('Something went wrong. Please try again.');
|
|
}
|
|
};
|
|
|
|
const renderItem = ({ item }: { item: WalletTransaction }) => {
|
|
const isCredit = item.direction === 'IN';
|
|
|
|
return (
|
|
<View style={styles.transactionCard}>
|
|
<View
|
|
style={[
|
|
styles.iconContainer,
|
|
{
|
|
backgroundColor: isCredit ? '#DFF7E4' : '#FFE5E5',
|
|
},
|
|
]}
|
|
>
|
|
{/* <Icon
|
|
name={isCredit ? 'arrow-bottom-left' : 'arrow-top-right'}
|
|
size={22}
|
|
color={isCredit ? '#18A558' : '#F04438'}
|
|
/> */}
|
|
</View>
|
|
|
|
<View style={styles.transactionInfo}>
|
|
<Text style={styles.transactionTitle}>{item.type}</Text>
|
|
|
|
<Text style={styles.transactionRef}>{item.transactionReference}</Text>
|
|
|
|
<Text style={styles.transactionDate}>
|
|
{new Date(item.createdAt).toLocaleString()}
|
|
</Text>
|
|
</View>
|
|
|
|
<View style={styles.amountContainer}>
|
|
<Text
|
|
style={[
|
|
styles.amount,
|
|
{
|
|
color: isCredit ? '#18A558' : '#F04438',
|
|
},
|
|
]}
|
|
>
|
|
{isCredit ? '+' : '-'}₹{item.amount}
|
|
</Text>
|
|
|
|
<Text style={styles.balanceText}>Bal ₹{item.balanceAfter}</Text>
|
|
</View>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<KeyboardAvoidingView style={styles.container}>
|
|
<Header title="Wallet" />
|
|
|
|
<View style={styles.balanceCard}>
|
|
<Text style={styles.balanceLabel}>Available Balance</Text>
|
|
|
|
<Text style={styles.balance}>₹{wallet?.balance.toFixed(2)}</Text>
|
|
|
|
<TouchableOpacity style={styles.addMoneyButton} onPress={openModal}>
|
|
{/* <Icon name="plus" color="#FFF" size={20} /> */}
|
|
<Text style={styles.addMoneyText}>Add Money</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
<Text style={styles.sectionTitle}>Recent Transactions</Text>
|
|
|
|
<FlatList
|
|
data={walletTransactions}
|
|
keyExtractor={item => item.id}
|
|
renderItem={renderItem}
|
|
showsVerticalScrollIndicator={false}
|
|
contentContainerStyle={styles.listContainer}
|
|
ListEmptyComponent={
|
|
<View style={styles.emptyContainer}>
|
|
{/* <Icon name="wallet-outline" size={70} color="#BDBDBD" /> */}
|
|
<Text style={styles.emptyText}>No Transactions Yet</Text>
|
|
</View>
|
|
}
|
|
/>
|
|
|
|
<Modal
|
|
visible={isModalVisible}
|
|
transparent
|
|
animationType="fade"
|
|
onRequestClose={closeModal}
|
|
>
|
|
<KeyboardAvoidingView
|
|
style={styles.modalOverlay}
|
|
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
|
|
>
|
|
<Pressable style={styles.modalBackdrop} onPress={closeModal} />
|
|
|
|
<View style={styles.modalCard}>
|
|
<Text style={styles.modalTitle}>Add Money</Text>
|
|
<Text style={styles.modalSubtitle}>
|
|
Enter an amount to top up your wallet
|
|
</Text>
|
|
|
|
<View style={styles.amountInputWrapper}>
|
|
<Text style={styles.rupeeSymbol}>₹</Text>
|
|
<TextInput
|
|
style={styles.amountInput}
|
|
keyboardType="decimal-pad"
|
|
placeholder="0.00"
|
|
placeholderTextColor="#B0B0B0"
|
|
value={amount}
|
|
onChangeText={handleAmountChange}
|
|
autoFocus
|
|
/>
|
|
</View>
|
|
|
|
{error ? <Text style={styles.modalError}>{error}</Text> : null}
|
|
|
|
<TouchableOpacity
|
|
style={[
|
|
styles.topUpButton,
|
|
isSubmitting && styles.topUpButtonDisabled,
|
|
]}
|
|
onPress={handleTopUp}
|
|
disabled={isSubmitting}
|
|
>
|
|
<Text style={styles.topUpButtonText}>
|
|
{isSubmitting ? 'Processing...' : 'Add Top Up'}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
|
|
<TouchableOpacity
|
|
style={styles.modalCancelButton}
|
|
onPress={closeModal}
|
|
disabled={isSubmitting}
|
|
>
|
|
<Text style={styles.modalCancelText}>Cancel</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</KeyboardAvoidingView>
|
|
</Modal>
|
|
</KeyboardAvoidingView>
|
|
);
|
|
};
|
|
|
|
export default WalletScreen; |