diff --git a/src/components/dashboard/MetaProgressCard.tsx b/src/components/dashboard/MetaProgressCard.tsx index 2f7428d..34e2264 100644 --- a/src/components/dashboard/MetaProgressCard.tsx +++ b/src/components/dashboard/MetaProgressCard.tsx @@ -1,90 +1,83 @@ import { format } from 'date-fns'; import { ptBR } from 'date-fns/locale'; -import { Trophy, Flag, FlagOff } from 'lucide-react'; -import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; +import { Card, CardContent, CardFooter } from '@/components/ui/card'; import { Progress } from '@/components/ui/progress'; +import { Button } from '@/components/ui/button'; import { ResultadoMeta } from '@/types/financialTypes'; +import { Check, Edit2, Trash2 } from 'lucide-react'; interface MetaProgressCardProps { meta: ResultadoMeta; - onEditClick?: () => void; + onEditClick: () => void; + onDeleteClick: () => void; } -export function MetaProgressCard({ meta, onEditClick }: MetaProgressCardProps) { - const formatCurrency = (value: number) => { - return new Intl.NumberFormat('pt-BR', { - style: 'currency', - currency: 'BRL', - }).format(value); - }; - - const getMesNome = (mes: number) => { - const date = new Date(2000, mes - 1, 1); - return format(date, 'MMMM', { locale: ptBR }); - }; - - const getStatusIcon = () => { - if (meta.meta_batida) { - return ; - } else { - return ; - } - }; - - const getProgressColor = () => { - if (meta.meta_batida) { - return 'bg-green-500'; - } else if (meta.percentual_atingido >= 75) { - return 'bg-yellow-500'; - } else { - return 'bg-red-500'; - } - }; +export function MetaProgressCard({ meta, onEditClick, onDeleteClick }: MetaProgressCardProps) { + // Format the month name in Portuguese + const mesFormatado = format(new Date(meta.ano, meta.mes - 1, 1), 'MMMM', { locale: ptBR }); + const mesCapitalizado = mesFormatado.charAt(0).toUpperCase() + mesFormatado.slice(1); return ( - - - {getMesNome(meta.mes)} {meta.ano} -
- {getStatusIcon()} + +
+
+

{mesCapitalizado}

+

{meta.ano}

+
+
+ +
- - - - -
- Meta: {formatCurrency(meta.valor_meta)} - Economia: {formatCurrency(meta.economia_real)}
-
-
- +
+
+ Meta de Economia + R$ {meta.valor_meta.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
-
- 0% - {meta.percentual_atingido.toFixed(0)}% atingido - 100% +
+ Economia Real + R$ {meta.economia_real.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}
+ +
+
+ Progresso + + {meta.percentual_atingido.toFixed(0)}% + +
+ +
- {onEditClick && ( - - - - )} + +
+ + {meta.meta_batida ? 'Meta atingida!' : 'Meta em andamento'} + + {meta.meta_batida && } +
+
); } diff --git a/src/pages/Metas.tsx b/src/pages/Metas.tsx index b033dc1..922c28d 100644 --- a/src/pages/Metas.tsx +++ b/src/pages/Metas.tsx @@ -9,7 +9,7 @@ import { Button } from '@/components/ui/button'; import { Card } from '@/components/ui/card'; import { ResultadoMeta } from '@/types/financialTypes'; import { useToast } from '@/components/ui/use-toast'; -import { calcularResultadosMetas, getMeta } from '@/services/metasService'; +import { calcularResultadosMetas, getMeta, deletarMeta } from '@/services/metasService'; import { PlusCircle } from 'lucide-react'; import { Dialog, @@ -18,6 +18,16 @@ import { DialogHeader, DialogTitle, } from '@/components/ui/dialog'; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from '@/components/ui/alert-dialog'; const MetasPage = () => { const { toast } = useToast(); @@ -25,8 +35,11 @@ const MetasPage = () => { const [resultados, setResultados] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isDialogOpen, setIsDialogOpen] = useState(false); - const [metaParaEditar, setMetaParaEditar] = useState<{ mes: number, ano: number } | null>(null); + const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); + const [metaParaEditar, setMetaParaEditar] = useState<{ mes: number, ano: number, id?: string } | null>(null); + const [metaParaDeletar, setMetaParaDeletar] = useState<{ mes: number, ano: number, id: string } | null>(null); const [valorMetaAtual, setValorMetaAtual] = useState(0); + const [isDeletingMeta, setIsDeletingMeta] = useState(false); useEffect(() => { // Obter userId armazenado no localStorage @@ -72,7 +85,7 @@ const MetasPage = () => { const meta = await getMeta(userId, mes, ano); if (meta) { setValorMetaAtual(meta.valor_meta); - setMetaParaEditar({ mes, ano }); + setMetaParaEditar({ mes, ano, id: meta.id }); setIsDialogOpen(true); } } catch (error) { @@ -80,6 +93,39 @@ const MetasPage = () => { } }; + const handleDeletarMeta = (mes: number, ano: number, id: string) => { + setMetaParaDeletar({ mes, ano, id }); + setIsDeleteDialogOpen(true); + }; + + const confirmarDeletarMeta = async () => { + if (!metaParaDeletar?.id) return; + + try { + setIsDeletingMeta(true); + await deletarMeta(metaParaDeletar.id); + + // Atualizar lista de metas após deleção + await loadData(userId); + + toast({ + title: 'Meta excluída', + description: `A meta de ${format(new Date(metaParaDeletar.ano, metaParaDeletar.mes - 1, 1), 'MMMM', { locale: ptBR })} ${metaParaDeletar.ano} foi excluída com sucesso.`, + }); + } catch (error) { + console.error('Erro ao deletar meta:', error); + toast({ + title: 'Erro ao deletar meta', + description: 'Não foi possível excluir a meta', + variant: 'destructive', + }); + } finally { + setIsDeletingMeta(false); + setIsDeleteDialogOpen(false); + setMetaParaDeletar(null); + } + }; + const handleNovaMeta = () => { setMetaParaEditar(null); setValorMetaAtual(0); @@ -161,6 +207,20 @@ const MetasPage = () => { key={`${meta.ano}-${meta.mes}`} meta={meta} onEditClick={() => handleEditarMeta(meta.mes, meta.ano)} + onDeleteClick={() => { + // Aqui precisamos buscar o ID primeiro pois resultadoMeta não tem o ID + // Vamos usar o metaParaEditar.id que já foi carregado se o usuário clicou em editar antes + if (metaParaEditar && metaParaEditar.mes === meta.mes && metaParaEditar.ano === meta.ano && metaParaEditar.id) { + handleDeletarMeta(meta.mes, meta.ano, metaParaEditar.id); + } else { + // Buscar o ID antes de deletar + getMeta(userId, meta.mes, meta.ano).then(metaCompleta => { + if (metaCompleta && metaCompleta.id) { + handleDeletarMeta(meta.mes, meta.ano, metaCompleta.id); + } + }); + } + }} /> ))}
@@ -191,6 +251,34 @@ const MetasPage = () => { /> + + + + + + Confirmar exclusão + + + {metaParaDeletar && ( + `Tem certeza que deseja excluir a meta de ${format(new Date(metaParaDeletar.ano, metaParaDeletar.mes - 1, 1), 'MMMM', { locale: ptBR })} de ${metaParaDeletar.ano}? Esta ação não pode ser desfeita.` + )} + + + + Cancelar + + {isDeletingMeta ? 'Deletando...' : 'Deletar Meta'} + + + +
);