import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { PieChart } from 'react-native-gifted-charts'; import { Colors, Radius, Spacing, Typography } from '@/constants/theme'; import type { DashboardExpenseItem } from '@/types'; import { Card, SectionLabel } from './primitives'; interface ExpensesChartProps { recurring: DashboardExpenseItem[]; oneTime: DashboardExpenseItem[]; } const CATEGORY_COLORS: Record = { moradia: '#4C6EF5', alimentação: '#FA5252', transporte: '#FAB005', saúde: '#12B886', educação: '#BE4BDB', lazer: '#FF922B', serviços: '#228BE6', outros: '#868E96', }; const CATEGORY_LABELS: Record = { moradia: 'Moradia', alimentação: 'Alimentação', transporte: 'Transporte', saúde: 'Saúde', educação: 'Educação', lazer: 'Lazer', serviços: 'Serviços', outros: 'Outros', }; export function ExpensesChart({ recurring, oneTime }: ExpensesChartProps) { const categoryTotals: Record = {}; const allExpenses = [ ...recurring.filter(e => e.is_active && e.type === 'expense'), ...oneTime.filter(e => e.type === 'expense') ]; if (allExpenses.length === 0) { return ( Não há despesas para analisar neste mês. ); } let totalExpenses = 0; allExpenses.forEach(e => { if (!categoryTotals[e.category]) { categoryTotals[e.category] = 0; } categoryTotals[e.category] += e.amount; totalExpenses += e.amount; }); const pieData = Object.keys(categoryTotals) .map(category => ({ value: categoryTotals[category], color: CATEGORY_COLORS[category] || CATEGORY_COLORS.outros, label: CATEGORY_LABELS[category] || 'Outros', percentage: ((categoryTotals[category] / totalExpenses) * 100).toFixed(0) + '%', })) .sort((a, b) => b.value - a.value); return ( { return ( {totalExpenses.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL', minimumFractionDigits: 0, maximumFractionDigits: 0, })} Total ); }} /> {pieData.map((item, index) => ( {item.label} {item.value.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL', })} ({item.percentage}) ))} ); } const styles = StyleSheet.create({ card: { gap: Spacing.md, }, emptyContainer: { paddingVertical: Spacing.xl, alignItems: 'center', justifyContent: 'center', }, emptyText: { ...Typography.body, color: Colors.textMuted, }, chartRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, chartWrapper: { alignItems: 'center', justifyContent: 'center', }, centerLabel: { alignItems: 'center', justifyContent: 'center', }, centerLabelValue: { ...Typography.body, fontFamily: 'DMSans_700Bold', color: Colors.textPrimary, fontSize: 14, }, centerLabelText: { ...Typography.caption, color: Colors.textSecondary, fontSize: 10, }, legendContainer: { flex: 1, marginLeft: Spacing.lg, gap: Spacing.sm, }, legendItem: { flexDirection: 'row', alignItems: 'center', }, legendDot: { width: 10, height: 10, borderRadius: 5, marginRight: Spacing.xs, }, legendTextWrapper: { flex: 1, }, legendLabel: { ...Typography.caption, color: Colors.textSecondary, }, legendValue: { ...Typography.caption, color: Colors.textPrimary, fontFamily: 'DMSans_600SemiBold', }, });