import React, { useCallback, useState } from 'react'; import { Alert, ScrollView, StyleSheet, Text, TouchableOpacity, View, } from 'react-native'; import Animated, { FadeInDown, LinearTransition } from 'react-native-reanimated'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import * as Haptics from 'expo-haptics'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Card, Divider, SectionLabel } from '@/components/ui/primitives'; import { OneTimeExpenseRow } from '@/components/expense-row'; import { Colors, Radius, Spacing, Typography } from '@/constants/theme'; import type { Category, OneTimeExpense } from '@/types'; import { createOneTimeExpense, updateOneTimeExpense, deleteOneTimeExpense, getOneTimeExpenses, } from '@/services/api'; import { useAuth } from '@/contexts/AuthContext'; import { ActionModal } from '@/components/ui/action-modal'; import { OptionsModal } from '@/components/ui/options-modal'; import { useFocusEffect } from 'expo-router'; import { useIsFocused } from "expo-router/react-navigation"; const CATEGORIES: { value: Category; emoji: string; label: string }[] = [ { value: 'alimentação', emoji: '🍽️', label: 'Alimentação' }, { value: 'lazer', emoji: '🎬', label: 'Lazer' }, { value: 'transporte', emoji: '🚗', label: 'Transporte' }, { value: 'saúde', emoji: '💊', label: 'Saúde' }, { value: 'moradia', emoji: '🏠', label: 'Moradia' }, { value: 'educação', emoji: '📚', label: 'Educação' }, { value: 'serviços', emoji: '⚙️', label: 'Serviços' }, { value: 'outros', emoji: '📦', label: 'Outros' }, ]; export default function OneTimeExpensesScreen() { const insets = useSafeAreaInsets(); const { user } = useAuth(); const [expenses, setExpenses] = useState([]); const [showForm, setShowForm] = useState(false); const [loading, setLoading] = useState(true); const [name, setName] = useState(''); const [amount, setAmount] = useState(''); const [selectedCategory, setSelectedCategory] = useState('outros'); const [expenseType, setExpenseType] = useState<'expense' | 'income'>('expense'); const [notes, setNotes] = useState(''); const [isSubmitting, setIsSubmitting] = useState(false); const [expenseToDelete, setExpenseToDelete] = useState(null); const [selectedExpense, setSelectedExpense] = useState(null); const [editingExpenseId, setEditingExpenseId] = useState(null); const isFocused = useIsFocused(); const fetchExpenses = useCallback(async () => { if (!user) return; try { setLoading(true); const data = await getOneTimeExpenses(user.id); setExpenses(data); } catch (err) { Alert.alert('Erro', 'Não foi possível carregar os gastos do mês.'); } finally { setLoading(false); } }, [user]); useFocusEffect( useCallback(() => { fetchExpenses(); }, [fetchExpenses]) ); const monthTotal = expenses.reduce((sum, e) => { return sum + (e.type === 'income' ? -e.amount : e.amount); }, 0); const isTotalIncome = monthTotal < 0; const absTotal = Math.abs(monthTotal); const formattedTotal = absTotal.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL', }); async function handleAdd() { const amountNum = parseFloat(amount.replace(',', '.')); if (!name.trim() || isNaN(amountNum) || amountNum <= 0) { Alert.alert('Dados inválidos', 'Preencha o nome e um valor válido.'); return; } try { if (!user) return; setIsSubmitting(true); if (editingExpenseId) { const updated = await updateOneTimeExpense(user.id, editingExpenseId, { name: name.trim(), amount: amountNum, category: selectedCategory, type: expenseType, notes: notes.trim() || null, }); setExpenses((prev) => prev.map((e) => e.id === editingExpenseId ? updated : e)); Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); } else { const today = new Date().toISOString().split('T')[0]; const newExpense = await createOneTimeExpense(user.id, { name: name.trim(), amount: amountNum, category: selectedCategory, type: expenseType, expense_date: today, notes: notes.trim() || null, }); setExpenses((prev) => [...prev, newExpense]); Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); } setName(''); setAmount(''); setNotes(''); setExpenseType('expense'); setShowForm(false); setEditingExpenseId(null); } catch (err) { Alert.alert('Erro', 'Não foi possível salvar o lançamento.'); } finally { setIsSubmitting(false); } } function handleDelete(id: number) { setExpenseToDelete(id); setSelectedExpense(null); } function handleEdit(expense: OneTimeExpense) { setName(expense.name); setAmount(expense.amount.toString()); setSelectedCategory(expense.category); setExpenseType(expense.type); setNotes(expense.notes || ''); setEditingExpenseId(expense.id); setSelectedExpense(null); setShowForm(true); } async function confirmDelete() { if (!user || expenseToDelete === null) return; Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); try { await deleteOneTimeExpense(user.id, expenseToDelete); setExpenses((prev) => prev.filter((e) => e.id !== expenseToDelete)); } catch (err) { Alert.alert('Erro', 'Não foi possível remover o lançamento.'); } finally { setExpenseToDelete(null); } } return ( {isFocused && ( Lançamentos Saldo líquido:{' '} {isTotalIncome ? '+ ' : (monthTotal > 0 ? '- ' : '')}{formattedTotal} { if (showForm) { setEditingExpenseId(null); setName(''); setAmount(''); setNotes(''); } setShowForm((v) => !v); }} accessibilityLabel="Adicionar lançamento" accessibilityRole="button" > {showForm ? '✕' : '+'} {showForm && ( setExpenseType('expense')} > Despesa setExpenseType('income')} > Receita Categoria {CATEGORIES.map((cat) => ( setSelectedCategory(cat.value)} accessibilityLabel={cat.label} accessibilityRole="radio" > {cat.emoji} {cat.label} ))}