Add transaction display feature to HomeScreen

This commit is contained in:
2025-09-10 20:34:38 +05:00
parent b925b48dd4
commit 4efaf2543e

View File

@@ -8,6 +8,7 @@ import {
TouchableOpacity,
ActivityIndicator,
RefreshControl,
FlatList,
} from 'react-native';
import { StatusBar } from 'expo-status-bar';
import { Ionicons } from '@expo/vector-icons';
@@ -16,6 +17,89 @@ import { COLORS } from '../../constants/colors';
import MetricCard from '../../components/MetricCard';
import apiService from '../../services/apiService';
const STATIC_TRANSACTIONS = [
{
id: 1,
type: 'debit',
description: 'Canva Design and Publishing',
date: '2025-09-07T10:30:00Z',
amount: 10.0,
currency: 'EUR',
},
{
id: 2,
type: 'debit',
description: 'Google',
date: '2025-09-07T11:00:00Z',
amount: 12.99,
currency: 'SAR',
},
{
id: 3,
type: 'debit',
description: 'Canva Design and Publishing',
date: '2025-09-05T14:15:00Z',
amount: 10.0,
currency: 'EUR',
},
{
id: 4,
type: 'credit',
description: 'Töleg alyňýan hasap',
date: '2025-09-03T09:00:00Z',
amount: 20.0,
currency: 'USD',
},
{
id: 5,
type: 'debit',
description: 'Комиссия за оплату',
date: '2025-09-03T09:01:00Z',
amount: 0.12,
currency: 'USD',
},
{
id: 6,
type: 'credit',
description: 'Hasaby doldurmak',
date: '2025-09-02T18:45:00Z',
amount: 10.0,
currency: 'USD',
},
{
id: 7,
type: 'debit',
description: 'Canva Design and Publishing',
date: '2025-09-01T12:00:00Z',
amount: 10.0,
currency: 'EUR',
},
{
id: 8,
type: 'debit',
description: 'Netflix',
date: '2025-08-28T16:00:00Z',
amount: 9.99,
currency: 'USD',
},
{
id: 9,
type: 'credit',
description: 'Bank Transfer',
date: '2025-08-25T08:20:00Z',
amount: 500.0,
currency: 'TMT',
},
{
id: 10,
type: 'debit',
description: 'Amazon',
date: '2025-08-23T19:55:00Z',
amount: 45.5,
currency: 'USD',
},
];
const HomeScreen = () => {
const { user, logout } = useAuth();
const [metrics, setMetrics] = useState(null);
@@ -25,6 +109,7 @@ const HomeScreen = () => {
const [cardBalanceError, setCardBalanceError] = useState(null);
const [isBalanceVisible, setIsBalanceVisible] = useState(true);
const [refreshing, setRefreshing] = useState(false);
const [transactions, setTransactions] = useState(STATIC_TRANSACTIONS);
const showBalanceCard = !loadingCardBalance && cardBalanceError === null && cardBalance !== null;
@@ -50,16 +135,18 @@ const HomeScreen = () => {
}, []);
useEffect(() => {
const fetchCardBalance = async () => {
const fetchCardData = async () => {
// Ensure user has filled all required card & passport fields
if (!user?.passport_serie || !user?.passport_id || !user?.card_number || !user?.card_month || !user?.card_year) {
setLoadingCardBalance(false);
return;
}
setLoadingCardBalance(true);
try {
const res = await apiService.getCardBalanceQuickCheck();
if (res.success) {
// Try common balance keys else fallback to raw
const raw = res.data;
let balanceValue = null;
if (raw && typeof raw === 'object') {
@@ -73,12 +160,13 @@ const HomeScreen = () => {
}
} catch (e) {
console.warn('Error fetching card balance:', e);
setCardBalanceError('Error fetching balance');
} finally {
setLoadingCardBalance(false);
}
};
fetchCardBalance();
fetchCardData();
}, [user]);
const handleRefresh = async () => {
@@ -124,6 +212,57 @@ const HomeScreen = () => {
setRefreshing(false);
};
const groupedTransactions = transactions.reduce((acc, transaction) => {
const date = new Date(transaction.date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
if (!acc[date]) {
acc[date] = [];
}
acc[date].push(transaction);
return acc;
}, {});
const renderTransactionItem = ({ item }) => (
<View style={styles.transactionItem}>
<View style={styles.transactionIcon}>
<Ionicons
name={item.type === 'credit' ? 'arrow-down' : 'arrow-up'}
size={20}
color={item.type === 'credit' ? COLORS.success : COLORS.danger}
/>
</View>
<View style={styles.transactionDetails}>
<Text style={styles.transactionTitle}>{item.description}</Text>
<Text style={styles.transactionDate}>{new Date(item.date).toLocaleTimeString()}</Text>
</View>
<Text
style={[
styles.transactionAmount,
{ color: item.type === 'credit' ? COLORS.success : COLORS.textPrimary },
]}
>
{item.type === 'credit' ? '+' : '-'}
{item.amount} {item.currency}
</Text>
</View>
);
const renderTransactionSection = ({ item: date }) => (
<View>
<Text style={styles.transactionDateHeader}>{date}</Text>
<FlatList
data={groupedTransactions[date]}
renderItem={renderTransactionItem}
keyExtractor={(item) => item.id.toString()}
scrollEnabled={false}
ItemSeparatorComponent={() => <View style={styles.separator} />}
/>
</View>
);
return (
<SafeAreaView style={styles.container}>
<StatusBar style="dark" />
@@ -149,7 +288,7 @@ const HomeScreen = () => {
{/* Metrics */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Metrics</Text>
<Text style={styles.sectionTitle}>Görkezijiler</Text>
{loadingMetrics ? (
<ActivityIndicator color={COLORS.primary} style={{ marginTop: 16 }} />
) : (
@@ -181,6 +320,29 @@ const HomeScreen = () => {
</View>
</View>
)}
{/* Card Transactions */}
{showBalanceCard && (
<View style={styles.section}>
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}>Transactions</Text>
<TouchableOpacity>
<Text style={styles.seeAllText}>See All</Text>
</TouchableOpacity>
</View>
{transactions.length > 0 ? (
<FlatList
data={Object.keys(groupedTransactions)}
renderItem={renderTransactionSection}
keyExtractor={(date) => date}
scrollEnabled={false}
ItemSeparatorComponent={() => <View style={styles.separator} />}
/>
) : (
<Text style={{ textAlign: 'center', color: COLORS.textSecondary }}>No transactions yet.</Text>
)}
</View>
)}
</ScrollView>
</SafeAreaView>
);
@@ -311,20 +473,21 @@ const styles = StyleSheet.create({
textAlign: 'center',
},
transactionsList: {
gap: 16,
marginTop: 16,
},
transactionItem: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 12,
},
transactionIcon: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: COLORS.backgroundSecondary,
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: COLORS.background,
alignItems: 'center',
justifyContent: 'center',
marginRight: 12,
marginRight: 16,
},
transactionDetails: {
flex: 1,
@@ -333,34 +496,29 @@ const styles = StyleSheet.create({
fontSize: 16,
fontWeight: '600',
color: COLORS.textPrimary,
marginBottom: 2,
},
transactionDate: {
fontSize: 14,
fontSize: 13,
color: COLORS.textSecondary,
},
transactionAmount: {
fontSize: 16,
fontWeight: 'bold',
color: COLORS.success,
fontWeight: '700',
},
servicesGrid: {
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-between',
},
serviceItem: {
width: '48%',
padding: 16,
backgroundColor: COLORS.backgroundSecondary,
borderRadius: 12,
alignItems: 'center',
marginBottom: 12,
},
serviceText: {
fontSize: 12,
transactionDateHeader: {
fontSize: 14,
fontWeight: '600',
color: COLORS.textSecondary,
textAlign: 'center',
marginTop: 8,
backgroundColor: COLORS.white,
paddingTop: 16,
paddingBottom: 8,
paddingHorizontal: 4,
},
separator: {
height: 1,
backgroundColor: COLORS.gray[200],
marginLeft: 60, // Align with transaction details, skipping the icon
},
metricsGrid: {
flexDirection: 'row',