|
|
|
|
|
import { useState, useEffect, useRef } from 'react'; |
|
|
import { io } from 'socket.io-client'; |
|
|
import './App.css'; |
|
|
|
|
|
function App() { |
|
|
const [phoneNumber, setPhoneNumber] = useState(''); |
|
|
const [status, setStatus] = useState(''); |
|
|
const [pairingCode, setPairingCode] = useState(''); |
|
|
const [isConnecting, setIsConnecting] = useState(false); |
|
|
const [logs, setLogs] = useState([]); |
|
|
const socketRef = useRef(null); |
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
const socketUrl = window.location.origin; |
|
|
|
|
|
socketRef.current = io(socketUrl, { |
|
|
autoConnect: true, |
|
|
reconnection: true, |
|
|
reconnectionDelay: 1000, |
|
|
reconnectionAttempts: 5 |
|
|
}); |
|
|
|
|
|
const socket = socketRef.current; |
|
|
|
|
|
socket.on('connect', () => { |
|
|
addLog('β
Connected to server', 'success'); |
|
|
}); |
|
|
|
|
|
socket.on('disconnect', () => { |
|
|
addLog('β Disconnected from server', 'error'); |
|
|
setIsConnecting(false); |
|
|
}); |
|
|
|
|
|
socket.on('status', (data) => { |
|
|
setStatus(data.message); |
|
|
addLog(`βΉοΈ ${data.message}`, 'info'); |
|
|
}); |
|
|
|
|
|
socket.on('pairing-code', (data) => { |
|
|
setPairingCode(data.code); |
|
|
setStatus('Pairing code generated successfully!'); |
|
|
addLog(`π Pairing Code: ${data.code}`, 'success'); |
|
|
}); |
|
|
|
|
|
socket.on('success', (data) => { |
|
|
setStatus(data.message); |
|
|
addLog(`β
${data.message}`, 'success'); |
|
|
setIsConnecting(false); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
resetForm(); |
|
|
}, 3000); |
|
|
}); |
|
|
|
|
|
socket.on('error', (data) => { |
|
|
setStatus(`Error: ${data.message}`); |
|
|
addLog(`β ${data.message}`, 'error'); |
|
|
setIsConnecting(false); |
|
|
setPairingCode(''); |
|
|
}); |
|
|
|
|
|
return () => { |
|
|
socket.disconnect(); |
|
|
}; |
|
|
}, []); |
|
|
|
|
|
const addLog = (message, type = 'info') => { |
|
|
const timestamp = new Date().toLocaleTimeString(); |
|
|
setLogs(prev => [...prev, { message, type, timestamp }]); |
|
|
}; |
|
|
|
|
|
const resetForm = () => { |
|
|
setPhoneNumber(''); |
|
|
setPairingCode(''); |
|
|
setStatus(''); |
|
|
setIsConnecting(false); |
|
|
}; |
|
|
|
|
|
const handleSubmit = (e) => { |
|
|
e.preventDefault(); |
|
|
|
|
|
if (!phoneNumber.trim()) { |
|
|
setStatus('Phone number cannot be empty!'); |
|
|
addLog('β Phone number cannot be empty', 'error'); |
|
|
return; |
|
|
} |
|
|
|
|
|
const cleanNumber = phoneNumber.replace(/[^\d]/g, ''); |
|
|
|
|
|
if (cleanNumber.length < 10 || cleanNumber.length > 15) { |
|
|
setStatus('Invalid phone number! Must be 10-15 digits'); |
|
|
addLog('β Invalid phone number format', 'error'); |
|
|
return; |
|
|
} |
|
|
|
|
|
if (cleanNumber.startsWith('0')) { |
|
|
setStatus('Phone number must include country code (e.g., 1, 44, 62, 91)'); |
|
|
addLog('β Country code required', 'error'); |
|
|
return; |
|
|
} |
|
|
|
|
|
setIsConnecting(true); |
|
|
setPairingCode(''); |
|
|
setStatus('Starting pairing process...'); |
|
|
setLogs([]); |
|
|
|
|
|
addLog('π Initiating connection...', 'info'); |
|
|
socketRef.current.emit('start-pairing', { phoneNumber: cleanNumber }); |
|
|
}; |
|
|
|
|
|
const handlePhoneChange = (e) => { |
|
|
const value = e.target.value.replace(/[^\d+]/g, ''); |
|
|
setPhoneNumber(value); |
|
|
}; |
|
|
|
|
|
const copyCode = () => { |
|
|
navigator.clipboard.writeText(pairingCode); |
|
|
addLog('π Pairing code copied!', 'success'); |
|
|
}; |
|
|
|
|
|
return ( |
|
|
<div className="container"> |
|
|
<div className="card"> |
|
|
<div className="header"> |
|
|
<h1>π€ WA Pairing Service</h1> |
|
|
<p>Get your WhatsApp bot session easily</p> |
|
|
</div> |
|
|
|
|
|
<form onSubmit={handleSubmit} className="form"> |
|
|
<div className="input-group"> |
|
|
<label htmlFor="phone">WhatsApp Bot Number</label> |
|
|
<input |
|
|
type="text" |
|
|
id="phone" |
|
|
value={phoneNumber} |
|
|
onChange={handlePhoneChange} |
|
|
placeholder="12025551234 (with country code)" |
|
|
disabled={isConnecting} |
|
|
maxLength={16} |
|
|
className="input" |
|
|
/> |
|
|
<small>Include country code (e.g., 1 for US, 44 for UK, 62 for ID, 91 for IN)</small> |
|
|
</div> |
|
|
|
|
|
<button |
|
|
type="submit" |
|
|
disabled={isConnecting} |
|
|
className={`button ${isConnecting ? 'loading' : ''}`} |
|
|
> |
|
|
{isConnecting ? 'β³ Processing...' : 'π Start Pairing'} |
|
|
</button> |
|
|
</form> |
|
|
|
|
|
{pairingCode && ( |
|
|
<div className="pairing-code"> |
|
|
<h3>Pairing Code</h3> |
|
|
<div className="code-display"> |
|
|
<span className="code">{pairingCode}</span> |
|
|
<button onClick={copyCode} className="copy-btn" title="Copy"> |
|
|
π |
|
|
</button> |
|
|
</div> |
|
|
<div className="instructions"> |
|
|
<p>Next steps:</p> |
|
|
<ol> |
|
|
<li>Open WhatsApp on your phone</li> |
|
|
<li>Go to <strong>Linked Devices</strong></li> |
|
|
<li>Enter the pairing code above</li> |
|
|
<li>Wait for creds.json to be sent</li> |
|
|
</ol> |
|
|
</div> |
|
|
</div> |
|
|
)} |
|
|
|
|
|
{status && ( |
|
|
<div className={`status ${status.includes('Error') || status.includes('Gagal') ? 'error' : 'success'}`}> |
|
|
{status} |
|
|
</div> |
|
|
)} |
|
|
|
|
|
{logs.length > 0 && ( |
|
|
<div className="logs"> |
|
|
<h3>π Activity Log</h3> |
|
|
<div className="log-container"> |
|
|
{logs.map((log, index) => ( |
|
|
<div key={index} className={`log-entry ${log.type}`}> |
|
|
<span className="log-time">{log.timestamp}</span> |
|
|
<span className="log-message">{log.message}</span> |
|
|
</div> |
|
|
))} |
|
|
</div> |
|
|
</div> |
|
|
)} |
|
|
|
|
|
<div className="footer"> |
|
|
<p>π Privacy guaranteed - Sessions auto-deleted after completion</p> |
|
|
<p>β‘ Powered by Baileys 6.7.20</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
); |
|
|
} |
|
|
|
|
|
export default App; |