diff --git a/src/components/auth/ProtectedRoute.tsx b/src/components/auth/ProtectedRoute.tsx
index 6af17a0..f1f6831 100644
--- a/src/components/auth/ProtectedRoute.tsx
+++ b/src/components/auth/ProtectedRoute.tsx
@@ -125,8 +125,8 @@ const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
return ;
}
- // Se tem sessão mas perfil não está completo, redirecionar para completar perfil
- if (session && !isProfileComplete) {
+ // Se tem sessão mas perfil não está completo E não está na página de completar perfil, redirecionar
+ if (session && !isProfileComplete && location.pathname !== '/complete-profile') {
console.log('🚨 [PROTECTED_ROUTE] Redirecionando para complete-profile - perfil incompleto');
return ;
}
diff --git a/src/hooks/useDespesaCartaoForm.ts b/src/hooks/useDespesaCartaoForm.ts
index ac0da26..b19c796 100644
--- a/src/hooks/useDespesaCartaoForm.ts
+++ b/src/hooks/useDespesaCartaoForm.ts
@@ -5,7 +5,8 @@ import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';
import { useToast } from '@/hooks/use-toast';
import { CartaoCredito } from '@/types/cartaoTypes';
-import { criarDespesa } from '@/services/cartao/despesas'; // Updated import path
+import { criarDespesa } from '@/services/cartao/despesas';
+import { buscarCartaoPorReferencia, gerarCodigoCartao } from '@/services/cartao/cartaoCodigoUtils';
import { format } from 'date-fns';
const despesaCartaoSchema = z.object({
@@ -42,6 +43,7 @@ export function useDespesaCartaoForm({ cartoes, onSuccess, onCancel }: UseDespes
const handleCartaoChange = (cartaoId: string) => {
const cartao = cartoes.find(c => c.id === cartaoId);
setSelectedCartao(cartao || null);
+ console.log('🔄 Cartão selecionado:', cartao?.nome);
};
const formatCartaoLabel = (cartao: CartaoCredito) => {
@@ -66,12 +68,26 @@ export function useDespesaCartaoForm({ cartoes, onSuccess, onCancel }: UseDespes
try {
const formattedDate = format(data.data_despesa, 'yyyy-MM-dd');
- // Garantir que temos um cartao_codigo, mesmo que seja gerado na hora
- const cartaoCodigo = selectedCartao.cartao_codigo || selectedCartao.nome;
+ // Usar busca inteligente para encontrar cartão por referência
+ let cartaoEncontrado = buscarCartaoPorReferencia(cartoes, selectedCartao.nome);
- console.log('Enviando dados para criar despesa:', {
- cartao_id: data.cartao_id,
- cartao_nome: selectedCartao.nome,
+ if (!cartaoEncontrado) {
+ cartaoEncontrado = selectedCartao;
+ console.log('⚠️ Usando cartão selecionado diretamente:', selectedCartao.nome);
+ } else {
+ console.log('✅ Cartão encontrado via busca inteligente:', cartaoEncontrado.nome);
+ }
+
+ // Garantir que temos um cartao_codigo, gerando se necessário
+ let cartaoCodigo = cartaoEncontrado.cartao_codigo;
+ if (!cartaoCodigo) {
+ cartaoCodigo = gerarCodigoCartao(cartaoEncontrado.nome, cartaoEncontrado.banco);
+ console.log('🔧 Código gerado para o cartão:', cartaoCodigo);
+ }
+
+ console.log('📝 Enviando dados para criar despesa:', {
+ cartao_id: cartaoEncontrado.id,
+ cartao_nome: cartaoEncontrado.nome,
cartao_codigo: cartaoCodigo,
valor: data.valor,
data_despesa: formattedDate,
@@ -79,7 +95,7 @@ export function useDespesaCartaoForm({ cartoes, onSuccess, onCancel }: UseDespes
});
const resultado = await criarDespesa(
- data.cartao_id,
+ cartaoEncontrado.id,
cartaoCodigo,
data.valor,
formattedDate,
@@ -100,7 +116,7 @@ export function useDespesaCartaoForm({ cartoes, onSuccess, onCancel }: UseDespes
});
}
} catch (error) {
- console.error('Erro ao processar formulário:', error);
+ console.error('❌ Erro ao processar formulário:', error);
toast({
title: "Erro inesperado",
description: "Ocorreu um erro ao processar sua solicitação",
diff --git a/src/services/cartao/cartaoCodigoUtils.ts b/src/services/cartao/cartaoCodigoUtils.ts
index 6c132fa..435c1d8 100644
--- a/src/services/cartao/cartaoCodigoUtils.ts
+++ b/src/services/cartao/cartaoCodigoUtils.ts
@@ -1,20 +1,113 @@
+import { CartaoCredito } from '@/types/cartaoTypes';
+
/**
- * Utility functions for generating and handling credit card codes
+ * Busca um cartão por código ou nome, usando correspondência flexível
*/
+export const buscarCartaoPorReferencia = (cartoes: CartaoCredito[], referencia: string): CartaoCredito | null => {
+ if (!referencia || cartoes.length === 0) {
+ return null;
+ }
-/**
- * Generates a unique code for a credit card
- * @param nome Card name
- * @param banco Bank name
- * @returns Unique card code
- */
-export function gerarCartaoCodigo(nome: string, banco: string): string {
- const timestamp = new Date().getTime();
- const randomStr = Math.random().toString(36).substring(2, 7);
- // Remove spaces and special characters
- const nomeSanitizado = nome.replace(/[^a-zA-Z0-9]/g, '').substring(0, 8);
- const bancoSanitizado = banco.replace(/[^a-zA-Z0-9]/g, '').substring(0, 5);
+ const referenciaLimpa = referencia.toLowerCase().trim();
- return `${nomeSanitizado}_${bancoSanitizado}_${randomStr}`;
+ // 1. Busca exata por nome
+ let cartaoEncontrado = cartoes.find(cartao =>
+ cartao.nome.toLowerCase().trim() === referenciaLimpa
+ );
+
+ if (cartaoEncontrado) {
+ console.log('🎯 Cartão encontrado por nome exato:', cartaoEncontrado.nome);
+ return cartaoEncontrado;
+ }
+
+ // 2. Busca por palavras-chave no nome (correspondência parcial)
+ const palavrasReferencia = referenciaLimpa.split(' ').filter(p => p.length > 1);
+
+ if (palavrasReferencia.length > 0) {
+ cartaoEncontrado = cartoes.find(cartao => {
+ const nomeCartao = cartao.nome.toLowerCase();
+ return palavrasReferencia.some(palavra => nomeCartao.includes(palavra));
+ });
+
+ if (cartaoEncontrado) {
+ console.log('🎯 Cartão encontrado por palavra-chave:', cartaoEncontrado.nome);
+ return cartaoEncontrado;
+ }
+ }
+
+ // 3. Busca por banco ou bandeira
+ cartaoEncontrado = cartoes.find(cartao => {
+ const banco = cartao.banco?.toLowerCase() || '';
+ const bandeira = cartao.bandeira?.toLowerCase() || '';
+ return banco.includes(referenciaLimpa) || bandeira.includes(referenciaLimpa);
+ });
+
+ if (cartaoEncontrado) {
+ console.log('🎯 Cartão encontrado por banco/bandeira:', cartaoEncontrado.nome);
+ return cartaoEncontrado;
+ }
+
+ // 4. Busca difusa (proximidade de caracteres)
+ cartaoEncontrado = cartoes.find(cartao => {
+ const similarity = calcularSimilaridade(referenciaLimpa, cartao.nome.toLowerCase());
+ return similarity > 0.6; // 60% de similaridade
+ });
+
+ if (cartaoEncontrado) {
+ console.log('🎯 Cartão encontrado por similaridade:', cartaoEncontrado.nome);
+ return cartaoEncontrado;
+ }
+
+ console.log('❌ Nenhum cartão encontrado para referência:', referencia);
+ return null;
+};
+
+/**
+ * Calcula a similaridade entre duas strings usando Levenshtein Distance
+ */
+function calcularSimilaridade(str1: string, str2: string): number {
+ const len1 = str1.length;
+ const len2 = str2.length;
+
+ if (len1 === 0) return len2 === 0 ? 1 : 0;
+ if (len2 === 0) return 0;
+
+ const matrix = Array(len1 + 1).fill(null).map(() => Array(len2 + 1).fill(null));
+
+ for (let i = 0; i <= len1; i++) matrix[i][0] = i;
+ for (let j = 0; j <= len2; j++) matrix[0][j] = j;
+
+ for (let i = 1; i <= len1; i++) {
+ for (let j = 1; j <= len2; j++) {
+ const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
+ matrix[i][j] = Math.min(
+ matrix[i - 1][j] + 1,
+ matrix[i][j - 1] + 1,
+ matrix[i - 1][j - 1] + cost
+ );
+ }
+ }
+
+ const maxLen = Math.max(len1, len2);
+ return 1 - matrix[len1][len2] / maxLen;
}
+
+/**
+ * Gera um código de cartão baseado no nome
+ */
+export const gerarCodigoCartao = (nome: string, banco?: string): string => {
+ const nomeSimplificado = nome
+ .toLowerCase()
+ .replace(/[^a-z0-9\s]/g, '')
+ .replace(/\s+/g, '_')
+ .substring(0, 20);
+
+ const bancoSimplificado = banco
+ ? banco.toLowerCase().replace(/[^a-z0-9]/g, '').substring(0, 10)
+ : '';
+
+ return bancoSimplificado
+ ? `${bancoSimplificado}_${nomeSimplificado}`
+ : nomeSimplificado;
+};