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 { COLORS } from '../../constants/colors';
|
||||||
import MetricCard from '../../components/MetricCard';
|
import MetricCard from '../../components/MetricCard';
|
||||||
import apiService from '../../services/apiService';
|
import apiService from '../../services/apiService';
|
||||||
|
import TransactionList from '../../components/TransactionList';
|
||||||
|
|
||||||
const STATIC_TRANSACTIONS = [
|
const STATIC_TRANSACTIONS = [
|
||||||
{
|
{
|
||||||
@@ -212,57 +213,6 @@ const HomeScreen = () => {
|
|||||||
setRefreshing(false);
|
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 (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<StatusBar style="dark" />
|
<StatusBar style="dark" />
|
||||||
@@ -330,17 +280,7 @@ const HomeScreen = () => {
|
|||||||
<Text style={styles.seeAllText}>See All</Text>
|
<Text style={styles.seeAllText}>See All</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
{transactions.length > 0 ? (
|
<TransactionList transactions={transactions} />
|
||||||
<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>
|
</View>
|
||||||
)}
|
)}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
@@ -472,54 +412,6 @@ const styles = StyleSheet.create({
|
|||||||
color: COLORS.textSecondary,
|
color: COLORS.textSecondary,
|
||||||
textAlign: 'center',
|
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: {
|
metricsGrid: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
|
|||||||
Reference in New Issue
Block a user