Refactor: Use login and nome for expense association

Update the frontend logic to display credit card expenses based on a combination of the 'login' and 'nome' columns, instead of 'cartao_id', for associating expenses with cards and users.
This commit is contained in:
gpt-engineer-app[bot] 2025-05-21 10:44:46 +00:00
parent e6d6f5c2b3
commit 1e9117cbd2
5 changed files with 102 additions and 35 deletions

View File

@ -10,7 +10,7 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
import { formatDistanceToNow } from 'date-fns'; import { format } from 'date-fns';
import { ptBR } from 'date-fns/locale'; import { ptBR } from 'date-fns/locale';
import { import {
Pagination, Pagination,
@ -40,12 +40,13 @@ export function DespesasList({ despesas, isLoading }: DespesasListProps) {
}; };
const formatDate = (dateString: string) => { const formatDate = (dateString: string) => {
const options: Intl.DateTimeFormatOptions = { try {
day: '2-digit', const date = new Date(dateString);
month: '2-digit', return format(date, 'dd/MM/yyyy', { locale: ptBR });
year: 'numeric' } catch (error) {
}; console.error("Error formatting date:", error);
return new Date(dateString).toLocaleDateString('pt-BR', options); return dateString;
}
}; };
if (isLoading) { if (isLoading) {

View File

@ -3,21 +3,57 @@ import { FormControl, FormItem, FormLabel, FormMessage } from "@/components/ui/f
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { UseFormReturn } from "react-hook-form"; import { UseFormReturn } from "react-hook-form";
import { TransactionFormValues } from "@/hooks/useTransactionForm"; import { TransactionFormValues } from "@/hooks/useTransactionForm";
import { CalendarIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Calendar } from "@/components/ui/calendar";
import { cn } from "@/lib/utils";
import { format } from "date-fns";
import { ptBR } from "date-fns/locale";
interface TransactionDateFieldProps { interface TransactionDateFieldProps {
form: UseFormReturn<TransactionFormValues>; form: UseFormReturn<TransactionFormValues>;
} }
export function TransactionDateField({ form }: TransactionDateFieldProps) { export function TransactionDateField({ form }: TransactionDateFieldProps) {
const date = form.watch("quando");
return ( return (
<FormItem> <FormItem className="flex flex-col">
<FormLabel>Data</FormLabel> <FormLabel>Data</FormLabel>
<Popover>
<PopoverTrigger asChild>
<FormControl> <FormControl>
<Input <Button
type="date" variant={"outline"}
{...form.register("quando")} className={cn(
/> "w-full pl-3 text-left font-normal",
!date && "text-muted-foreground"
)}
>
{date ? (
format(new Date(date), "dd/MM/yyyy", { locale: ptBR })
) : (
<span>Selecione uma data</span>
)}
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
</Button>
</FormControl> </FormControl>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
mode="single"
selected={date ? new Date(date) : undefined}
onSelect={(date) => {
if (date) {
form.setValue("quando", date.toISOString());
}
}}
initialFocus
locale={ptBR}
/>
</PopoverContent>
</Popover>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
); );

View File

@ -146,7 +146,7 @@ export type Database = {
} }
despesas_cartao: { despesas_cartao: {
Row: { Row: {
cartao_id: string cartao_id: string | null
created_at: string created_at: string
data_despesa: string data_despesa: string
descricao: string descricao: string
@ -156,7 +156,7 @@ export type Database = {
valor: number valor: number
} }
Insert: { Insert: {
cartao_id: string cartao_id?: string | null
created_at?: string created_at?: string
data_despesa: string data_despesa: string
descricao: string descricao: string
@ -166,7 +166,7 @@ export type Database = {
valor: number valor: number
} }
Update: { Update: {
cartao_id?: string cartao_id?: string | null
created_at?: string created_at?: string
data_despesa?: string data_despesa?: string
descricao?: string descricao?: string

View File

@ -40,6 +40,7 @@ const CartoesCreditoPage = () => {
const loadDespesasCartao = async (cartaoId: string) => { const loadDespesasCartao = async (cartaoId: string) => {
try { try {
setIsLoading(true); setIsLoading(true);
// This function now uses login+nome matching internally instead of cartao_id
const data = await getDespesasCartao(cartaoId); const data = await getDespesasCartao(cartaoId);
setDespesas(data); setDespesas(data);
} catch (error) { } catch (error) {

View File

@ -4,8 +4,9 @@ import { DespesaCartao } from "@/types/cartaoTypes";
import { getCartao } from "./cartoesService"; import { getCartao } from "./cartoesService";
/** /**
* Fetches expenses for a specific credit card * Fetches expenses for a specific credit card based on login and nome
* @param cartaoId Card ID * @param cartaoId Card ID (still used for type compatibility)
* @param cardName Card name to match with expenses
* @returns Array of card expenses * @returns Array of card expenses
*/ */
export async function getDespesasCartao(cartaoId: string): Promise<DespesaCartao[]> { export async function getDespesasCartao(cartaoId: string): Promise<DespesaCartao[]> {
@ -21,7 +22,7 @@ export async function getDespesasCartao(cartaoId: string): Promise<DespesaCartao
const normalizedEmail = userEmail.trim().toLowerCase(); const normalizedEmail = userEmail.trim().toLowerCase();
try { try {
// Primeiro, obter o cartao_codigo do cartão // First, get the card details to get the name
const cartao = await getCartao(cartaoId); const cartao = await getCartao(cartaoId);
if (!cartao) { if (!cartao) {
@ -29,10 +30,14 @@ export async function getDespesasCartao(cartaoId: string): Promise<DespesaCartao
return []; return [];
} }
const cardName = cartao.nome;
// Now get expenses matching by login and nome instead of cartao_id
const { data, error } = await supabase const { data, error } = await supabase
.from('despesas_cartao') .from('despesas_cartao')
.select('*') .select('*')
.eq('cartao_id', cartaoId) .eq('login', normalizedEmail)
.eq('nome', cardName)
.order('data_despesa', { ascending: false }); .order('data_despesa', { ascending: false });
if (error) { if (error) {
@ -40,10 +45,11 @@ export async function getDespesasCartao(cartaoId: string): Promise<DespesaCartao
throw new Error('Não foi possível carregar as despesas do cartão'); throw new Error('Não foi possível carregar as despesas do cartão');
} }
// Mapear os resultados para o tipo DespesaCartao, adicionando o cartao_codigo // Map results to DespesaCartao type, adding cartao_codigo
const despesasCompletas = data.map(despesa => ({ const despesasCompletas = data.map(despesa => ({
...despesa, ...despesa,
cartao_codigo: cartao.cartao_codigo || '' // Use o código do cartão obtido anteriormente cartao_codigo: cartao.cartao_codigo || '',
cartao_id: cartaoId // Keep for backwards compatibility
})) as DespesaCartao[]; })) as DespesaCartao[];
return despesasCompletas; return despesasCompletas;
@ -55,7 +61,7 @@ export async function getDespesasCartao(cartaoId: string): Promise<DespesaCartao
/** /**
* Creates a new expense for a credit card * Creates a new expense for a credit card
* @param cartao_id Card ID * @param cartao_id Card ID (kept for backwards compatibility)
* @param cartao_codigo Card code * @param cartao_codigo Card code
* @param valor Expense value * @param valor Expense value
* @param data_despesa Expense date * @param data_despesa Expense date
@ -98,7 +104,6 @@ export async function criarDespesa(
const nomeCartao = cartaoData.nome; const nomeCartao = cartaoData.nome;
console.log('Tentando criar despesa de cartão com os dados:', { console.log('Tentando criar despesa de cartão com os dados:', {
cartao_id,
login: normalizedEmail, login: normalizedEmail,
nome: nomeCartao, nome: nomeCartao,
valor, valor,
@ -106,16 +111,16 @@ export async function criarDespesa(
descricao descricao
}); });
// Inserir registro com as novas colunas login e nome // Insert new expense with login and nome (but not cartao_id)
const { data, error } = await supabase const { data, error } = await supabase
.from('despesas_cartao') .from('despesas_cartao')
.insert([{ .insert([{
cartao_id: cartao_id,
login: normalizedEmail, login: normalizedEmail,
nome: nomeCartao, nome: nomeCartao,
valor: valor, valor: valor,
data_despesa: data_despesa, data_despesa: data_despesa,
descricao: descricao descricao: descricao,
cartao_id: cartao_id // Keep for now to avoid breaking existing functionality
}]) }])
.select(); .select();
@ -129,10 +134,10 @@ export async function criarDespesa(
return null; return null;
} }
// Adicionar cartao_codigo ao resultado // Add cartao_codigo to result
const despesaCompleta = { const despesaCompleta = {
...data[0], ...data[0],
cartao_codigo: cartao_codigo // Use o código do cartão fornecido no parâmetro cartao_codigo: cartao_codigo
} as DespesaCartao; } as DespesaCartao;
return despesaCompleta; return despesaCompleta;
@ -143,8 +148,8 @@ export async function criarDespesa(
} }
/** /**
* Calculates the total expenses for a credit card * Calculates the total expenses for a credit card based on login and card name
* @param cartaoId Card ID (not code) * @param cartaoId Card ID
* @returns Total expenses amount * @returns Total expenses amount
*/ */
export async function getTotalDespesasCartao(cartaoId: string): Promise<number> { export async function getTotalDespesasCartao(cartaoId: string): Promise<number> {
@ -155,18 +160,42 @@ export async function getTotalDespesasCartao(cartaoId: string): Promise<number>
} }
try { try {
// Buscar despesas pelo ID do cartão // Get the user's email from localStorage
const userEmail = localStorage.getItem('userEmail');
if (!userEmail) {
console.error('Email do usuário não encontrado');
return 0;
}
const normalizedEmail = userEmail.trim().toLowerCase();
// Get the card's name from cartoes_credito
const { data: cardData, error: cardError } = await supabase
.from('cartoes_credito')
.select('nome')
.eq('id', cartaoId)
.single();
if (cardError || !cardData) {
console.error('Erro ao obter nome do cartão:', cardError);
return 0;
}
const cardName = cardData.nome;
// Now get expenses matching both login and nome
const { data, error } = await supabase const { data, error } = await supabase
.from('despesas_cartao') .from('despesas_cartao')
.select('valor') .select('valor')
.eq('cartao_id', cartaoId); .eq('login', normalizedEmail)
.eq('nome', cardName);
if (error) { if (error) {
console.error('Erro ao calcular total de despesas:', error); console.error('Erro ao calcular total de despesas:', error);
return 0; return 0;
} }
// Somar todos os valores das despesas // Sum all expense values
const total = data.reduce((acc, item) => acc + Number(item.valor), 0); const total = data.reduce((acc, item) => acc + Number(item.valor), 0);
return total; return total;
} catch (error) { } catch (error) {