diff --git a/src/components/filters/MonthFilter.tsx b/src/components/filters/MonthFilter.tsx
new file mode 100644
index 0000000..5e29b06
--- /dev/null
+++ b/src/components/filters/MonthFilter.tsx
@@ -0,0 +1,63 @@
+
+import React from 'react';
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
+import { Calendar } from 'lucide-react';
+
+interface MonthFilterProps {
+ selectedMonth: string;
+ onMonthChange: (month: string) => void;
+ className?: string;
+}
+
+export const MonthFilter = ({ selectedMonth, onMonthChange, className }: MonthFilterProps) => {
+ const months = [
+ { value: '2024-01', label: 'Janeiro 2024' },
+ { value: '2024-02', label: 'Fevereiro 2024' },
+ { value: '2024-03', label: 'Março 2024' },
+ { value: '2024-04', label: 'Abril 2024' },
+ { value: '2024-05', label: 'Maio 2024' },
+ { value: '2024-06', label: 'Junho 2024' },
+ { value: '2024-07', label: 'Julho 2024' },
+ { value: '2024-08', label: 'Agosto 2024' },
+ { value: '2024-09', label: 'Setembro 2024' },
+ { value: '2024-10', label: 'Outubro 2024' },
+ { value: '2024-11', label: 'Novembro 2024' },
+ { value: '2024-12', label: 'Dezembro 2024' },
+ { value: '2025-01', label: 'Janeiro 2025' },
+ { value: '2025-02', label: 'Fevereiro 2025' },
+ { value: '2025-03', label: 'Março 2025' },
+ { value: '2025-04', label: 'Abril 2025' },
+ { value: '2025-05', label: 'Maio 2025' },
+ { value: '2025-06', label: 'Junho 2025' },
+ { value: '2025-07', label: 'Julho 2025' },
+ { value: '2025-08', label: 'Agosto 2025' },
+ { value: '2025-09', label: 'Setembro 2025' },
+ { value: '2025-10', label: 'Outubro 2025' },
+ { value: '2025-11', label: 'Novembro 2025' },
+ { value: '2025-12', label: 'Dezembro 2025' },
+ ];
+
+ // Função para obter o mês atual no formato YYYY-MM
+ const getCurrentMonth = () => {
+ const now = new Date();
+ return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
+ };
+
+ return (
+
+
+
+
+ );
+};
diff --git a/src/hooks/useTransactions.ts b/src/hooks/useTransactions.ts
index 9068a7e..f65951c 100644
--- a/src/hooks/useTransactions.ts
+++ b/src/hooks/useTransactions.ts
@@ -1,4 +1,3 @@
-
import { useState, useEffect } from 'react';
import { Transaction } from '@/types/financialTypes';
import { CartaoCredito } from '@/types/cartaoTypes';
@@ -6,7 +5,11 @@ import { useToast } from '@/hooks/use-toast';
import { getTransacoes } from '@/services/transacao';
import { getCartoes } from '@/services/cartaoCreditoService';
-export const useTransactions = () => {
+interface UseTransactionsProps {
+ monthFilter?: string;
+}
+
+export const useTransactions = ({ monthFilter }: UseTransactionsProps = {}) => {
const [transactions, setTransactions] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [isDialogOpen, setIsDialogOpen] = useState(false);
@@ -20,8 +23,8 @@ export const useTransactions = () => {
const loadTransactions = async () => {
try {
setIsLoading(true);
- console.log("Carregando todas as transações...");
- const data = await getTransacoes();
+ console.log("Carregando transações com filtro:", monthFilter);
+ const data = await getTransacoes(monthFilter);
console.log(`${data.length} transações carregadas com sucesso`);
setTransactions(data);
} catch (error) {
@@ -53,7 +56,7 @@ export const useTransactions = () => {
useEffect(() => {
loadTransactions();
loadCartoes();
- }, []);
+ }, [monthFilter]);
const handleTransactionSuccess = () => {
setIsDialogOpen(false);
diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts
index 12e3391..8638603 100644
--- a/src/integrations/supabase/types.ts
+++ b/src/integrations/supabase/types.ts
@@ -144,6 +144,39 @@ export type Database = {
}
Relationships: []
}
+ conversas_zap: {
+ Row: {
+ created_at: string
+ date_time: string | null
+ id: number
+ id_transacao_gerada: number | null
+ login: string | null
+ msg_recebida: string | null
+ remote_jid: string | null
+ status_processamento: string | null
+ }
+ Insert: {
+ created_at?: string
+ date_time?: string | null
+ id?: number
+ id_transacao_gerada?: number | null
+ login?: string | null
+ msg_recebida?: string | null
+ remote_jid?: string | null
+ status_processamento?: string | null
+ }
+ Update: {
+ created_at?: string
+ date_time?: string | null
+ id?: number
+ id_transacao_gerada?: number | null
+ login?: string | null
+ msg_recebida?: string | null
+ remote_jid?: string | null
+ status_processamento?: string | null
+ }
+ Relationships: []
+ }
despesas_cartao: {
Row: {
cartao_id: string | null
@@ -294,10 +327,11 @@ export type Database = {
empresa: string | null
id: string
instancia_zap: string | null
- nome: string
+ nome: string | null
remote_jid: string | null
- senha: string
+ senha: string | null
status_instancia: string | null
+ webhook: string | null
whatsapp: string
}
Insert: {
@@ -306,10 +340,11 @@ export type Database = {
empresa?: string | null
id?: string
instancia_zap?: string | null
- nome: string
+ nome?: string | null
remote_jid?: string | null
- senha: string
+ senha?: string | null
status_instancia?: string | null
+ webhook?: string | null
whatsapp: string
}
Update: {
@@ -318,10 +353,11 @@ export type Database = {
empresa?: string | null
id?: string
instancia_zap?: string | null
- nome?: string
+ nome?: string | null
remote_jid?: string | null
- senha?: string
+ senha?: string | null
status_instancia?: string | null
+ webhook?: string | null
whatsapp?: string
}
Relationships: []
diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx
index e848e97..cdc8a34 100644
--- a/src/pages/Index.tsx
+++ b/src/pages/Index.tsx
@@ -5,6 +5,7 @@ import SummaryCard from '@/components/dashboard/SummaryCard';
import TransactionsTable from '@/components/dashboard/TransactionsTable';
import CategoryChart from '@/components/dashboard/CategoryChart';
import MonthlyChart from '@/components/dashboard/MonthlyChart';
+import { MonthFilter } from '@/components/filters/MonthFilter';
import { Wallet, ArrowUp, ArrowDown, PiggyBank, CreditCard } from 'lucide-react';
import { Transaction, CategorySummary, MonthlyData } from '@/types/financialTypes';
import { useToast } from "@/components/ui/use-toast";
@@ -24,6 +25,14 @@ const Dashboard = () => {
const [totals, setTotals] = useState({ receitas: 0, despesas: 0, saldo: 0, cartoes: 0 });
const { toast } = useToast();
+ // Função para obter o mês atual no formato YYYY-MM
+ const getCurrentMonth = () => {
+ const now = new Date();
+ return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
+ };
+
+ const [selectedMonth, setSelectedMonth] = useState(getCurrentMonth());
+
// Use useCallback to ensure this function doesn't change on every render
const setupUserId = useCallback(() => {
const storedUserId = localStorage.getItem('userId');
@@ -42,19 +51,19 @@ const Dashboard = () => {
setupUserId();
}, [setupUserId]);
- // Load data only once when component mounts
+ // Load data when component mounts or month changes
useEffect(() => {
async function loadData() {
try {
setIsLoading(true);
- console.log("Iniciando carregamento de dados...");
+ console.log("Iniciando carregamento de dados para o mês:", selectedMonth);
- // Buscar todos os dados necessários
+ // Buscar todos os dados necessários com filtro de mês
const [transacoesData, totalsData, categoriesData, monthlyDataResult, cartoesData] = await Promise.all([
- getTransacoes(),
- getTransactionSummary(),
- getCategorySummary(),
- getMonthlyData(),
+ getTransacoes(selectedMonth),
+ getTransactionSummary(selectedMonth),
+ getCategorySummary('despesa', selectedMonth),
+ getMonthlyData(), // Monthly data não precisa de filtro pois já mostra todos os meses
getCartoes()
]);
@@ -67,7 +76,8 @@ const Dashboard = () => {
categories: categoriesData.length,
monthlyData: monthlyDataResult.length,
cartoes: cartoesData.length,
- totalCartoes: totalCartoes
+ totalCartoes: totalCartoes,
+ mesEscolhido: selectedMonth
});
setTransactions(transacoesData);
@@ -82,7 +92,7 @@ const Dashboard = () => {
toast({
title: "Dados carregados com sucesso",
- description: "Seus dados financeiros foram atualizados"
+ description: `Dados financeiros de ${selectedMonth} foram atualizados`
});
} catch (error) {
console.error("Erro ao carregar dados:", error);
@@ -97,9 +107,8 @@ const Dashboard = () => {
}
loadData();
- // Ensure toast doesn't cause re-renders by removing it from dependencies
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ }, [selectedMonth]);
const formatCurrency = (value: number) => {
return new Intl.NumberFormat('pt-BR', {
@@ -111,14 +120,30 @@ const Dashboard = () => {
// Calculate total of all expenses (regular + credit cards)
const totalDespesasGeral = totals.despesas + totals.cartoes;
+ // Função para formatar o mês para exibição
+ const formatMonthDisplay = (month: string) => {
+ const [year, monthNum] = month.split('-');
+ const months = [
+ 'Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho',
+ 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'
+ ];
+ return `${months[parseInt(monthNum) - 1]} ${year}`;
+ };
+
return (
-
Dashboard Financeiro
-
- Última atualização: {new Date().toLocaleDateString('pt-BR')}
-
+
+
Dashboard Financeiro
+
+ Dados de: {formatMonthDisplay(selectedMonth)}
+
+
+
diff --git a/src/pages/Transacoes.tsx b/src/pages/Transacoes.tsx
index dc6f49e..ff95294 100644
--- a/src/pages/Transacoes.tsx
+++ b/src/pages/Transacoes.tsx
@@ -1,13 +1,22 @@
-import React from 'react';
+import React, { useState } from 'react';
import Layout from '@/components/layout/Layout';
import TransactionsTable from '@/components/dashboard/TransactionsTable';
import { useTransactions } from '@/hooks/useTransactions';
import { TransactionHeader } from '@/components/transacoes/TransactionHeader';
import { TransactionSummaryCards } from '@/components/transacoes/TransactionSummaryCards';
import { TransactionDialogs } from '@/components/transacoes/TransactionDialogs';
+import { MonthFilter } from '@/components/filters/MonthFilter';
const TransacoesPage = () => {
+ // Função para obter o mês atual no formato YYYY-MM
+ const getCurrentMonth = () => {
+ const now = new Date();
+ return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
+ };
+
+ const [selectedMonth, setSelectedMonth] = useState
(getCurrentMonth());
+
const {
transactions,
isLoading,
@@ -29,11 +38,34 @@ const TransacoesPage = () => {
handleOpenDialog,
handleOpenCartaoCreditoDialog,
loadTransactions
- } = useTransactions();
+ } = useTransactions({ monthFilter: selectedMonth });
+
+ // Função para formatar o mês para exibição
+ const formatMonthDisplay = (month: string) => {
+ const [year, monthNum] = month.split('-');
+ const months = [
+ 'Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho',
+ 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'
+ ];
+ return `${months[parseInt(monthNum) - 1]} ${year}`;
+ };
return (
+
+
+
Transações
+
+ Dados de: {formatMonthDisplay(selectedMonth)}
+
+
+
+
+
0 ? `grupo_id.in.(${groupIds.map(id => `"${id}"`).join(',')})` : ''}`);
+ // Apply month filter if provided
+ if (monthFilter) {
+ const startDate = `${monthFilter}-01`;
+ const year = parseInt(monthFilter.split('-')[0]);
+ const month = parseInt(monthFilter.split('-')[1]);
+ const endDate = new Date(year, month, 0).toISOString().split('T')[0]; // Last day of the month
+
+ query = query
+ .gte('quando', startDate)
+ .lte('quando', `${endDate}T23:59:59.999Z`);
+ }
+
+ const { data, error } = await query;
+
if (error) {
console.error('Erro ao buscar resumo das transações:', error);
throw new Error('Não foi possível carregar o resumo das transações');
@@ -56,12 +71,13 @@ export async function getTransactionSummary() {
}
/**
- * Get category summary for transactions
+ * Get category summary for transactions with optional month filter
* @param tipoFiltro Filter by transaction type ('receita', 'despesa', or 'all')
+ * @param monthFilter - Optional month filter in format 'YYYY-MM'
* @returns Promise with category summary data
*/
-export async function getCategorySummary(tipoFiltro: string = 'despesa'): Promise {
- console.log(`Buscando resumo de categorias para tipo: ${tipoFiltro}`);
+export async function getCategorySummary(tipoFiltro: string = 'despesa', monthFilter?: string): Promise {
+ console.log(`Buscando resumo de categorias para tipo: ${tipoFiltro}`, monthFilter ? `Filtro do mês: ${monthFilter}` : "Sem filtro de mês");
const normalizedEmail = getUserEmail();
@@ -73,12 +89,26 @@ export async function getCategorySummary(tipoFiltro: string = 'despesa'): Promis
// Get user groups by email
const groupIds = await getUserGroups(normalizedEmail);
- // Fetch category summary with enhanced filter based on email (login) or group_id
- const { data, error } = await supabase
+ // Build the query with month filter if provided
+ let query = supabase
.from('transacoes')
.select('categoria, valor, tipo')
.or(`login.eq.${normalizedEmail},${groupIds.length > 0 ? `grupo_id.in.(${groupIds.map(id => `"${id}"`).join(',')})` : ''}`);
+ // Apply month filter if provided
+ if (monthFilter) {
+ const startDate = `${monthFilter}-01`;
+ const year = parseInt(monthFilter.split('-')[0]);
+ const month = parseInt(monthFilter.split('-')[1]);
+ const endDate = new Date(year, month, 0).toISOString().split('T')[0]; // Last day of the month
+
+ query = query
+ .gte('quando', startDate)
+ .lte('quando', `${endDate}T23:59:59.999Z`);
+ }
+
+ const { data, error } = await query;
+
if (error) {
console.error('Erro ao buscar resumo de categorias:', error);
throw new Error('Não foi possível carregar o resumo por categoria');
diff --git a/src/services/transacao/transacaoFetchService.ts b/src/services/transacao/transacaoFetchService.ts
index af088d0..a1c3de1 100644
--- a/src/services/transacao/transacaoFetchService.ts
+++ b/src/services/transacao/transacaoFetchService.ts
@@ -4,11 +4,12 @@ import { Transaction } from "@/types/financialTypes";
import { getUserEmail, getUserGroups } from "./baseService";
/**
- * Fetch all transactions for the current user
+ * Fetch all transactions for the current user with optional month filter
+ * @param monthFilter - Optional month filter in format 'YYYY-MM'
* @returns Promise with array of transactions
*/
-export async function getTransacoes(): Promise {
- console.log("Buscando transações do Supabase...");
+export async function getTransacoes(monthFilter?: string): Promise {
+ console.log("Buscando transações do Supabase...", monthFilter ? `Filtro do mês: ${monthFilter}` : "Sem filtro de mês");
// Get the user's email from localStorage
const normalizedEmail = getUserEmail();
@@ -24,13 +25,29 @@ export async function getTransacoes(): Promise {
const groupIds = await getUserGroups(normalizedEmail);
console.log(`Encontrados ${groupIds.length} grupos vinculados ao usuário:`, groupIds);
- // Fetch transactions with filter based on email (login) or group_id
- const { data, error } = await supabase
+ // Build the query with month filter if provided
+ let query = supabase
.from('transacoes')
.select('*')
.or(`login.eq.${normalizedEmail},${groupIds.length > 0 ? `grupo_id.in.(${groupIds.map(id => `"${id}"`).join(',')})` : ''}`)
.order('quando', { ascending: false });
+ // Apply month filter if provided
+ if (monthFilter) {
+ const startDate = `${monthFilter}-01`;
+ const year = parseInt(monthFilter.split('-')[0]);
+ const month = parseInt(monthFilter.split('-')[1]);
+ const endDate = new Date(year, month, 0).toISOString().split('T')[0]; // Last day of the month
+
+ query = query
+ .gte('quando', startDate)
+ .lte('quando', `${endDate}T23:59:59.999Z`);
+
+ console.log(`Aplicando filtro de mês: ${startDate} até ${endDate}`);
+ }
+
+ const { data, error } = await query;
+
if (error) {
console.error('Erro ao buscar transações:', error);
throw new Error('Não foi possível carregar as transações');