Ikyy commited on
Commit
6aecd8c
Β·
verified Β·
1 Parent(s): 0e33a69

Create frontend/src/App.jsx

Browse files
Files changed (1) hide show
  1. frontend/src/App.jsx +207 -0
frontend/src/App.jsx ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // frontend/src/App.jsx
2
+ import { useState, useEffect, useRef } from 'react';
3
+ import { io } from 'socket.io-client';
4
+ import './App.css';
5
+
6
+ function App() {
7
+ const [phoneNumber, setPhoneNumber] = useState('');
8
+ const [status, setStatus] = useState('');
9
+ const [pairingCode, setPairingCode] = useState('');
10
+ const [isConnecting, setIsConnecting] = useState(false);
11
+ const [logs, setLogs] = useState([]);
12
+ const socketRef = useRef(null);
13
+
14
+ useEffect(() => {
15
+ // Initialize socket connection
16
+ const socketUrl = window.location.origin;
17
+
18
+ socketRef.current = io(socketUrl, {
19
+ autoConnect: true,
20
+ reconnection: true,
21
+ reconnectionDelay: 1000,
22
+ reconnectionAttempts: 5
23
+ });
24
+
25
+ const socket = socketRef.current;
26
+
27
+ socket.on('connect', () => {
28
+ addLog('βœ… Connected to server', 'success');
29
+ });
30
+
31
+ socket.on('disconnect', () => {
32
+ addLog('❌ Disconnected from server', 'error');
33
+ setIsConnecting(false);
34
+ });
35
+
36
+ socket.on('status', (data) => {
37
+ setStatus(data.message);
38
+ addLog(`ℹ️ ${data.message}`, 'info');
39
+ });
40
+
41
+ socket.on('pairing-code', (data) => {
42
+ setPairingCode(data.code);
43
+ setStatus('Pairing code generated successfully!');
44
+ addLog(`πŸ”‘ Pairing Code: ${data.code}`, 'success');
45
+ });
46
+
47
+ socket.on('success', (data) => {
48
+ setStatus(data.message);
49
+ addLog(`βœ… ${data.message}`, 'success');
50
+ setIsConnecting(false);
51
+
52
+ // Reset after 3 seconds
53
+ setTimeout(() => {
54
+ resetForm();
55
+ }, 3000);
56
+ });
57
+
58
+ socket.on('error', (data) => {
59
+ setStatus(`Error: ${data.message}`);
60
+ addLog(`❌ ${data.message}`, 'error');
61
+ setIsConnecting(false);
62
+ setPairingCode('');
63
+ });
64
+
65
+ return () => {
66
+ socket.disconnect();
67
+ };
68
+ }, []);
69
+
70
+ const addLog = (message, type = 'info') => {
71
+ const timestamp = new Date().toLocaleTimeString();
72
+ setLogs(prev => [...prev, { message, type, timestamp }]);
73
+ };
74
+
75
+ const resetForm = () => {
76
+ setPhoneNumber('');
77
+ setPairingCode('');
78
+ setStatus('');
79
+ setIsConnecting(false);
80
+ };
81
+
82
+ const handleSubmit = (e) => {
83
+ e.preventDefault();
84
+
85
+ if (!phoneNumber.trim()) {
86
+ setStatus('Phone number cannot be empty!');
87
+ addLog('❌ Phone number cannot be empty', 'error');
88
+ return;
89
+ }
90
+
91
+ const cleanNumber = phoneNumber.replace(/[^\d]/g, '');
92
+
93
+ if (cleanNumber.length < 10 || cleanNumber.length > 15) {
94
+ setStatus('Invalid phone number! Must be 10-15 digits');
95
+ addLog('❌ Invalid phone number format', 'error');
96
+ return;
97
+ }
98
+
99
+ if (cleanNumber.startsWith('0')) {
100
+ setStatus('Phone number must include country code (e.g., 1, 44, 62, 91)');
101
+ addLog('❌ Country code required', 'error');
102
+ return;
103
+ }
104
+
105
+ setIsConnecting(true);
106
+ setPairingCode('');
107
+ setStatus('Starting pairing process...');
108
+ setLogs([]);
109
+
110
+ addLog('πŸš€ Initiating connection...', 'info');
111
+ socketRef.current.emit('start-pairing', { phoneNumber: cleanNumber });
112
+ };
113
+
114
+ const handlePhoneChange = (e) => {
115
+ const value = e.target.value.replace(/[^\d+]/g, '');
116
+ setPhoneNumber(value);
117
+ };
118
+
119
+ const copyCode = () => {
120
+ navigator.clipboard.writeText(pairingCode);
121
+ addLog('πŸ“‹ Pairing code copied!', 'success');
122
+ };
123
+
124
+ return (
125
+ <div className="container">
126
+ <div className="card">
127
+ <div className="header">
128
+ <h1>πŸ€– WA Pairing Service</h1>
129
+ <p>Get your WhatsApp bot session easily</p>
130
+ </div>
131
+
132
+ <form onSubmit={handleSubmit} className="form">
133
+ <div className="input-group">
134
+ <label htmlFor="phone">WhatsApp Bot Number</label>
135
+ <input
136
+ type="text"
137
+ id="phone"
138
+ value={phoneNumber}
139
+ onChange={handlePhoneChange}
140
+ placeholder="12025551234 (with country code)"
141
+ disabled={isConnecting}
142
+ maxLength={16}
143
+ className="input"
144
+ />
145
+ <small>Include country code (e.g., 1 for US, 44 for UK, 62 for ID, 91 for IN)</small>
146
+ </div>
147
+
148
+ <button
149
+ type="submit"
150
+ disabled={isConnecting}
151
+ className={`button ${isConnecting ? 'loading' : ''}`}
152
+ >
153
+ {isConnecting ? '⏳ Processing...' : 'πŸš€ Start Pairing'}
154
+ </button>
155
+ </form>
156
+
157
+ {pairingCode && (
158
+ <div className="pairing-code">
159
+ <h3>Pairing Code</h3>
160
+ <div className="code-display">
161
+ <span className="code">{pairingCode}</span>
162
+ <button onClick={copyCode} className="copy-btn" title="Copy">
163
+ πŸ“‹
164
+ </button>
165
+ </div>
166
+ <div className="instructions">
167
+ <p>Next steps:</p>
168
+ <ol>
169
+ <li>Open WhatsApp on your phone</li>
170
+ <li>Go to <strong>Linked Devices</strong></li>
171
+ <li>Enter the pairing code above</li>
172
+ <li>Wait for creds.json to be sent</li>
173
+ </ol>
174
+ </div>
175
+ </div>
176
+ )}
177
+
178
+ {status && (
179
+ <div className={`status ${status.includes('Error') || status.includes('Gagal') ? 'error' : 'success'}`}>
180
+ {status}
181
+ </div>
182
+ )}
183
+
184
+ {logs.length > 0 && (
185
+ <div className="logs">
186
+ <h3>πŸ“‹ Activity Log</h3>
187
+ <div className="log-container">
188
+ {logs.map((log, index) => (
189
+ <div key={index} className={`log-entry ${log.type}`}>
190
+ <span className="log-time">{log.timestamp}</span>
191
+ <span className="log-message">{log.message}</span>
192
+ </div>
193
+ ))}
194
+ </div>
195
+ </div>
196
+ )}
197
+
198
+ <div className="footer">
199
+ <p>πŸ”’ Privacy guaranteed - Sessions auto-deleted after completion</p>
200
+ <p>⚑ Powered by Baileys 6.7.20</p>
201
+ </div>
202
+ </div>
203
+ </div>
204
+ );
205
+ }
206
+
207
+ export default App;