From 1f3197caf510f894b4146bd88ad623e5b0c25cb6 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 02:25:49 +0000 Subject: [PATCH] feat: Move user button and integrate webhook Move the logged-in user button above the month filter on the dashboard. Integrate a webhook call to send contact form data to a specified URL. --- .../dashboard/UserProfileButton.tsx | 97 +++++++++++++++++++ src/components/help/ContactForm.tsx | 31 +++++- src/components/layout/ModernLayout.tsx | 86 ---------------- src/pages/Index.tsx | 13 ++- src/services/webhookService.ts | 70 +++++++++++++ 5 files changed, 205 insertions(+), 92 deletions(-) create mode 100644 src/components/dashboard/UserProfileButton.tsx create mode 100644 src/services/webhookService.ts diff --git a/src/components/dashboard/UserProfileButton.tsx b/src/components/dashboard/UserProfileButton.tsx new file mode 100644 index 0000000..a2a92c1 --- /dev/null +++ b/src/components/dashboard/UserProfileButton.tsx @@ -0,0 +1,97 @@ + +import React, { useState, useEffect } from 'react'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Button } from '@/components/ui/button'; +import { LogOut, User } from 'lucide-react'; +import { supabase } from '@/integrations/supabase/client'; +import { useToast } from '@/hooks/use-toast'; +import { useNavigate } from 'react-router-dom'; + +const UserProfileButton = () => { + const [userEmail, setUserEmail] = useState(''); + const [dropdownOpen, setDropdownOpen] = useState(false); + const { toast } = useToast(); + const navigate = useNavigate(); + + useEffect(() => { + // Buscar dados do usuário logado + const getUserData = async () => { + const { data: { user } } = await supabase.auth.getUser(); + if (user?.email) { + setUserEmail(user.email); + } + }; + + getUserData(); + }, []); + + const handleLogout = async () => { + try { + const { error } = await supabase.auth.signOut(); + if (error) throw error; + + // Limpar localStorage + localStorage.removeItem('userEmail'); + + toast({ + title: "Logout realizado", + description: "Você foi desconectado com sucesso" + }); + + navigate('/auth'); + } catch (error) { + console.error('Erro no logout:', error); + toast({ + title: "Erro no logout", + description: "Ocorreu um erro ao sair da conta", + variant: "destructive" + }); + } + }; + + return ( + + + + + + { + e.preventDefault(); + e.stopPropagation(); + setDropdownOpen(false); + handleLogout(); + }} + className="flex items-center gap-2 text-red-600 hover:text-red-700 hover:bg-red-50 cursor-pointer" + > + + Sair + + + + ); +}; + +export default UserProfileButton; diff --git a/src/components/help/ContactForm.tsx b/src/components/help/ContactForm.tsx index 0d09879..68f9b18 100644 --- a/src/components/help/ContactForm.tsx +++ b/src/components/help/ContactForm.tsx @@ -4,6 +4,7 @@ import { ArrowLeft } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { useToast } from '@/hooks/use-toast'; import { supabase } from '@/integrations/supabase/client'; +import { enviarFaleConoscoParaWebhook } from '@/utils/webhookService'; import ContactFormFields from './ContactFormFields'; import ContactFormHeader from './ContactFormHeader'; @@ -37,6 +38,15 @@ const ContactForm = ({ onBack }: ContactFormProps) => { try { let anexoUrl = null; + let userId = null; + let userEmail = null; + + // Obter dados do usuário + const { data: { user } } = await supabase.auth.getUser(); + if (user) { + userId = user.id; + userEmail = user.email; + } // Upload do anexo se existe if (formData.anexo) { @@ -64,12 +74,31 @@ const ContactForm = ({ onBack }: ContactFormProps) => { motivo: formData.motivo, mensagem: formData.mensagem, anexo_url: anexoUrl, - user_id: (await supabase.auth.getUser()).data.user?.id, + user_id: userId, status: 'pendente' }); if (error) throw error; + // Enviar dados para o webhook do N8N + const webhookData = { + assunto: formData.assunto, + motivo: formData.motivo, + mensagem: formData.mensagem, + anexo_url: anexoUrl, + user_id: userId, + user_email: userEmail, + data_envio: new Date().toISOString() + }; + + try { + await enviarFaleConoscoParaWebhook(webhookData); + console.log("Dados enviados para webhook N8N com sucesso"); + } catch (webhookError) { + console.error("Erro ao enviar para webhook N8N:", webhookError); + // Não interrompe o fluxo se o webhook falhar + } + toast({ title: "Mensagem enviada!", description: "Você vai receber a resposta no e-mail que cadastrou aqui. Obrigado!", diff --git a/src/components/layout/ModernLayout.tsx b/src/components/layout/ModernLayout.tsx index 6abbb27..171ae3c 100644 --- a/src/components/layout/ModernLayout.tsx +++ b/src/components/layout/ModernLayout.tsx @@ -78,10 +78,6 @@ export default function ModernLayout({ children }: ModernLayoutProps) { const [open, setOpen] = useState(false); const location = useLocation(); const isMobile = useIsMobile(); - const { toast } = useToast(); - const navigate = useNavigate(); - const [userEmail, setUserEmail] = useState(''); - const [dropdownOpen, setDropdownOpen] = useState(false); const { isOpen: tourOpen, @@ -91,42 +87,6 @@ export default function ModernLayout({ children }: ModernLayoutProps) { closeTour } = useOnboardingTour(); - useEffect(() => { - // Buscar dados do usuário logado - const getUserData = async () => { - const { data: { user } } = await supabase.auth.getUser(); - if (user?.email) { - setUserEmail(user.email); - } - }; - - getUserData(); - }, []); - - const handleLogout = async () => { - try { - const { error } = await supabase.auth.signOut(); - if (error) throw error; - - // Limpar localStorage - localStorage.removeItem('userEmail'); - - toast({ - title: "Logout realizado", - description: "Você foi desconectado com sucesso" - }); - - navigate('/auth'); - } catch (error) { - console.error('Erro no logout:', error); - toast({ - title: "Erro no logout", - description: "Ocorreu um erro ao sair da conta", - variant: "destructive" - }); - } - }; - const mainLinks = [ { id: "dashboard", @@ -260,52 +220,6 @@ export default function ModernLayout({ children }: ModernLayoutProps) { className="space-y-1" iconContainerClassName={!open ? "justify-center" : ""} /> - - {/* User Profile */} -
- - - - - - { - e.preventDefault(); - e.stopPropagation(); - setDropdownOpen(false); - handleLogout(); - }} - className="flex items-center gap-2 text-red-600 hover:text-red-700 hover:bg-red-50 cursor-pointer" - > - - Sair - - - -
diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index 47a5dee..79026bd 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -1,10 +1,10 @@ - import { useState, useEffect } from 'react'; import Layout from '@/components/layout/Layout'; 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 UserProfileButton from '@/components/dashboard/UserProfileButton'; import { MonthFilter } from '@/components/filters/MonthFilter'; import { OnboardingTour, useOnboardingTour } from '@/components/onboarding'; import { Wallet, ArrowUp, ArrowDown, PiggyBank } from 'lucide-react'; @@ -154,10 +154,13 @@ const Dashboard = () => { Dados de: {formatMonthDisplay(selectedMonth)}

- +
+ + +
{/* Resumo em cards */} diff --git a/src/services/webhookService.ts b/src/services/webhookService.ts new file mode 100644 index 0000000..43b6a7d --- /dev/null +++ b/src/services/webhookService.ts @@ -0,0 +1,70 @@ + +// URL do webhook para notificação de novo cadastro +const WEBHOOK_URL = "https://hook.us1.make.com/j6y1odto82tyo38qv3jh4579kkluhsx7"; + +// URL do webhook para fale conosco +const FALE_CONOSCO_WEBHOOK_URL = "https://webhookn8n.innova1001.com.br/webhook/faleconosco"; + +interface UserData { + nome: string; + empresa?: string; + email: string; + whatsapp?: string; + data_cadastro: string; + origem: string; +} + +interface FaleConoscoData { + assunto: string; + motivo: string; + mensagem: string; + anexo_url?: string; + user_id?: string; + user_email?: string; + data_envio: string; +} + +// Função para enviar dados do usuário para o webhook +export const enviarDadosParaWebhook = async (dadosUsuario: UserData) => { + try { + console.log("Enviando dados do usuário para webhook:", dadosUsuario); + + await fetch(WEBHOOK_URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + mode: 'no-cors', // Necessário para webhooks externos + body: JSON.stringify(dadosUsuario), + }); + + console.log("Dados enviados com sucesso para o webhook"); + } catch (error) { + console.error("Erro ao enviar dados para o webhook:", error); + } +}; + +// Função para enviar dados do Fale Conosco para o webhook do N8N +export const enviarFaleConoscoParaWebhook = async (dadosFaleConosco: FaleConoscoData) => { + try { + console.log("Enviando dados do Fale Conosco para webhook N8N:", dadosFaleConosco); + + const response = await fetch(FALE_CONOSCO_WEBHOOK_URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(dadosFaleConosco), + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + console.log("Dados do Fale Conosco enviados com sucesso para o webhook N8N"); + return true; + } catch (error) { + console.error("Erro ao enviar dados do Fale Conosco para o webhook N8N:", error); + throw error; + } +};