duit/components/TransactionList.tsx

149 lines
3.5 KiB
TypeScript
Raw Permalink Normal View History

import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet, FlatList } from 'react-native';
import { COLORS, FONTS } from '../constants/theme';
import { Transaction, CATEGORIES } from '../types';
import { formatRupiah, formatDate } from '../utils/helpers';
interface TransactionListProps {
transactions: Transaction[];
onDelete: (id: string) => void;
}
export const TransactionList: React.FC<TransactionListProps> = ({
transactions,
onDelete,
}) => {
const getCategoryLabel = (categoryId: string) => {
const category = CATEGORIES.find((c) => c.id === categoryId);
return category ? category.label : categoryId;
};
const renderItem = ({ item }: { item: Transaction }) => {
const isExpense = item.type === 'expense';
return (
<View style={styles.item}>
<View style={styles.info}>
<Text style={styles.description}>{item.description}</Text>
<Text style={styles.category}>{getCategoryLabel(item.category)}</Text>
<Text style={styles.date}>{formatDate(item.date)}</Text>
</View>
<View style={styles.amountContainer}>
<Text style={[styles.amount, isExpense ? styles.expense : styles.income]}>
{isExpense ? '-' : '+'}{formatRupiah(item.amount)}
</Text>
<TouchableOpacity
style={styles.deleteButton}
onPress={() => onDelete(item.id)}
>
<Text style={styles.deleteText}>Hapus</Text>
</TouchableOpacity>
</View>
</View>
);
};
if (transactions.length === 0) {
return (
<View style={styles.empty}>
<Text style={styles.emptyText}>Belum ada transaksi</Text>
<Text style={styles.emptySubtext}>
Tambahkan transaksi pertama Anda
</Text>
</View>
);
}
return (
<View style={styles.container}>
<Text style={styles.title}>Riwayat Transaksi</Text>
<FlatList
data={transactions}
keyExtractor={(item) => item.id}
renderItem={renderItem}
scrollEnabled={false}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
margin: 16,
marginTop: 0,
},
title: {
fontSize: FONTS.regular,
fontWeight: 'bold',
color: COLORS.text,
marginBottom: 12,
},
item: {
backgroundColor: COLORS.card,
padding: 16,
borderRadius: 12,
marginBottom: 8,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.05,
shadowRadius: 2,
elevation: 1,
},
info: {
flex: 1,
},
description: {
fontSize: FONTS.regular,
fontWeight: '600',
color: COLORS.text,
},
category: {
fontSize: FONTS.small,
color: COLORS.textSecondary,
marginTop: 2,
},
date: {
fontSize: FONTS.small,
color: COLORS.textSecondary,
marginTop: 2,
},
amountContainer: {
alignItems: 'flex-end',
},
amount: {
fontSize: FONTS.regular,
fontWeight: 'bold',
},
income: {
color: COLORS.income,
},
expense: {
color: COLORS.expense,
},
deleteButton: {
marginTop: 4,
paddingHorizontal: 8,
paddingVertical: 4,
},
deleteText: {
fontSize: FONTS.small,
color: COLORS.expense,
},
empty: {
margin: 16,
padding: 40,
alignItems: 'center',
},
emptyText: {
fontSize: FONTS.regular,
color: COLORS.textSecondary,
},
emptySubtext: {
fontSize: FONTS.small,
color: COLORS.textSecondary,
marginTop: 8,
},
});