Refactor transaction display in HomeScreen by integrating TransactionList component and removing redundant code for rendering transactions.
This commit is contained in:
132
src/components/TransactionList.js
Normal file
132
src/components/TransactionList.js
Normal file
@@ -0,0 +1,132 @@
|
||||
import React from 'react';
|
||||
import { View, Text, FlatList, StyleSheet } from 'react-native';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { COLORS } from '../constants/colors';
|
||||
|
||||
const TransactionList = ({ transactions }) => {
|
||||
if (!transactions || transactions.length === 0) {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.emptyText}>No transactions yet.</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<FlatList
|
||||
data={Object.keys(groupedTransactions)}
|
||||
renderItem={renderTransactionSection}
|
||||
keyExtractor={(date) => date}
|
||||
scrollEnabled={false}
|
||||
ItemSeparatorComponent={() => <View style={styles.separator} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
padding: 16,
|
||||
},
|
||||
emptyText: {
|
||||
textAlign: 'center',
|
||||
color: COLORS.textSecondary,
|
||||
},
|
||||
transactionItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 12,
|
||||
},
|
||||
transactionIcon: {
|
||||
width: 44,
|
||||
height: 44,
|
||||
borderRadius: 22,
|
||||
backgroundColor: COLORS.background,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: 16,
|
||||
},
|
||||
transactionDetails: {
|
||||
flex: 1,
|
||||
},
|
||||
transactionTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: COLORS.textPrimary,
|
||||
marginBottom: 2,
|
||||
},
|
||||
transactionDate: {
|
||||
fontSize: 13,
|
||||
color: COLORS.textSecondary,
|
||||
},
|
||||
transactionAmount: {
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
},
|
||||
transactionDateHeader: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: COLORS.textSecondary,
|
||||
backgroundColor: COLORS.white,
|
||||
paddingTop: 16,
|
||||
paddingBottom: 8,
|
||||
paddingHorizontal: 4,
|
||||
},
|
||||
separator: {
|
||||
height: 1,
|
||||
backgroundColor: COLORS.gray[200],
|
||||
marginLeft: 60,
|
||||
},
|
||||
});
|
||||
|
||||
export default TransactionList;
|
||||
@@ -16,6 +16,7 @@ import { useAuth } from '../../contexts/AuthContext';
|
||||
import { COLORS } from '../../constants/colors';
|
||||
import MetricCard from '../../components/MetricCard';
|
||||
import apiService from '../../services/apiService';
|
||||
import TransactionList from '../../components/TransactionList';
|
||||
|
||||
const STATIC_TRANSACTIONS = [
|
||||
{
|
||||
@@ -212,57 +213,6 @@ 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" />
|
||||
@@ -330,17 +280,7 @@ const HomeScreen = () => {
|
||||
<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>
|
||||
)}
|
||||
<TransactionList transactions={transactions} />
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
@@ -472,54 +412,6 @@ const styles = StyleSheet.create({
|
||||
color: COLORS.textSecondary,
|
||||
textAlign: 'center',
|
||||
},
|
||||
transactionsList: {
|
||||
marginTop: 16,
|
||||
},
|
||||
transactionItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 12,
|
||||
},
|
||||
transactionIcon: {
|
||||
width: 44,
|
||||
height: 44,
|
||||
borderRadius: 22,
|
||||
backgroundColor: COLORS.background,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: 16,
|
||||
},
|
||||
transactionDetails: {
|
||||
flex: 1,
|
||||
},
|
||||
transactionTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: COLORS.textPrimary,
|
||||
marginBottom: 2,
|
||||
},
|
||||
transactionDate: {
|
||||
fontSize: 13,
|
||||
color: COLORS.textSecondary,
|
||||
},
|
||||
transactionAmount: {
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
},
|
||||
transactionDateHeader: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: COLORS.textSecondary,
|
||||
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',
|
||||
justifyContent: 'space-between',
|
||||
|
||||
Reference in New Issue
Block a user