From 31659a215793d15b3a2f75da2dbfa4667cc5fb20 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Wed, 25 Jun 2025 00:39:07 +0000 Subject: [PATCH] feat: Implement category and transaction card styling Styled the category page and transaction summary cards to match the provided print. --- .../transacoes/TransactionSummaryCards.tsx | 93 +++--- src/pages/Categorias.tsx | 307 ++++++++---------- 2 files changed, 186 insertions(+), 214 deletions(-) diff --git a/src/components/transacoes/TransactionSummaryCards.tsx b/src/components/transacoes/TransactionSummaryCards.tsx index d39ea72..7a1e7d6 100644 --- a/src/components/transacoes/TransactionSummaryCards.tsx +++ b/src/components/transacoes/TransactionSummaryCards.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { ArrowUp, ArrowDown, CreditCard } from 'lucide-react'; -import { SimpleCard } from '@/components/ui/simple-card'; interface TransactionSummaryCardsProps { totalReceitas: number; @@ -16,66 +15,58 @@ export const TransactionSummaryCards = ({ totalCartoes, formatCurrency }: TransactionSummaryCardsProps) => { - // Calculate the grand total of all expenses const totalGeral = totalDespesas + totalCartoes; return ( -
- -
-
- - Ganhos do mês +
+ {/* Card Ganhos do mês */} +
+
+
+
+

Ganhos do mês

-
-

- {formatCurrency(totalReceitas)} +

+ {formatCurrency(totalReceitas)} +

+
+ + {/* Card Gastos do mês */} +
+
+
+ +
+

Gastos do mês

+
+

+ {formatCurrency(totalDespesas)} +

+
+ + {/* Card Gastos em cartões */} +
+
+
+ +
+

Gastos em cartões

+
+
+

+ {formatCurrency(totalCartoes)}

-
- - - -
-
- - Gastos do mês -
-
-
-
- Despesas: - - {formatCurrency(totalDespesas)} - -
- {totalCartoes > 0 && ( -
- Cartões: - - {formatCurrency(totalCartoes)} +
+
+ Total geral: + + {formatCurrency(totalGeral)}
- )} -
- - - -
-
- - Total geral
-
-

- {formatCurrency(totalGeral)} -

-

- Despesas + Cartões -

-
-
+
); }; diff --git a/src/pages/Categorias.tsx b/src/pages/Categorias.tsx index 6edf987..7f80fcb 100644 --- a/src/pages/Categorias.tsx +++ b/src/pages/Categorias.tsx @@ -2,49 +2,44 @@ import React, { useState, useEffect } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Badge } from "@/components/ui/badge"; -import { Plus, Search, Edit, Trash2 } from 'lucide-react'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useToast } from "@/hooks/use-toast"; -import { SimpleCard } from "@/components/ui/simple-card"; +import { getCategorySummary } from '@/services/transacao'; +import { CategorySummary } from '@/types/financialTypes'; -interface Categoria { - id: string; +interface CategoryCard { nome: string; - tipo: 'receita' | 'despesa'; + valor: number; + percentual: number; cor: string; - total?: number; } const Categorias = () => { - const [categorias, setCategorias] = useState([]); - const [searchTerm, setSearchTerm] = useState(''); + const [categories, setCategories] = useState([]); + const [filtro, setFiltro] = useState<'despesa' | 'receita'>('despesa'); const [isLoading, setIsLoading] = useState(true); const { toast } = useToast(); - // Mock data - replace with actual API calls - useEffect(() => { - const mockCategorias: Categoria[] = [ - { id: '1', nome: 'Alimentação', tipo: 'despesa', cor: '#ef4444', total: 850.50 }, - { id: '2', nome: 'Transporte', tipo: 'despesa', cor: '#f97316', total: 420.30 }, - { id: '3', nome: 'Lazer', tipo: 'despesa', cor: '#eab308', total: 300.00 }, - { id: '4', nome: 'Salário', tipo: 'receita', cor: '#22c55e', total: 5000.00 }, - { id: '5', nome: 'Freelance', tipo: 'receita', cor: '#10b981', total: 1200.00 }, - { id: '6', nome: 'Educação', tipo: 'despesa', cor: '#3b82f6', total: 450.00 }, - ]; - - setTimeout(() => { - setCategorias(mockCategorias); + const loadCategories = async () => { + try { + setIsLoading(true); + const data = await getCategorySummary(filtro); + setCategories(data); + } catch (error) { + console.error("Erro ao carregar categorias:", error); + toast({ + title: "Erro ao carregar categorias", + description: "Não foi possível obter os dados das categorias", + variant: "destructive" + }); + } finally { setIsLoading(false); - }, 1000); - }, []); + } + }; - const filteredCategorias = categorias.filter(categoria => - categoria.nome.toLowerCase().includes(searchTerm.toLowerCase()) - ); - - const receitas = filteredCategorias.filter(cat => cat.tipo === 'receita'); - const despesas = filteredCategorias.filter(cat => cat.tipo === 'despesa'); + useEffect(() => { + loadCategories(); + }, [filtro]); const formatCurrency = (value: number) => { return new Intl.NumberFormat('pt-BR', { @@ -53,29 +48,22 @@ const Categorias = () => { }).format(value); }; - const handleEdit = (categoria: Categoria) => { - toast({ - title: "Editar categoria", - description: `Função de edição para ${categoria.nome} será implementada`, - }); + const formatPercentage = (value: number) => { + return `${(value * 100).toFixed(1)}%`; }; - const handleDelete = (categoria: Categoria) => { - toast({ - title: "Excluir categoria", - description: `Função de exclusão para ${categoria.nome} será implementada`, - }); - }; + const totalGeral = categories.reduce((sum, cat) => sum + cat.valor, 0); if (isLoading) { return (

Categorias

- +
{[1, 2, 3, 4, 5, 6].map((i) => ( @@ -98,125 +86,118 @@ const Categorias = () => {

Categorias

- -
- - -
- - setSearchTerm(e.target.value)} - className="pl-10" - /> +
+ Filtrar por: +
- - -
- -
- {receitas.length === 0 ? ( -

- Nenhuma categoria de receita encontrada -

- ) : ( - receitas.map((categoria) => ( -
-
-
-
-

{categoria.nome}

-

- {categoria.total ? formatCurrency(categoria.total) : 'R$ 0,00'} -

-
-
-
- - {categoria.tipo} - - - -
-
- )) - )} -
- - - -
- {despesas.length === 0 ? ( -

- Nenhuma categoria de despesa encontrada -

- ) : ( - despesas.map((categoria) => ( -
-
-
-
-

{categoria.nome}

-

- {categoria.total ? formatCurrency(categoria.total) : 'R$ 0,00'} -

-
-
-
- - {categoria.tipo} - - - -
-
- )) - )} -
-
+ + {/* Cards das Categorias */} +
+ {categories.map((categoria, index) => ( + + +
+
+

{categoria.categoria}

+
+
+

+ {formatCurrency(categoria.valor)} +

+
+
+
+
+

+ {formatPercentage(categoria.percentage)} do total +

+
+
+ + + ))} +
+ + {/* Resumo de Categorias */} + {categories.length > 0 && ( + + + + Resumo de Categorias ({filtro === 'despesa' ? 'Despesas' : 'Receitas'}) + + + +
+ + + + + + + + + + {categories.map((categoria) => ( + + + + + + ))} + + + + + + +
CategoriaValorPercentual
+
+
+ {categoria.categoria} +
+
+ {formatCurrency(categoria.valor)} + + {formatPercentage(categoria.percentage)} +
Total{formatCurrency(totalGeral)}100%
+
+
+
+ )} + + {categories.length === 0 && !isLoading && ( + + +

+ Nenhuma categoria encontrada para {filtro === 'despesa' ? 'despesas' : 'receitas'}. +

+

+ Adicione algumas transações para ver as categorias aqui. +

+
+
+ )}
); };