pair / frontend /src /App.jsx
Ikyy's picture
Create frontend/src/App.jsx
6aecd8c verified
// frontend/src/App.jsx
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(() => {
// Initialize socket connection
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);
// Reset after 3 seconds
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;