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:
parent
e6d6f5c2b3
commit
1e9117cbd2
@ -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) {
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user