import React, { useState, useEffect, useRef } from 'react'; import { QrCode, Send, CheckCircle2, AlertCircle, Loader2, Terminal, Users, MessageSquare, Play, Lock, LogOut } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; interface Group { id: { _serialized: string; user: string; }; name: string; } function App() { const [passkey, setPasskey] = useState(localStorage.getItem('passkey') || ''); const [isLoggedIn, setIsLoggedIn] = useState(false); const [isCheckingAuth, setIsCheckingAuth] = useState(true); const [loginError, setLoginError] = useState(''); const [status, setStatus] = useState('DISCONNECTED'); const [qrCode, setQrCode] = useState(''); const [logs, setLogs] = useState([]); const [message, setMessage] = useState(''); const [phone, setPhone] = useState(''); const [groups, setGroups] = useState([]); const [selectedGroup, setSelectedGroup] = useState(''); const [isSending, setIsSending] = useState(false); const [activeTab, setActiveTab] = useState<'direct' | 'group'>('direct'); const [template, setTemplate] = useState<'normal' | 'poll' | 'date'>('normal'); const [pollName, setPollName] = useState(''); const [pollOptions, setPollOptions] = useState(['', '']); const [links, setLinks] = useState(''); const logsEndRef = useRef(null); const fetchWithAuth = async (url: string, options: RequestInit = {}) => { const headers = { ...options.headers, 'x-passkey': passkey, 'Content-Type': 'application/json' }; const response = await fetch(url, { ...options, headers }); if (response.status === 401) { handleLogout(); throw new Error('Unauthorized'); } return response; }; const handleLogin = async (e: React.FormEvent) => { e.preventDefault(); setLoginError(''); try { const res = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ passkey }) }); const data = await res.json(); if (data.success) { localStorage.setItem('passkey', passkey); setIsLoggedIn(true); } else { setLoginError('Invalid passkey'); } } catch (err) { setLoginError('Failed to connect to server'); } }; const handleLogout = () => { localStorage.removeItem('passkey'); setPasskey(''); setIsLoggedIn(false); }; useEffect(() => { const checkAuth = async () => { const savedPasskey = localStorage.getItem('passkey'); if (savedPasskey) { try { const res = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ passkey: savedPasskey }) }); const data = await res.json(); if (data.success) { setIsLoggedIn(true); } else { localStorage.removeItem('passkey'); } } catch (err) { console.error('Auth check failed', err); } } setIsCheckingAuth(false); }; checkAuth(); }, []); useEffect(() => { if (!isLoggedIn) return; const interval = setInterval(async () => { try { const res = await fetchWithAuth('/api/status'); const data = await res.json(); setStatus(data.status); setQrCode(data.qrCode); setLogs(data.logs); } catch (error) { console.error('Failed to fetch status', error); } }, 2000); return () => clearInterval(interval); }, [isLoggedIn, passkey]); useEffect(() => { logsEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [logs]); const startService = async () => { try { await fetchWithAuth('/api/start', { method: 'POST' }); } catch (error) { console.error('Failed to start service', error); } }; const fetchGroups = async () => { try { const res = await fetchWithAuth('/api/groups'); const data = await res.json(); if (data.success) setGroups(data.groups); } catch (error) { console.error('Failed to fetch groups', error); } }; const handleSend = async (e: React.FormEvent) => { e.preventDefault(); setIsSending(true); try { let endpoint = '/api/send'; let body: any = { message: template === 'date' ? `${message}\n\n${links}` : message, isGroup: activeTab === 'group' }; if (activeTab === 'direct') { body.phone = phone; } else { body.phone = selectedGroup; } if (template === 'poll') { endpoint = '/api/send-poll'; body = { recipient: body.phone, pollName, options: pollOptions.filter(o => o.trim() !== ''), isGroup: activeTab === 'group' }; } const res = await fetchWithAuth(endpoint, { method: 'POST', body: JSON.stringify(body) }); const result = await res.json(); if (result.success) { alert('Message sent successfully!'); if (template === 'poll') { setPollName(''); setPollOptions(['', '']); } else { setMessage(''); setLinks(''); } } else { alert('Error: ' + result.error); } } catch (error) { alert('Failed to send message'); } finally { setIsSending(false); } }; if (isCheckingAuth) { return (
); } if (!isLoggedIn) { return (

Dashboard Access

Enter your passkey to access the WPPConnect dashboard

setPasskey(e.target.value)} className="w-full px-4 py-3 border border-gray-300 rounded-xl focus:ring-2 focus:ring-orange-500 focus:border-orange-500 outline-none transition-all" autoFocus />
{loginError && (

{loginError}

)}
); } return (
{/* Header */}

WPPConnect Portal

{status}
{/* Left Column: Messaging Control */}
{status !== 'CONNECTED' ? (

Not Connected

Please authenticate with WhatsApp to start messaging.

) : (
{activeTab === 'direct' ? (
setPhone(e.target.value)} className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-orange-500 focus:border-orange-500 outline-none transition-all" />
) : (
setSelectedGroup(e.target.value)} disabled={status !== 'CONNECTED'} className="flex-1 px-4 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-orange-500 focus:border-orange-500 outline-none" />
)}
{(['normal', 'poll', 'date'] as const).map((t) => ( ))}
{template === 'poll' ? (
setPollName(e.target.value)} className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-orange-500 focus:border-orange-500 outline-none" />
{pollOptions.map((opt, idx) => (
{ const newOpts = [...pollOptions]; newOpts[idx] = e.target.value; setPollOptions(newOpts); }} className="flex-1 px-4 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-orange-500 focus:border-orange-500 outline-none" /> {pollOptions.length > 2 && ( )}
))}
) : (