From 13c4fb0760051885aa21879c538e47b1195b5b9a Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 18:56:23 +0000 Subject: [PATCH] Fix: Implement card deletion and display card details Added card deletion functionality. Improved card details display to show the month and the total expenses for each card. Fixed dashboard card layout issues on smaller screens. Separated expenses and credit card expenses in the dashboard summary. --- src/components/credito/CartaoCreditoList.tsx | 164 ++++++++++++++---- src/components/credito/CartaoListView.tsx | 12 +- .../dashboard/DashboardSummaryCards.tsx | 74 ++++---- .../transacoes/TransactionSummaryCards.tsx | 38 ++-- src/pages/CartoesCredito.tsx | 10 ++ src/services/cartao/cartoesService.ts | 73 +++++++- src/services/cartaoCreditoService.ts | 3 +- 7 files changed, 285 insertions(+), 89 deletions(-) diff --git a/src/components/credito/CartaoCreditoList.tsx b/src/components/credito/CartaoCreditoList.tsx index d5504e2..67eba6c 100644 --- a/src/components/credito/CartaoCreditoList.tsx +++ b/src/components/credito/CartaoCreditoList.tsx @@ -2,17 +2,33 @@ import { useState } from 'react'; import { CartaoCredito } from '@/types/cartaoTypes'; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; import { useToast } from '@/components/ui/use-toast'; -import { CreditCard } from 'lucide-react'; +import { CreditCard, Trash2 } from 'lucide-react'; +import { excluirCartao } from '@/services/cartaoCreditoService'; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog"; interface CartaoCreditoListProps { cartoes: CartaoCredito[]; isLoading: boolean; onCartaoClick: (cartao: CartaoCredito) => void; + onCartaoDeleted?: () => void; } -export function CartaoCreditoList({ cartoes, isLoading, onCartaoClick }: CartaoCreditoListProps) { +export function CartaoCreditoList({ cartoes, isLoading, onCartaoClick, onCartaoDeleted }: CartaoCreditoListProps) { const { toast } = useToast(); + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); + const [cartaoToDelete, setCartaoToDelete] = useState(null); + const [isDeleting, setIsDeleting] = useState(false); const formatCurrency = (value: number = 0) => { return new Intl.NumberFormat('pt-BR', { @@ -21,6 +37,53 @@ export function CartaoCreditoList({ cartoes, isLoading, onCartaoClick }: CartaoC }).format(value); }; + const getCurrentMonthYear = () => { + const now = new Date(); + const month = now.toLocaleDateString('pt-BR', { month: 'long' }); + const year = now.getFullYear(); + return `${month.charAt(0).toUpperCase() + month.slice(1)} ${year}`; + }; + + const handleDeleteClick = (e: React.MouseEvent, cartao: CartaoCredito) => { + e.stopPropagation(); + setCartaoToDelete(cartao); + setDeleteDialogOpen(true); + }; + + const handleConfirmDelete = async () => { + if (!cartaoToDelete) return; + + setIsDeleting(true); + try { + const success = await excluirCartao(cartaoToDelete.id); + + if (success) { + toast({ + title: "Cartão excluído", + description: "O cartão e todas as suas despesas foram removidos com sucesso.", + }); + onCartaoDeleted?.(); + } else { + toast({ + title: "Erro ao excluir cartão", + description: "Não foi possível excluir o cartão. Tente novamente.", + variant: "destructive" + }); + } + } catch (error) { + console.error('Erro ao excluir cartão:', error); + toast({ + title: "Erro ao excluir cartão", + description: "Ocorreu um erro inesperado. Tente novamente.", + variant: "destructive" + }); + } finally { + setIsDeleting(false); + setDeleteDialogOpen(false); + setCartaoToDelete(null); + } + }; + if (isLoading) { return (
@@ -48,36 +111,71 @@ export function CartaoCreditoList({ cartoes, isLoading, onCartaoClick }: CartaoC } return ( -
- {cartoes.map((cartao) => { - console.log(`Cartão na lista: ${cartao.nome}, total: ${cartao.total_despesas}`); - return ( - onCartaoClick(cartao)} - > - - - - {cartao.nome} - -
- {cartao.banco &&
{cartao.banco}
} - {cartao.bandeira &&
{cartao.bandeira}
} -
-
- -

- {formatCurrency(cartao.total_despesas)} -

-

- Total em despesas -

-
-
- ); - })} -
+ <> +
+ {cartoes.map((cartao) => { + console.log(`Cartão na lista: ${cartao.nome}, total: ${cartao.total_despesas}`); + return ( + onCartaoClick(cartao)} + > + +
+ + + {cartao.nome} + + +
+
+ {cartao.banco &&
{cartao.banco}
} + {cartao.bandeira &&
{cartao.bandeira}
} +
+
+ +

+ {formatCurrency(cartao.total_despesas)} +

+

+ Fatura de {getCurrentMonthYear()} +

+
+
+ ); + })} +
+ + + + + Confirmar exclusão + + Tem certeza que deseja excluir o cartão "{cartaoToDelete?.nome}"? + Esta ação removerá permanentemente o cartão e todas as suas despesas associadas. + Esta ação não pode ser desfeita. + + + + Cancelar + + {isDeleting ? 'Excluindo...' : 'Excluir'} + + + + + ); } diff --git a/src/components/credito/CartaoListView.tsx b/src/components/credito/CartaoListView.tsx index 40dc998..3be7824 100644 --- a/src/components/credito/CartaoListView.tsx +++ b/src/components/credito/CartaoListView.tsx @@ -1,19 +1,21 @@ -import { CartaoCredito } from "@/types/cartaoTypes"; -import { CartaoCreditoList } from "./CartaoCreditoList"; +import { CartaoCreditoList } from './CartaoCreditoList'; +import { CartaoCredito } from '@/types/cartaoTypes'; interface CartaoListViewProps { cartoes: CartaoCredito[]; isLoading: boolean; onCartaoClick: (cartao: CartaoCredito) => void; + onCartaoDeleted?: () => void; } -export function CartaoListView({ cartoes, isLoading, onCartaoClick }: CartaoListViewProps) { +export function CartaoListView({ cartoes, isLoading, onCartaoClick, onCartaoDeleted }: CartaoListViewProps) { return ( ); } diff --git a/src/components/dashboard/DashboardSummaryCards.tsx b/src/components/dashboard/DashboardSummaryCards.tsx index fcfdfc4..a9363d6 100644 --- a/src/components/dashboard/DashboardSummaryCards.tsx +++ b/src/components/dashboard/DashboardSummaryCards.tsx @@ -14,28 +14,27 @@ const DashboardSummaryCards: React.FC = ({ resumo, f const { navigateToTransactions } = useNavigateWithFilter(); const saldo = resumo ? resumo.totalReceitas - resumo.totalDespesas - (resumo.totalCartoes || 0) : 0; - const totalDespesasGeral = resumo ? resumo.totalDespesas + (resumo.totalCartoes || 0) : 0; return ( -
+
{/* Card Receitas - Clicável */} navigateToTransactions('receita')} >
- -
-
- + +
+
+
-
+
+5%
-
-

Receitas

-

+

+

Receitas

+

{resumo ? formatCurrency(resumo.totalReceitas) : 'R$ 0,00'}

Clique para ver detalhes

@@ -49,22 +48,27 @@ const DashboardSummaryCards: React.FC = ({ resumo, f onClick={() => navigateToTransactions('despesa')} >
- -
-
- + +
+
+
-
+
-2%
-
-

Despesas

-

- {resumo ? formatCurrency(totalDespesasGeral) : 'R$ 0,00'} +

+

Despesas

+

+ {resumo ? formatCurrency(resumo.totalDespesas) : 'R$ 0,00'}

{resumo && resumo.totalCartoes > 0 && ( -

Cartões: {formatCurrency(resumo.totalCartoes)}

+
+

+ Cartões: + {formatCurrency(resumo.totalCartoes)} +

+
)}

Clique para ver detalhes

@@ -74,15 +78,15 @@ const DashboardSummaryCards: React.FC = ({ resumo, f {/* Card Saldo */}
- -
-
- + +
+
+
-
-

Saldo

-

+

Saldo

+

= 0 ? 'text-blue-600' : 'text-red-600' }`}> {resumo ? formatCurrency(saldo) : 'R$ 0,00'} @@ -94,18 +98,18 @@ const DashboardSummaryCards: React.FC = ({ resumo, f {/* Card Economia */}

- -
-
- + +
+
+
-
-

Economia

-

+

+

Economia

+

-22.2%

-

{resumo ? formatCurrency(Math.abs(saldo)) : 'R$ 0,00'}

+

{resumo ? formatCurrency(Math.abs(saldo)) : 'R$ 0,00'}

diff --git a/src/components/transacoes/TransactionSummaryCards.tsx b/src/components/transacoes/TransactionSummaryCards.tsx index 2506fea..d39ea72 100644 --- a/src/components/transacoes/TransactionSummaryCards.tsx +++ b/src/components/transacoes/TransactionSummaryCards.tsx @@ -20,7 +20,7 @@ export const TransactionSummaryCards = ({ const totalGeral = totalDespesas + totalCartoes; return ( -
+
@@ -29,7 +29,7 @@ export const TransactionSummaryCards = ({
-

+

{formatCurrency(totalReceitas)}

@@ -42,10 +42,21 @@ export const TransactionSummaryCards = ({ Gastos do mês
-
-

- {formatCurrency(totalDespesas)} -

+
+
+ Despesas: + + {formatCurrency(totalDespesas)} + +
+ {totalCartoes > 0 && ( +
+ Cartões: + + {formatCurrency(totalCartoes)} + +
+ )}
@@ -53,17 +64,16 @@ export const TransactionSummaryCards = ({
- Gastos em cartões + Total geral
-
-

- {formatCurrency(totalCartoes)} +

+

+ {formatCurrency(totalGeral)} +

+

+ Despesas + Cartões

-
- Total geral: - {formatCurrency(totalGeral)} -
diff --git a/src/pages/CartoesCredito.tsx b/src/pages/CartoesCredito.tsx index 2340153..93cc874 100644 --- a/src/pages/CartoesCredito.tsx +++ b/src/pages/CartoesCredito.tsx @@ -86,6 +86,15 @@ const CartoesCreditoPage = () => { }); }; + const handleCartaoDeleted = () => { + loadCartoes(); + if (detalheCartaoAberto) { + setDetalheCartaoAberto(false); + setCartaoSelecionado(null); + setDespesas([]); + } + }; + const handleCartaoClick = async (cartao: CartaoCredito) => { const totalDespesas = await getTotalDespesasCartao(cartao.id); const updatedCartao = { ...cartao, total_despesas: totalDespesas }; @@ -120,6 +129,7 @@ const CartoesCreditoPage = () => { cartoes={cartoes} isLoading={isLoading} onCartaoClick={handleCartaoClick} + onCartaoDeleted={handleCartaoDeleted} /> ) : cartaoSelecionado && ( { + const userEmail = localStorage.getItem('userEmail'); + + if (!userEmail) { + console.error('Email do usuário não encontrado no localStorage'); + return false; + } + + const normalizedEmail = userEmail.trim().toLowerCase(); + + try { + // First, get the card name to delete associated expenses + const { data: cardData, error: cardError } = await supabase + .from('cartoes_credito') + .select('nome') + .eq('id', cartaoId) + .eq('login', normalizedEmail) + .single(); + + if (cardError) { + console.error('Erro ao obter dados do cartão:', cardError); + return false; + } + + // Delete all expenses associated with this card + const { error: expensesError } = await supabase + .from('despesas_cartao') + .delete() + .eq('nome', cardData.nome) + .eq('login', normalizedEmail); + + if (expensesError) { + console.error('Erro ao excluir despesas do cartão:', expensesError); + return false; + } + + // Delete all invoices associated with this card + const { error: invoicesError } = await supabase + .from('faturas_cartao') + .delete() + .eq('cartao_id', cartaoId) + .eq('login', normalizedEmail); + + if (invoicesError) { + console.error('Erro ao excluir faturas do cartão:', invoicesError); + // Continue with card deletion even if invoices fail + } + + // Finally, delete the card itself + const { error: cardDeleteError } = await supabase + .from('cartoes_credito') + .delete() + .eq('id', cartaoId) + .eq('login', normalizedEmail); + + if (cardDeleteError) { + console.error('Erro ao excluir cartão:', cardDeleteError); + return false; + } + + return true; + } catch (error) { + console.error('Erro ao excluir cartão:', error); + return false; + } +} diff --git a/src/services/cartaoCreditoService.ts b/src/services/cartaoCreditoService.ts index 5e1942e..8e4952c 100644 --- a/src/services/cartaoCreditoService.ts +++ b/src/services/cartaoCreditoService.ts @@ -7,7 +7,8 @@ export { getCartoes, criarCartao, - getCartao + getCartao, + excluirCartao } from './cartao/cartoesService'; // Re-export all functions from despesas services