Implement credit card and expense features.
Add credit card registration form with required fields and auto-generated code. Implement expense registration form with card selection and required fields. Establish association logic between expenses and cards based on user and card codes. Ensure data privacy and validation.
This commit is contained in:
parent
04ed74ac61
commit
0d58128969
@ -1,5 +1,5 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import * as z from 'zod';
|
||||
@ -15,9 +15,31 @@ import {
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
// Opções para as listas suspensas
|
||||
const bandeirasCartao = [
|
||||
'Visa', 'Mastercard', 'Elo', 'American Express', 'Hipercard',
|
||||
'Diners Club', 'Credicard', 'Sorocred', 'Cabal', 'Banescard',
|
||||
'Sicoobcard', 'Sicredi', 'Alelo', 'Ticket', 'VR', 'ValeCard', 'Havan'
|
||||
];
|
||||
|
||||
const bancos = [
|
||||
'Itaú', 'Bradesco', 'Santander', 'Banco do Brasil', 'Caixa', 'Nubank',
|
||||
'Inter', 'C6 Bank', 'Next', 'Original', 'Pan', 'Banco Bari',
|
||||
'Sicoob', 'Sicredi', 'Neon', 'BTG Pactual', 'PagBank', 'Will Bank', 'XP'
|
||||
];
|
||||
|
||||
const cartaoSchema = z.object({
|
||||
nome: z.string().min(1, { message: 'Nome do cartão é obrigatório' }),
|
||||
bandeira: z.string({ required_error: 'Selecione uma bandeira' }),
|
||||
banco: z.string({ required_error: 'Selecione um banco' }),
|
||||
});
|
||||
|
||||
type CartaoFormValues = z.infer<typeof cartaoSchema>;
|
||||
@ -35,14 +57,30 @@ export function CartaoCreditoForm({ onSuccess, onCancel }: CartaoCreditoFormProp
|
||||
resolver: zodResolver(cartaoSchema),
|
||||
defaultValues: {
|
||||
nome: '',
|
||||
bandeira: '',
|
||||
banco: '',
|
||||
}
|
||||
});
|
||||
|
||||
// Função para gerar um código único para o cartão
|
||||
const gerarCartaoCodigo = (nome: string, banco: string) => {
|
||||
const randomStr = Math.random().toString(36).substring(2, 8);
|
||||
return `${banco.toLowerCase()}_${nome.toLowerCase().replace(/\s/g, '')}_${randomStr}`;
|
||||
};
|
||||
|
||||
async function onSubmit(data: CartaoFormValues) {
|
||||
setIsSubmitting(true);
|
||||
|
||||
try {
|
||||
const resultado = await criarCartao(data.nome);
|
||||
// Gerar código único para o cartão
|
||||
const cartao_codigo = gerarCartaoCodigo(data.nome, data.banco);
|
||||
|
||||
const resultado = await criarCartao(
|
||||
data.nome,
|
||||
data.bandeira,
|
||||
data.banco,
|
||||
cartao_codigo
|
||||
);
|
||||
|
||||
if (resultado) {
|
||||
toast({
|
||||
@ -79,13 +117,63 @@ export function CartaoCreditoForm({ onSuccess, onCancel }: CartaoCreditoFormProp
|
||||
<FormItem>
|
||||
<FormLabel>Nome do Cartão</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Ex: Nubank, Itaú, Banco do Brasil..." {...field} />
|
||||
<Input placeholder="Ex: Gold, Platinum, Internacional..." {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bandeira"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Bandeira</FormLabel>
|
||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Selecione uma bandeira" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{bandeirasCartao.map((bandeira) => (
|
||||
<SelectItem key={bandeira} value={bandeira}>
|
||||
{bandeira}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="banco"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Banco Emissor</FormLabel>
|
||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Selecione um banco" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{bancos.map((banco) => (
|
||||
<SelectItem key={banco} value={banco}>
|
||||
{banco}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end space-x-2 pt-2">
|
||||
<Button variant="outline" type="button" onClick={onCancel} disabled={isSubmitting}>
|
||||
Cancelar
|
||||
|
||||
@ -60,6 +60,10 @@ export function CartaoCreditoList({ cartoes, isLoading, onCartaoClick }: CartaoC
|
||||
<CreditCard className="w-5 h-5 mr-2" />
|
||||
{cartao.nome}
|
||||
</CardTitle>
|
||||
<div className="text-sm text-muted-foreground space-y-1">
|
||||
{cartao.banco && <div>{cartao.banco}</div>}
|
||||
{cartao.bandeira && <div>{cartao.bandeira}</div>}
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-2xl font-semibold">
|
||||
|
||||
@ -4,7 +4,11 @@ import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import * as z from 'zod';
|
||||
import { useToast } from '@/components/ui/use-toast';
|
||||
import { CartaoCredito } from '@/types/cartaoTypes';
|
||||
import { criarDespesa } from '@/services/cartaoCreditoService';
|
||||
import { CalendarIcon } from 'lucide-react';
|
||||
import { format } from 'date-fns';
|
||||
import { ptBR } from 'date-fns/locale';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
@ -15,23 +19,31 @@ import {
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { CartaoCredito } from '@/types/cartaoTypes';
|
||||
import {
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue
|
||||
} from '@/components/ui/select';
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const despesaSchema = z.object({
|
||||
cartaoId: z.string().min(1, { message: 'Cartão é obrigatório' }),
|
||||
valor: z.string().min(1, { message: 'Valor é obrigatório' }),
|
||||
data_despesa: z.string().min(1, { message: 'Data é obrigatória' }),
|
||||
const despesaCartaoSchema = z.object({
|
||||
cartao_id: z.string().min(1, { message: 'Selecione um cartão' }),
|
||||
valor: z.number().positive({ message: 'O valor deve ser maior que zero' }),
|
||||
data_despesa: z.date({
|
||||
required_error: "Selecione uma data",
|
||||
}),
|
||||
descricao: z.string().min(1, { message: 'Descrição é obrigatória' }),
|
||||
});
|
||||
|
||||
type DespesaFormValues = z.infer<typeof despesaSchema>;
|
||||
type DespesaCartaoFormValues = z.infer<typeof despesaCartaoSchema>;
|
||||
|
||||
interface DespesaCartaoFormSelectProps {
|
||||
cartoes: CartaoCredito[];
|
||||
@ -42,44 +54,56 @@ interface DespesaCartaoFormSelectProps {
|
||||
export function DespesaCartaoFormSelect({ cartoes, onSuccess, onCancel }: DespesaCartaoFormSelectProps) {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const { toast } = useToast();
|
||||
const [selectedCartao, setSelectedCartao] = useState<CartaoCredito | null>(null);
|
||||
|
||||
const form = useForm<DespesaFormValues>({
|
||||
resolver: zodResolver(despesaSchema),
|
||||
const form = useForm<DespesaCartaoFormValues>({
|
||||
resolver: zodResolver(despesaCartaoSchema),
|
||||
defaultValues: {
|
||||
cartaoId: '',
|
||||
valor: '',
|
||||
data_despesa: new Date().toISOString().split('T')[0],
|
||||
valor: undefined,
|
||||
data_despesa: new Date(),
|
||||
descricao: '',
|
||||
}
|
||||
});
|
||||
|
||||
async function onSubmit(data: DespesaFormValues) {
|
||||
const handleCartaoChange = (cartaoId: string) => {
|
||||
const cartao = cartoes.find(c => c.id === cartaoId);
|
||||
setSelectedCartao(cartao || null);
|
||||
};
|
||||
|
||||
const formatCartaoLabel = (cartao: CartaoCredito) => {
|
||||
let label = cartao.nome;
|
||||
if (cartao.banco) label += ` - ${cartao.banco}`;
|
||||
if (cartao.bandeira) label += ` (${cartao.bandeira})`;
|
||||
return label;
|
||||
};
|
||||
|
||||
async function onSubmit(data: DespesaCartaoFormValues) {
|
||||
if (!selectedCartao || !selectedCartao.cartao_codigo) {
|
||||
toast({
|
||||
title: "Erro",
|
||||
description: "Informações do cartão incompletas",
|
||||
variant: "destructive"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSubmitting(true);
|
||||
|
||||
try {
|
||||
const valorNumerico = parseFloat(data.valor.replace(',', '.'));
|
||||
|
||||
if (isNaN(valorNumerico)) {
|
||||
toast({
|
||||
title: "Erro no formulário",
|
||||
description: "O valor precisa ser um número válido",
|
||||
variant: "destructive"
|
||||
});
|
||||
setIsSubmitting(false);
|
||||
return;
|
||||
}
|
||||
const formattedDate = format(data.data_despesa, 'yyyy-MM-dd');
|
||||
|
||||
const resultado = await criarDespesa(
|
||||
data.cartaoId,
|
||||
valorNumerico,
|
||||
data.data_despesa,
|
||||
data.cartao_id,
|
||||
selectedCartao.cartao_codigo,
|
||||
data.valor,
|
||||
formattedDate,
|
||||
data.descricao
|
||||
);
|
||||
|
||||
if (resultado) {
|
||||
toast({
|
||||
title: "Despesa adicionada",
|
||||
description: "Despesa do cartão cadastrada com sucesso",
|
||||
description: "Despesa do cartão registrada com sucesso",
|
||||
});
|
||||
onSuccess();
|
||||
} else {
|
||||
@ -101,21 +125,21 @@ export function DespesaCartaoFormSelect({ cartoes, onSuccess, onCancel }: Despes
|
||||
}
|
||||
}
|
||||
|
||||
const selectedCartaoNome = form.watch('cartaoId') ?
|
||||
cartoes.find(cartao => cartao.id === form.watch('cartaoId'))?.nome : '';
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cartaoId"
|
||||
name="cartao_id"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Cartão de Crédito</FormLabel>
|
||||
<Select
|
||||
onValueChange={field.onChange}
|
||||
value={field.value}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value);
|
||||
handleCartaoChange(value);
|
||||
}}
|
||||
defaultValue={field.value}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
@ -125,7 +149,7 @@ export function DespesaCartaoFormSelect({ cartoes, onSuccess, onCancel }: Despes
|
||||
<SelectContent>
|
||||
{cartoes.map((cartao) => (
|
||||
<SelectItem key={cartao.id} value={cartao.id}>
|
||||
{cartao.nome}
|
||||
{formatCartaoLabel(cartao)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
@ -135,12 +159,6 @@ export function DespesaCartaoFormSelect({ cartoes, onSuccess, onCancel }: Despes
|
||||
)}
|
||||
/>
|
||||
|
||||
{selectedCartaoNome && (
|
||||
<div className="mb-4">
|
||||
<p className="text-sm text-muted-foreground">Cartão selecionado: <span className="font-medium">{selectedCartaoNome}</span></p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="valor"
|
||||
@ -149,26 +167,56 @@ export function DespesaCartaoFormSelect({ cartoes, onSuccess, onCancel }: Despes
|
||||
<FormLabel>Valor</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="0,00"
|
||||
{...field}
|
||||
type="text"
|
||||
inputMode="decimal"
|
||||
type="number"
|
||||
step="0.01"
|
||||
placeholder="0.00"
|
||||
{...field}
|
||||
onChange={(e) => field.onChange(parseFloat(e.target.value) || 0)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="data_despesa"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Data</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="date" {...field} />
|
||||
</FormControl>
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Data da Despesa</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-full pl-3 text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "dd/MM/yyyy", { locale: ptBR })
|
||||
) : (
|
||||
<span>Selecione uma data</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
disabled={(date) =>
|
||||
date > new Date() || date < new Date("1900-01-01")
|
||||
}
|
||||
initialFocus
|
||||
locale={ptBR}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
@ -181,7 +229,7 @@ export function DespesaCartaoFormSelect({ cartoes, onSuccess, onCancel }: Despes
|
||||
<FormItem>
|
||||
<FormLabel>Descrição</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Detalhes da despesa" {...field} />
|
||||
<Input placeholder="Ex: Compras de supermercado, Restaurante..." {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@ -24,6 +24,7 @@ export const TransactionSummaryCards = ({
|
||||
<Card>
|
||||
<CardHeader className="pb-2 bg-green-50">
|
||||
<CardTitle className="text-finance-green flex items-center">
|
||||
<Wallet className="h-4 w-4 mr-2" />
|
||||
Ganhos do mês
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
@ -29,7 +29,7 @@ export async function getCartoes(): Promise<CartaoCredito[]> {
|
||||
// Buscar o total de despesas para cada cartão
|
||||
const cartoesComTotal = await Promise.all(
|
||||
data.map(async (cartao: CartaoCredito) => {
|
||||
const total = await getTotalDespesasCartao(cartao.id);
|
||||
const total = await getTotalDespesasCartao(cartao.cartao_codigo);
|
||||
return { ...cartao, total_despesas: total };
|
||||
})
|
||||
);
|
||||
@ -41,8 +41,41 @@ export async function getCartoes(): Promise<CartaoCredito[]> {
|
||||
}
|
||||
}
|
||||
|
||||
// Verificar se já existe um cartão com o mesmo nome e banco para o usuário
|
||||
export async function verificarCartaoExistente(nome: string, banco: string): Promise<boolean> {
|
||||
// Obter o email do usuário do localStorage
|
||||
const userEmail = localStorage.getItem('userEmail');
|
||||
|
||||
if (!userEmail) {
|
||||
console.error('Email do usuário não encontrado no localStorage');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normalizar o email (minúsculo e sem espaços)
|
||||
const normalizedEmail = userEmail.trim().toLowerCase();
|
||||
|
||||
try {
|
||||
const { data, error, count } = await supabase
|
||||
.from('cartoes_credito')
|
||||
.select('*', { count: 'exact' })
|
||||
.eq('login', normalizedEmail)
|
||||
.eq('nome', nome)
|
||||
.eq('banco', banco);
|
||||
|
||||
if (error) {
|
||||
console.error('Erro ao verificar cartão existente:', error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return count ? count > 0 : false;
|
||||
} catch (error) {
|
||||
console.error('Erro ao verificar cartão existente:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Função para criar um novo cartão de crédito
|
||||
export async function criarCartao(nome: string): Promise<CartaoCredito | null> {
|
||||
export async function criarCartao(nome: string, bandeira: string, banco: string, cartao_codigo: string): Promise<CartaoCredito | null> {
|
||||
// Obter o email do usuário do localStorage
|
||||
const userEmail = localStorage.getItem('userEmail');
|
||||
// Obter o ID do usuário do localStorage (mantido por compatibilidade)
|
||||
@ -56,11 +89,20 @@ export async function criarCartao(nome: string): Promise<CartaoCredito | null> {
|
||||
// Normalizar o email (minúsculo e sem espaços)
|
||||
const normalizedEmail = userEmail.trim().toLowerCase();
|
||||
|
||||
// Verificar se já existe um cartão com o mesmo nome e banco
|
||||
const cartaoExistente = await verificarCartaoExistente(nome, banco);
|
||||
if (cartaoExistente) {
|
||||
throw new Error(`Você já possui um cartão ${nome} do banco ${banco}.`);
|
||||
}
|
||||
|
||||
try {
|
||||
const { data, error } = await supabase
|
||||
.from('cartoes_credito')
|
||||
.insert([{
|
||||
nome: nome,
|
||||
bandeira: bandeira,
|
||||
banco: banco,
|
||||
cartao_codigo: cartao_codigo,
|
||||
user_id: userId,
|
||||
login: normalizedEmail
|
||||
}])
|
||||
@ -74,7 +116,7 @@ export async function criarCartao(nome: string): Promise<CartaoCredito | null> {
|
||||
return data[0];
|
||||
} catch (error) {
|
||||
console.error('Erro ao criar cartão:', error);
|
||||
return null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,12 +142,24 @@ export async function getCartao(cartaoId: string): Promise<CartaoCredito | null>
|
||||
}
|
||||
|
||||
// Função para buscar despesas de um cartão
|
||||
export async function getDespesasCartao(cartaoId: string): Promise<DespesaCartao[]> {
|
||||
export async function getDespesasCartao(cartaoCodigo: string): Promise<DespesaCartao[]> {
|
||||
// Obter o email do usuário do localStorage
|
||||
const userEmail = localStorage.getItem('userEmail');
|
||||
|
||||
if (!userEmail) {
|
||||
console.error('Email do usuário não encontrado no localStorage');
|
||||
return [];
|
||||
}
|
||||
|
||||
// Normalizar o email (minúsculo e sem espaços)
|
||||
const normalizedEmail = userEmail.trim().toLowerCase();
|
||||
|
||||
try {
|
||||
const { data, error } = await supabase
|
||||
.from('despesas_cartao')
|
||||
.select('*')
|
||||
.eq('cartao_id', cartaoId)
|
||||
.eq('cartao_codigo', cartaoCodigo)
|
||||
.eq('login', normalizedEmail)
|
||||
.order('data_despesa', { ascending: false });
|
||||
|
||||
if (error) {
|
||||
@ -121,15 +175,31 @@ export async function getDespesasCartao(cartaoId: string): Promise<DespesaCartao
|
||||
}
|
||||
|
||||
// Função para criar uma nova despesa no cartão
|
||||
export async function criarDespesa(cartaoId: string, valor: number, data_despesa: string, descricao: string): Promise<DespesaCartao | null> {
|
||||
export async function criarDespesa(cartao_id: string, cartao_codigo: string, valor: number, data_despesa: string, descricao: string): Promise<DespesaCartao | null> {
|
||||
// Obter o email do usuário do localStorage
|
||||
const userEmail = localStorage.getItem('userEmail');
|
||||
// Obter o ID do usuário do localStorage (mantido por compatibilidade)
|
||||
const userId = localStorage.getItem('userId');
|
||||
|
||||
if (!userEmail || !userId) {
|
||||
console.error('Dados do usuário não encontrados no localStorage');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Normalizar o email (minúsculo e sem espaços)
|
||||
const normalizedEmail = userEmail.trim().toLowerCase();
|
||||
|
||||
try {
|
||||
const { data, error } = await supabase
|
||||
.from('despesas_cartao')
|
||||
.insert([{
|
||||
cartao_id: cartaoId,
|
||||
cartao_id: cartao_id,
|
||||
cartao_codigo: cartao_codigo,
|
||||
valor: valor,
|
||||
data_despesa: data_despesa,
|
||||
descricao: descricao
|
||||
descricao: descricao,
|
||||
login: normalizedEmail,
|
||||
user_id: userId
|
||||
}])
|
||||
.select();
|
||||
|
||||
@ -146,12 +216,24 @@ export async function criarDespesa(cartaoId: string, valor: number, data_despesa
|
||||
}
|
||||
|
||||
// Função para calcular o total de despesas de um cartão
|
||||
export async function getTotalDespesasCartao(cartaoId: string): Promise<number> {
|
||||
export async function getTotalDespesasCartao(cartaoCodigo: string): Promise<number> {
|
||||
// Obter o email do usuário do localStorage
|
||||
const userEmail = localStorage.getItem('userEmail');
|
||||
|
||||
if (!userEmail) {
|
||||
console.error('Email do usuário não encontrado no localStorage');
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Normalizar o email (minúsculo e sem espaços)
|
||||
const normalizedEmail = userEmail.trim().toLowerCase();
|
||||
|
||||
try {
|
||||
const { data, error } = await supabase
|
||||
.from('despesas_cartao')
|
||||
.select('valor')
|
||||
.eq('cartao_id', cartaoId);
|
||||
.eq('cartao_codigo', cartaoCodigo)
|
||||
.eq('login', normalizedEmail);
|
||||
|
||||
if (error) {
|
||||
console.error('Erro ao calcular total de despesas:', error);
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
export interface CartaoCredito {
|
||||
id: string;
|
||||
nome: string;
|
||||
bandeira?: string;
|
||||
banco?: string;
|
||||
cartao_codigo: string;
|
||||
user_id: string;
|
||||
login?: string;
|
||||
created_at: string;
|
||||
@ -11,6 +14,9 @@ export interface CartaoCredito {
|
||||
export interface DespesaCartao {
|
||||
id: string;
|
||||
cartao_id: string;
|
||||
cartao_codigo: string;
|
||||
user_id?: string;
|
||||
login?: string;
|
||||
valor: number;
|
||||
data_despesa: string;
|
||||
descricao: string;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user