feat: Implement WhatsApp group creation and instance management
- Implemented POST request to Evolution API for WhatsApp group creation on "Cadastrar Grupo" button click. - Added "Desconectar Instância" button with disconnection logic and Supabase update. - Hid debug information in the "Grupos" menu. - Changed app name to "Finance Home". - Added hover color to sidebar menu items.
This commit is contained in:
parent
a097f05a74
commit
7f202972b2
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
import { Link, NavLink, useLocation } from 'react-router-dom';
|
import { Link, NavLink, useLocation } from 'react-router-dom';
|
||||||
import { useIsMobile } from '@/hooks/use-mobile';
|
import { useIsMobile } from '@/hooks/use-mobile';
|
||||||
import {
|
import {
|
||||||
@ -23,8 +24,8 @@ interface SidebarProps {
|
|||||||
|
|
||||||
const getNavLinkClass = (isActive: boolean) => {
|
const getNavLinkClass = (isActive: boolean) => {
|
||||||
return cn(
|
return cn(
|
||||||
"group flex items-center rounded-md px-3 py-2 text-sm font-medium hover:bg-secondary hover:text-foreground",
|
"group flex items-center rounded-md px-3 py-2 text-sm font-medium transition-all duration-200 hover:bg-gradient-to-r hover:from-blue-50 hover:to-indigo-50 hover:text-blue-700 hover:scale-105 hover:shadow-sm",
|
||||||
isActive ? "bg-secondary text-foreground" : "text-muted-foreground"
|
isActive ? "bg-gradient-to-r from-blue-100 to-indigo-100 text-blue-700 shadow-sm" : "text-muted-foreground"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,8 +39,8 @@ export default function Sidebar({ isOpen, onClose }: SidebarProps) {
|
|||||||
isMobile ? 'fixed left-0 top-0 z-50 w-full transition-all duration-300' : 'relative'
|
isMobile ? 'fixed left-0 top-0 z-50 w-full transition-all duration-300' : 'relative'
|
||||||
)}>
|
)}>
|
||||||
<div className="flex items-center justify-between px-4 py-2">
|
<div className="flex items-center justify-between px-4 py-2">
|
||||||
<Link to="/" className="flex items-center space-x-2 font-semibold">
|
<Link to="/" className="flex items-center space-x-2 font-semibold text-blue-700 hover:text-blue-800 transition-colors">
|
||||||
<span>FinDash</span>
|
<span className="text-lg">Finance Home</span>
|
||||||
</Link>
|
</Link>
|
||||||
{isMobile && (
|
{isMobile && (
|
||||||
<Button variant="ghost" size="icon" onClick={onClose}>
|
<Button variant="ghost" size="icon" onClick={onClose}>
|
||||||
@ -56,7 +57,7 @@ export default function Sidebar({ isOpen, onClose }: SidebarProps) {
|
|||||||
className={({ isActive }) => getNavLinkClass(isActive)}
|
className={({ isActive }) => getNavLinkClass(isActive)}
|
||||||
onClick={isMobile ? onClose : undefined}
|
onClick={isMobile ? onClose : undefined}
|
||||||
>
|
>
|
||||||
<Home className="mr-2 h-4 w-4" />
|
<Home className="mr-2 h-4 w-4 transition-transform group-hover:scale-110" />
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink
|
<NavLink
|
||||||
@ -64,7 +65,7 @@ export default function Sidebar({ isOpen, onClose }: SidebarProps) {
|
|||||||
className={({ isActive }) => getNavLinkClass(isActive)}
|
className={({ isActive }) => getNavLinkClass(isActive)}
|
||||||
onClick={isMobile ? onClose : undefined}
|
onClick={isMobile ? onClose : undefined}
|
||||||
>
|
>
|
||||||
<Receipt className="mr-2 h-4 w-4" />
|
<Receipt className="mr-2 h-4 w-4 transition-transform group-hover:scale-110" />
|
||||||
<span>Transações</span>
|
<span>Transações</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink
|
<NavLink
|
||||||
@ -72,7 +73,7 @@ export default function Sidebar({ isOpen, onClose }: SidebarProps) {
|
|||||||
className={({ isActive }) => getNavLinkClass(isActive)}
|
className={({ isActive }) => getNavLinkClass(isActive)}
|
||||||
onClick={isMobile ? onClose : undefined}
|
onClick={isMobile ? onClose : undefined}
|
||||||
>
|
>
|
||||||
<CreditCard className="mr-2 h-4 w-4" />
|
<CreditCard className="mr-2 h-4 w-4 transition-transform group-hover:scale-110" />
|
||||||
<span>Cartões de Crédito</span>
|
<span>Cartões de Crédito</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink
|
<NavLink
|
||||||
@ -80,7 +81,7 @@ export default function Sidebar({ isOpen, onClose }: SidebarProps) {
|
|||||||
className={({ isActive }) => getNavLinkClass(isActive)}
|
className={({ isActive }) => getNavLinkClass(isActive)}
|
||||||
onClick={isMobile ? onClose : undefined}
|
onClick={isMobile ? onClose : undefined}
|
||||||
>
|
>
|
||||||
<ListFilter className="mr-2 h-4 w-4" />
|
<ListFilter className="mr-2 h-4 w-4 transition-transform group-hover:scale-110" />
|
||||||
<span>Categorias</span>
|
<span>Categorias</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink
|
<NavLink
|
||||||
@ -88,7 +89,7 @@ export default function Sidebar({ isOpen, onClose }: SidebarProps) {
|
|||||||
className={({ isActive }) => getNavLinkClass(isActive)}
|
className={({ isActive }) => getNavLinkClass(isActive)}
|
||||||
onClick={isMobile ? onClose : undefined}
|
onClick={isMobile ? onClose : undefined}
|
||||||
>
|
>
|
||||||
<Target className="mr-2 h-4 w-4" />
|
<Target className="mr-2 h-4 w-4 transition-transform group-hover:scale-110" />
|
||||||
<span>Metas</span>
|
<span>Metas</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink
|
<NavLink
|
||||||
@ -96,14 +97,14 @@ export default function Sidebar({ isOpen, onClose }: SidebarProps) {
|
|||||||
className={({ isActive }) => getNavLinkClass(isActive)}
|
className={({ isActive }) => getNavLinkClass(isActive)}
|
||||||
onClick={isMobile ? onClose : undefined}
|
onClick={isMobile ? onClose : undefined}
|
||||||
>
|
>
|
||||||
<Calendar className="mr-2 h-4 w-4" />
|
<Calendar className="mr-2 h-4 w-4 transition-transform group-hover:scale-110" />
|
||||||
<span>Calendário</span>
|
<span>Calendário</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="px-3 py-2">
|
<div className="px-3 py-2">
|
||||||
<h2 className="mb-2 px-3 text-sm font-semibold tracking-tight">
|
<h2 className="mb-2 px-3 text-sm font-semibold tracking-tight text-gray-600">
|
||||||
WhatsApp
|
WhatsApp
|
||||||
</h2>
|
</h2>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
@ -112,7 +113,7 @@ export default function Sidebar({ isOpen, onClose }: SidebarProps) {
|
|||||||
className={({ isActive }) => getNavLinkClass(isActive)}
|
className={({ isActive }) => getNavLinkClass(isActive)}
|
||||||
onClick={isMobile ? onClose : undefined}
|
onClick={isMobile ? onClose : undefined}
|
||||||
>
|
>
|
||||||
<MessageSquareText className="mr-2 h-4 w-4" />
|
<MessageSquareText className="mr-2 h-4 w-4 transition-transform group-hover:scale-110" />
|
||||||
<span>Conectar WhatsApp</span>
|
<span>Conectar WhatsApp</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<NavLink
|
<NavLink
|
||||||
@ -120,13 +121,13 @@ export default function Sidebar({ isOpen, onClose }: SidebarProps) {
|
|||||||
className={({ isActive }) => getNavLinkClass(isActive)}
|
className={({ isActive }) => getNavLinkClass(isActive)}
|
||||||
onClick={isMobile ? onClose : undefined}
|
onClick={isMobile ? onClose : undefined}
|
||||||
>
|
>
|
||||||
<Users className="mr-2 h-4 w-4" />
|
<Users className="mr-2 h-4 w-4 transition-transform group-hover:scale-110" />
|
||||||
<span>Grupos</span>
|
<span>Grupos</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-3 py-2">
|
<div className="px-3 py-2">
|
||||||
<h2 className="mb-2 px-3 text-sm font-semibold tracking-tight">
|
<h2 className="mb-2 px-3 text-sm font-semibold tracking-tight text-gray-600">
|
||||||
Configurações
|
Configurações
|
||||||
</h2>
|
</h2>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
@ -135,7 +136,7 @@ export default function Sidebar({ isOpen, onClose }: SidebarProps) {
|
|||||||
className={({ isActive }) => getNavLinkClass(isActive)}
|
className={({ isActive }) => getNavLinkClass(isActive)}
|
||||||
onClick={isMobile ? onClose : undefined}
|
onClick={isMobile ? onClose : undefined}
|
||||||
>
|
>
|
||||||
<Settings className="mr-2 h-4 w-4" />
|
<Settings className="mr-2 h-4 w-4 transition-transform group-hover:scale-110" />
|
||||||
<span>Configurações</span>
|
<span>Configurações</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -7,7 +7,8 @@ import {
|
|||||||
PowerOff,
|
PowerOff,
|
||||||
CircleDot,
|
CircleDot,
|
||||||
CircleOff,
|
CircleOff,
|
||||||
X
|
X,
|
||||||
|
Unplug
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { WhatsAppInstance } from "@/types/whatsAppTypes";
|
import { WhatsAppInstance } from "@/types/whatsAppTypes";
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ interface InstanceActionsProps {
|
|||||||
onViewQrCode: (instance: WhatsAppInstance) => void;
|
onViewQrCode: (instance: WhatsAppInstance) => void;
|
||||||
onRestart: () => void;
|
onRestart: () => void;
|
||||||
onLogout: () => void;
|
onLogout: () => void;
|
||||||
|
onDisconnect?: () => void;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
onSetOnline: () => void;
|
onSetOnline: () => void;
|
||||||
onSetOffline: () => void;
|
onSetOffline: () => void;
|
||||||
@ -28,10 +30,13 @@ const InstanceActions = ({
|
|||||||
onViewQrCode,
|
onViewQrCode,
|
||||||
onRestart,
|
onRestart,
|
||||||
onLogout,
|
onLogout,
|
||||||
|
onDisconnect,
|
||||||
onDelete,
|
onDelete,
|
||||||
onSetOnline,
|
onSetOnline,
|
||||||
onSetOffline,
|
onSetOffline,
|
||||||
}: InstanceActionsProps) => {
|
}: InstanceActionsProps) => {
|
||||||
|
const isConnected = instance.connectionState === 'open' || instance.status === 'connected';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex justify-between w-full">
|
<div className="flex justify-between w-full">
|
||||||
@ -55,6 +60,7 @@ const InstanceActions = ({
|
|||||||
Excluir
|
Excluir
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-2 w-full">
|
<div className="grid grid-cols-2 gap-2 w-full">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@ -75,6 +81,21 @@ const InstanceActions = ({
|
|||||||
Desconectar
|
Desconectar
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Botão de desconectar instância - apenas quando conectada */}
|
||||||
|
{isConnected && onDisconnect && (
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={onDisconnect}
|
||||||
|
disabled={loading !== null}
|
||||||
|
className="w-full bg-orange-50 hover:bg-orange-100 text-orange-700 border-orange-200"
|
||||||
|
>
|
||||||
|
<Unplug className="h-4 w-4 mr-1" />
|
||||||
|
Desconectar Instância
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-2 w-full">
|
<div className="grid grid-cols-2 gap-2 w-full">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
|
|||||||
@ -13,6 +13,7 @@ interface InstanceCardProps {
|
|||||||
onDelete: (instanceId: string) => void;
|
onDelete: (instanceId: string) => void;
|
||||||
onRestart: (instance: WhatsAppInstance) => Promise<void>;
|
onRestart: (instance: WhatsAppInstance) => Promise<void>;
|
||||||
onLogout: (instance: WhatsAppInstance) => Promise<void>;
|
onLogout: (instance: WhatsAppInstance) => Promise<void>;
|
||||||
|
onDisconnect?: (instance: WhatsAppInstance) => Promise<void>;
|
||||||
onSetPresence: (instance: WhatsAppInstance, presence: 'online' | 'offline') => Promise<void>;
|
onSetPresence: (instance: WhatsAppInstance, presence: 'online' | 'offline') => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ const InstanceCard = ({
|
|||||||
onDelete,
|
onDelete,
|
||||||
onRestart,
|
onRestart,
|
||||||
onLogout,
|
onLogout,
|
||||||
|
onDisconnect,
|
||||||
onSetPresence
|
onSetPresence
|
||||||
}: InstanceCardProps) => {
|
}: InstanceCardProps) => {
|
||||||
const [loading, setLoading] = useState<string | null>(null);
|
const [loading, setLoading] = useState<string | null>(null);
|
||||||
@ -88,6 +90,22 @@ const InstanceCard = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handler para desconectar instância permanentemente
|
||||||
|
const handleDisconnect = () => {
|
||||||
|
if (!onDisconnect) return;
|
||||||
|
|
||||||
|
handleConfirmAction(
|
||||||
|
"Desconectar Instância",
|
||||||
|
`Deseja realmente desconectar a instância "${instance.instanceName}" permanentemente? Esta ação atualizará seu status no banco de dados para "desconectado".`,
|
||||||
|
async () => {
|
||||||
|
if (onDisconnect) {
|
||||||
|
await onDisconnect(instance);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Desconectar"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// Handler para apagar instância
|
// Handler para apagar instância
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
handleConfirmAction(
|
handleConfirmAction(
|
||||||
@ -169,6 +187,7 @@ const InstanceCard = ({
|
|||||||
onViewQrCode={onViewQrCode}
|
onViewQrCode={onViewQrCode}
|
||||||
onRestart={handleRestart}
|
onRestart={handleRestart}
|
||||||
onLogout={handleLogout}
|
onLogout={handleLogout}
|
||||||
|
onDisconnect={onDisconnect ? handleDisconnect : undefined}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
onSetOnline={handleSetOnline}
|
onSetOnline={handleSetOnline}
|
||||||
onSetOffline={handleSetOffline}
|
onSetOffline={handleSetOffline}
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
|
||||||
import InstanceCard from './InstanceCard';
|
|
||||||
import { WhatsAppInstance } from '@/types/whatsAppTypes';
|
import { WhatsAppInstance } from '@/types/whatsAppTypes';
|
||||||
import { RefreshCw } from 'lucide-react';
|
import InstanceCard from './InstanceCard';
|
||||||
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
|
import { Loader2 } from 'lucide-react';
|
||||||
|
|
||||||
interface InstanceListProps {
|
interface InstanceListProps {
|
||||||
instances: WhatsAppInstance[];
|
instances: WhatsAppInstance[];
|
||||||
@ -11,41 +10,42 @@ interface InstanceListProps {
|
|||||||
onDelete: (instanceId: string) => void;
|
onDelete: (instanceId: string) => void;
|
||||||
onRestart: (instance: WhatsAppInstance) => Promise<void>;
|
onRestart: (instance: WhatsAppInstance) => Promise<void>;
|
||||||
onLogout: (instance: WhatsAppInstance) => Promise<void>;
|
onLogout: (instance: WhatsAppInstance) => Promise<void>;
|
||||||
|
onDisconnect?: (instance: WhatsAppInstance) => Promise<void>;
|
||||||
onSetPresence: (instance: WhatsAppInstance, presence: 'online' | 'offline') => Promise<void>;
|
onSetPresence: (instance: WhatsAppInstance, presence: 'online' | 'offline') => Promise<void>;
|
||||||
onRefreshInstances: () => Promise<void>;
|
onRefreshInstances: () => void;
|
||||||
isRefreshing: boolean;
|
isRefreshing: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InstanceList = ({
|
const InstanceList = ({
|
||||||
instances,
|
instances,
|
||||||
onViewQrCode,
|
onViewQrCode,
|
||||||
onDelete,
|
onDelete,
|
||||||
onRestart,
|
onRestart,
|
||||||
onLogout,
|
onLogout,
|
||||||
|
onDisconnect,
|
||||||
onSetPresence,
|
onSetPresence,
|
||||||
onRefreshInstances,
|
onRefreshInstances,
|
||||||
isRefreshing
|
isRefreshing
|
||||||
}: InstanceListProps) => {
|
}: InstanceListProps) => {
|
||||||
// Safely check if instances is an array and has elements
|
|
||||||
const hasInstances = Array.isArray(instances) && instances.length > 0;
|
if (isRefreshing && instances.length === 0) {
|
||||||
|
|
||||||
if (!hasInstances) {
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent className="py-6">
|
<CardContent className="flex items-center justify-center py-8">
|
||||||
|
<Loader2 className="h-6 w-6 animate-spin mr-2" />
|
||||||
|
<span>Carregando instâncias...</span>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instances.length === 0) {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardContent className="flex items-center justify-center py-8">
|
||||||
<div className="text-center text-muted-foreground">
|
<div className="text-center text-muted-foreground">
|
||||||
<p>Nenhuma instância criada ainda.</p>
|
<p className="text-lg mb-2">Nenhuma instância encontrada</p>
|
||||||
<p className="mt-1">Clique em 'Atualizar Lista' para buscar novamente.</p>
|
<p className="text-sm">Crie uma nova instância para começar</p>
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
onClick={onRefreshInstances}
|
|
||||||
disabled={isRefreshing}
|
|
||||||
className="mt-4"
|
|
||||||
>
|
|
||||||
<RefreshCw className={`h-4 w-4 mr-2 ${isRefreshing ? 'animate-spin' : ''}`} />
|
|
||||||
{isRefreshing ? 'Atualizando...' : 'Atualizar Lista'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
@ -54,27 +54,23 @@ const InstanceList = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className="text-xl font-semibold">Instâncias Criadas</h2>
|
<h2 className="text-xl font-semibold">Suas Instâncias do WhatsApp</h2>
|
||||||
<Button
|
<span className="text-sm text-muted-foreground">
|
||||||
variant="outline"
|
{instances.length} instância{instances.length !== 1 ? 's' : ''} encontrada{instances.length !== 1 ? 's' : ''}
|
||||||
size="sm"
|
</span>
|
||||||
onClick={onRefreshInstances}
|
|
||||||
disabled={isRefreshing}
|
|
||||||
>
|
|
||||||
<RefreshCw className={`h-4 w-4 mr-2 ${isRefreshing ? 'animate-spin' : ''}`} />
|
|
||||||
{isRefreshing ? 'Atualizando...' : 'Atualizar Lista'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
||||||
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||||
{instances.map((instance) => (
|
{instances.map((instance) => (
|
||||||
<InstanceCard
|
<InstanceCard
|
||||||
key={instance.instanceId}
|
key={instance.instanceId}
|
||||||
instance={instance}
|
instance={instance}
|
||||||
onViewQrCode={onViewQrCode}
|
onViewQrCode={onViewQrCode}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
onRestart={onRestart}
|
onRestart={onRestart}
|
||||||
onLogout={onLogout}
|
onLogout={onLogout}
|
||||||
|
onDisconnect={onDisconnect}
|
||||||
onSetPresence={onSetPresence}
|
onSetPresence={onSetPresence}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -32,66 +32,41 @@ const CreateGroupForm = ({ userEmail, onSuccess }: CreateGroupFormProps) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const checkUserInstance = async () => {
|
const checkUserInstance = async () => {
|
||||||
if (!userEmail) {
|
if (!userEmail) {
|
||||||
console.log('🔍 Email do usuário não fornecido');
|
console.log('Email do usuário não fornecido');
|
||||||
setCheckingInstance(false);
|
setCheckingInstance(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCheckingInstance(true);
|
setCheckingInstance(true);
|
||||||
try {
|
try {
|
||||||
console.log('🔍 === VERIFICAÇÃO DE INSTÂNCIA INICIADA ===');
|
console.log('Verificando instância para:', userEmail);
|
||||||
console.log('🔍 Email fornecido:', userEmail);
|
|
||||||
console.log('🔍 Tipo do email:', typeof userEmail);
|
|
||||||
console.log('🔍 Email length:', userEmail.length);
|
|
||||||
|
|
||||||
// TESTE: Verificar se o email está sendo usado corretamente
|
|
||||||
const emailTrimmed = userEmail.trim().toLowerCase();
|
|
||||||
console.log('📧 Email após trim/lower:', emailTrimmed);
|
|
||||||
|
|
||||||
const instanceData = await getUserWhatsAppInstance(userEmail);
|
const instanceData = await getUserWhatsAppInstance(userEmail);
|
||||||
console.log('📊 === DADOS RETORNADOS DA FUNÇÃO ===');
|
console.log('Dados da instância:', instanceData);
|
||||||
console.log('📊 instanceData completo:', JSON.stringify(instanceData, null, 2));
|
|
||||||
|
|
||||||
if (instanceData) {
|
if (instanceData) {
|
||||||
console.log('🔍 === ANÁLISE DETALHADA DOS DADOS ===');
|
const hasValidInstance = !!(
|
||||||
console.log('✅ instanceData existe:', !!instanceData);
|
instanceData &&
|
||||||
console.log('📝 instancia_zap valor:', instanceData.instancia_zap);
|
instanceData.instancia_zap &&
|
||||||
console.log('📝 instancia_zap tipo:', typeof instanceData.instancia_zap);
|
instanceData.instancia_zap.trim() !== '' &&
|
||||||
console.log('✅ instancia_zap não é null:', instanceData.instancia_zap !== null);
|
instanceData.status_instancia === 'conectado'
|
||||||
console.log('✅ instancia_zap não é vazio após trim:', instanceData.instancia_zap?.trim() !== '');
|
);
|
||||||
console.log('📝 status_instancia valor:', instanceData.status_instancia);
|
|
||||||
console.log('📝 status_instancia tipo:', typeof instanceData.status_instancia);
|
console.log('Instância válida:', hasValidInstance);
|
||||||
console.log('✅ status_instancia é "conectado":', instanceData.status_instancia === 'conectado');
|
|
||||||
} else {
|
if (hasValidInstance) {
|
||||||
console.log('❌ instanceData é null ou undefined');
|
setHasWhatsAppInstance(true);
|
||||||
}
|
setUserInstance(instanceData);
|
||||||
|
} else {
|
||||||
// LÓGICA CORRETA: Verificar se tem instância E se está conectada
|
setHasWhatsAppInstance(false);
|
||||||
const hasValidInstance = !!(
|
setUserInstance(instanceData);
|
||||||
instanceData &&
|
}
|
||||||
instanceData.instancia_zap &&
|
|
||||||
instanceData.instancia_zap.trim() !== '' &&
|
|
||||||
instanceData.status_instancia === 'conectado'
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log('🎯 === RESULTADO FINAL DA VALIDAÇÃO ===');
|
|
||||||
console.log('🎯 hasValidInstance:', hasValidInstance);
|
|
||||||
|
|
||||||
if (hasValidInstance) {
|
|
||||||
setHasWhatsAppInstance(true);
|
|
||||||
setUserInstance(instanceData);
|
|
||||||
console.log('✅ USUÁRIO TEM INSTÂNCIA VÁLIDA - Liberando cadastro de grupo');
|
|
||||||
} else {
|
} else {
|
||||||
setHasWhatsAppInstance(false);
|
setHasWhatsAppInstance(false);
|
||||||
setUserInstance(instanceData);
|
setUserInstance(null);
|
||||||
console.log('❌ USUÁRIO NÃO TEM INSTÂNCIA VÁLIDA:', {
|
|
||||||
temInstanceData: !!instanceData,
|
|
||||||
instancia_zap: instanceData?.instancia_zap || 'NULL',
|
|
||||||
status_instancia: instanceData?.status_instancia || 'NULL'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('💥 ERRO CRÍTICO ao verificar instância do usuário:', error);
|
console.error('Erro ao verificar instância do usuário:', error);
|
||||||
setHasWhatsAppInstance(false);
|
setHasWhatsAppInstance(false);
|
||||||
setUserInstance(null);
|
setUserInstance(null);
|
||||||
} finally {
|
} finally {
|
||||||
@ -142,13 +117,9 @@ const CreateGroupForm = ({ userEmail, onSuccess }: CreateGroupFormProps) => {
|
|||||||
throw new Error('Não foi possível cadastrar o grupo no banco de dados');
|
throw new Error('Não foi possível cadastrar o grupo no banco de dados');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Criar grupo no WhatsApp via API
|
// 2. Criar grupo no WhatsApp via API com os parâmetros corretos
|
||||||
try {
|
try {
|
||||||
const groupResponse = await createWhatsAppGroup(
|
const groupResponse = await createWhatsAppGroup(userEmail);
|
||||||
userInstance.instancia_zap,
|
|
||||||
userEmail,
|
|
||||||
userInstance.whatsapp || ''
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log('Resposta da criação do grupo:', groupResponse);
|
console.log('Resposta da criação do grupo:', groupResponse);
|
||||||
|
|
||||||
@ -229,53 +200,6 @@ const CreateGroupForm = ({ userEmail, onSuccess }: CreateGroupFormProps) => {
|
|||||||
Acesse o menu "Conectar WhatsApp" e realize a conexão primeiro.
|
Acesse o menu "Conectar WhatsApp" e realize a conexão primeiro.
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
||||||
{/* Informações de debug SUPER DETALHADAS */}
|
|
||||||
<div className="mt-4 p-4 bg-gray-100 rounded text-sm">
|
|
||||||
<p><strong>🔧 DEBUG COMPLETO - CONEXÃO COM BANCO:</strong></p>
|
|
||||||
<div className="mt-2 space-y-1">
|
|
||||||
<p><strong>Email original:</strong> {userEmail || 'Não definido'}</p>
|
|
||||||
<p><strong>Email processado:</strong> {userEmail?.trim().toLowerCase() || 'Não processado'}</p>
|
|
||||||
|
|
||||||
<div className="mt-3 p-2 bg-blue-100 rounded">
|
|
||||||
<p><strong>📊 DADOS DO BANCO DE DADOS:</strong></p>
|
|
||||||
{userInstance ? (
|
|
||||||
<>
|
|
||||||
<p><strong>instancia_zap:</strong>
|
|
||||||
<span className={userInstance.instancia_zap ? 'text-green-600' : 'text-red-600'}>
|
|
||||||
"{userInstance.instancia_zap || 'NULL'}" (tipo: {typeof userInstance.instancia_zap})
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p><strong>status_instancia:</strong>
|
|
||||||
<span className={userInstance.status_instancia === 'conectado' ? 'text-green-600' : 'text-red-600'}>
|
|
||||||
"{userInstance.status_instancia || 'NULL'}" (tipo: {typeof userInstance.status_instancia})
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p><strong>whatsapp:</strong> "{userInstance.whatsapp || 'NULL'}"</p>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<p className="text-red-600">❌ Nenhum dado retornado do banco de dados!</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-3 p-2 bg-yellow-100 rounded">
|
|
||||||
<p><strong>🔍 VALIDAÇÕES STEP-BY-STEP:</strong></p>
|
|
||||||
<p>1. Dados existem? {userInstance ? '✅ SIM' : '❌ NÃO'}</p>
|
|
||||||
<p>2. instancia_zap preenchida? {(userInstance?.instancia_zap && userInstance.instancia_zap.trim() !== '') ? '✅ SIM' : '❌ NÃO'}</p>
|
|
||||||
<p>3. Status é "conectado"? {userInstance?.status_instancia === 'conectado' ? '✅ SIM' : '❌ NÃO'}</p>
|
|
||||||
|
|
||||||
{userInstance?.instancia_zap && userInstance?.status_instancia !== 'conectado' && (
|
|
||||||
<p className="text-red-600 font-medium mt-2">
|
|
||||||
⚠️ Instância encontrada mas status incorreto: "{userInstance.status_instancia}"
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-3 text-xs text-gray-600">
|
|
||||||
<p>💡 Abra o Console do navegador (F12) para ver logs detalhados da consulta ao banco de dados</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
@ -336,7 +260,7 @@ const CreateGroupForm = ({ userEmail, onSuccess }: CreateGroupFormProps) => {
|
|||||||
<ul className="list-disc list-inside space-y-1 text-sm text-muted-foreground">
|
<ul className="list-disc list-inside space-y-1 text-sm text-muted-foreground">
|
||||||
<li>O grupo será criado automaticamente no seu WhatsApp</li>
|
<li>O grupo será criado automaticamente no seu WhatsApp</li>
|
||||||
<li>Você será adicionado como participante do grupo</li>
|
<li>Você será adicionado como participante do grupo</li>
|
||||||
<li>O grupo terá o nome: FinDash - {userEmail.split('@')[0]}</li>
|
<li>O grupo terá o nome: finance{userEmail.split('@')[0]}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
logoutInstance,
|
logoutInstance,
|
||||||
deleteInstance,
|
deleteInstance,
|
||||||
setInstancePresence,
|
setInstancePresence,
|
||||||
|
disconnectInstance,
|
||||||
fetchQrCode
|
fetchQrCode
|
||||||
} from '@/services/whatsAppService';
|
} from '@/services/whatsAppService';
|
||||||
|
|
||||||
@ -80,6 +81,43 @@ export const useWhatsAppActions = (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handler for quando uma instância é desconectada permanentemente
|
||||||
|
const handleDisconnectInstance = async (instance: WhatsAppInstance) => {
|
||||||
|
try {
|
||||||
|
console.log(`Attempting to disconnect instance ${instance.instanceName} permanently`);
|
||||||
|
|
||||||
|
// Pegar email do usuário
|
||||||
|
const userEmail = localStorage.getItem('userEmail');
|
||||||
|
if (!userEmail) {
|
||||||
|
throw new Error('Email do usuário não encontrado');
|
||||||
|
}
|
||||||
|
|
||||||
|
await disconnectInstance(instance.instanceName, userEmail);
|
||||||
|
|
||||||
|
// Atualiza o estado da instância para "closed"
|
||||||
|
const updatedInstance = {
|
||||||
|
...instance,
|
||||||
|
connectionState: 'closed' as const,
|
||||||
|
status: 'disconnected'
|
||||||
|
};
|
||||||
|
console.log(`Instance ${instance.instanceName} disconnected permanently, updating instance state`, updatedInstance);
|
||||||
|
updateInstance(updatedInstance);
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "Sucesso",
|
||||||
|
description: `Instância ${instance.instanceName} desconectada permanentemente`
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error disconnecting instance ${instance.instanceName}:`, error);
|
||||||
|
toast({
|
||||||
|
title: "Erro",
|
||||||
|
description: `Falha ao desconectar a instância ${instance.instanceName}`,
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Handler for quando a presença é alterada
|
// Handler for quando a presença é alterada
|
||||||
const handleSetPresence = async (instance: WhatsAppInstance, presence: 'online' | 'offline') => {
|
const handleSetPresence = async (instance: WhatsAppInstance, presence: 'online' | 'offline') => {
|
||||||
@ -179,6 +217,7 @@ export const useWhatsAppActions = (
|
|||||||
setQrDialogOpen,
|
setQrDialogOpen,
|
||||||
handleRestartInstance,
|
handleRestartInstance,
|
||||||
handleLogoutInstance,
|
handleLogoutInstance,
|
||||||
|
handleDisconnectInstance,
|
||||||
handleSetPresence,
|
handleSetPresence,
|
||||||
handleDeleteInstance,
|
handleDeleteInstance,
|
||||||
handleViewQrCode
|
handleViewQrCode
|
||||||
|
|||||||
@ -32,6 +32,7 @@ const WhatsApp = () => {
|
|||||||
setQrDialogOpen,
|
setQrDialogOpen,
|
||||||
handleRestartInstance,
|
handleRestartInstance,
|
||||||
handleLogoutInstance,
|
handleLogoutInstance,
|
||||||
|
handleDisconnectInstance,
|
||||||
handleSetPresence,
|
handleSetPresence,
|
||||||
handleDeleteInstance,
|
handleDeleteInstance,
|
||||||
handleViewQrCode
|
handleViewQrCode
|
||||||
@ -149,6 +150,7 @@ const WhatsApp = () => {
|
|||||||
onDelete={handleDeleteInstanceWrapper}
|
onDelete={handleDeleteInstanceWrapper}
|
||||||
onRestart={handleRestartInstance}
|
onRestart={handleRestartInstance}
|
||||||
onLogout={handleLogoutInstance}
|
onLogout={handleLogoutInstance}
|
||||||
|
onDisconnect={handleDisconnectInstance}
|
||||||
onSetPresence={handleSetPresence}
|
onSetPresence={handleSetPresence}
|
||||||
onRefreshInstances={refreshInstances}
|
onRefreshInstances={refreshInstances}
|
||||||
isRefreshing={isRefreshing}
|
isRefreshing={isRefreshing}
|
||||||
|
|||||||
@ -3,3 +3,6 @@
|
|||||||
export * from './instanceManagement';
|
export * from './instanceManagement';
|
||||||
export * from './instanceActions';
|
export * from './instanceActions';
|
||||||
export * from './localStorage';
|
export * from './localStorage';
|
||||||
|
|
||||||
|
// Import and re-export the disconnect function specifically
|
||||||
|
export { disconnectInstance } from './instanceActions';
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
import { makeRequest } from './apiHelpers';
|
import { makeRequest } from './apiHelpers';
|
||||||
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restarts a WhatsApp instance
|
* Restarts a WhatsApp instance
|
||||||
@ -35,6 +36,38 @@ export const logoutInstance = async (instanceName: string): Promise<any> => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnects a WhatsApp instance and updates database
|
||||||
|
*/
|
||||||
|
export const disconnectInstance = async (instanceName: string, userEmail: string): Promise<any> => {
|
||||||
|
try {
|
||||||
|
console.log(`Disconnecting instance: ${instanceName}`);
|
||||||
|
|
||||||
|
// Primeiro desconecta via API
|
||||||
|
const data = await makeRequest(`/instance/logout/${encodeURIComponent(instanceName)}`, 'DELETE');
|
||||||
|
|
||||||
|
// Depois atualiza o banco de dados
|
||||||
|
const { error } = await supabase
|
||||||
|
.from('usuarios')
|
||||||
|
.update({
|
||||||
|
status_instancia: 'desconectado',
|
||||||
|
instancia_zap: null
|
||||||
|
})
|
||||||
|
.eq('email', userEmail.trim().toLowerCase());
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.error('Erro ao atualizar status no banco:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Instance ${instanceName} disconnected and database updated`);
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error disconnecting instance ${instanceName}:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a WhatsApp instance
|
* Deletes a WhatsApp instance
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -9,24 +9,22 @@ interface CreateGroupResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cria um grupo WhatsApp via API da Evolution
|
* Cria um grupo WhatsApp via API da Evolution usando o padrão correto
|
||||||
*/
|
*/
|
||||||
export async function createWhatsAppGroup(
|
export async function createWhatsAppGroup(
|
||||||
instanceName: string,
|
userEmail: string
|
||||||
userEmail: string,
|
|
||||||
userPhone: string
|
|
||||||
): Promise<CreateGroupResponse> {
|
): Promise<CreateGroupResponse> {
|
||||||
try {
|
try {
|
||||||
// Extrair a parte antes do @ do email
|
// Extrair nome do usuário do email (parte antes do @)
|
||||||
const emailPrefix = userEmail.split('@')[0];
|
const userName = userEmail.split('@')[0];
|
||||||
const groupSubject = `FinDash - ${emailPrefix}`;
|
const groupSubject = `finance${userName}`;
|
||||||
|
|
||||||
const url = `https://evolutionapi2.innova1001.com.br/group/create/${instanceName}`;
|
const url = `https://evolutionapi2.innova1001.com.br/group/create/${userEmail}`;
|
||||||
|
|
||||||
const requestBody = {
|
const requestBody = {
|
||||||
subject: groupSubject,
|
subject: groupSubject,
|
||||||
description: "Seu sistema financeiro Inteligente e Pratico",
|
description: "Finance Home seu controle sem complicação",
|
||||||
participants: [userPhone]
|
participants: ["5561992444275"]
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('Criando grupo WhatsApp:', { url, requestBody });
|
console.log('Criando grupo WhatsApp:', { url, requestBody });
|
||||||
@ -35,6 +33,7 @@ export async function createWhatsAppGroup(
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'beeb77fbd7f48f91db2cd539a573c130'
|
||||||
},
|
},
|
||||||
body: JSON.stringify(requestBody)
|
body: JSON.stringify(requestBody)
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user