offerpk3 commited on
Commit
290c7b6
·
verified ·
1 Parent(s): 8811a93

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +644 -259
index.html CHANGED
@@ -7,249 +7,494 @@
7
  <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  </head>
11
- <body class="bg-gray-50">
12
- <!-- Header Section -->
13
- <header class="bg-indigo-700 text-white shadow-lg">
14
- <div class="container mx-auto px-4 py-6 flex justify-between items-center">
15
- <div class="flex items-center space-x-3">
16
- <i class="fas fa-network-wired text-3xl"></i>
17
- <h1 class="text-2xl font-bold">Network Device Monitor</h1>
 
 
 
 
 
 
 
 
 
 
 
 
18
  </div>
19
- <div class="flex items-center space-x-4">
 
 
 
 
 
 
 
 
 
 
20
  <div class="relative">
21
- <i class="fas fa-bell text-xl"></i>
22
- <span class="absolute top-0 right-0 bg-red-500 text-xs rounded-full h-4 w-4 flex items-center justify-center">3</span>
 
 
23
  </div>
24
- <div class="flex items-center space-x-2 bg-indigo-600 px-3 py-1 rounded-lg">
25
- <i class="fas fa-user-circle"></i>
26
- <span>Admin</span>
 
 
 
 
 
27
  </div>
28
  </div>
29
  </div>
30
- </header>
31
-
32
- <div class="container mx-auto px-4 py-8">
33
- <!-- Dashboard Summary -->
34
- <div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
35
- <div class="bg-white rounded-xl shadow p-6 flex items-center">
36
- <div class="bg-blue-100 p-4 rounded-xl mr-4">
37
- <i class="fas fa-desktop text-blue-600 text-2xl"></i>
 
 
 
 
38
  </div>
39
- <div>
40
- <p class="text-gray-500">Total Devices</p>
41
- <p class="text-2xl font-bold" id="total-devices">0</p>
 
 
42
  </div>
43
  </div>
44
- <div class="bg-white rounded-xl shadow p-6 flex items-center">
45
- <div class="bg-green-100 p-4 rounded-xl mr-4">
46
- <i class="fas fa-check-circle text-green-600 text-2xl"></i>
 
 
 
 
 
 
 
47
  </div>
48
- <div>
49
- <p class="text-gray-500">Active Devices</p>
50
- <p class="text-2xl font-bold" id="active-devices">0</p>
 
 
51
  </div>
52
  </div>
53
- <div class="bg-white rounded-xl shadow p-6 flex items-center">
54
- <div class="bg-red-100 p-4 rounded-xl mr-4">
55
- <i class="fas fa-ban text-red-600 text-2xl"></i>
 
 
 
 
 
 
 
56
  </div>
57
- <div>
58
- <p class="text-gray-500">Blocked Devices</p>
59
- <p class="text-2xl font-bold" id="blocked-devices">0</p>
 
 
60
  </div>
61
  </div>
62
- <div class="bg-white rounded-xl shadow p-6 flex items-center">
63
- <div class="bg-purple-100 p-4 rounded-xl mr-4">
64
- <i class="fas fa-rupee-sign text-purple-600 text-2xl"></i>
 
 
 
 
 
 
 
65
  </div>
66
- <div>
67
- <p class="text-gray-500">Total Revenue</p>
68
- <p class="text-2xl font-bold" id="total-revenue">₹0</p>
 
 
69
  </div>
70
  </div>
71
  </div>
72
-
73
  <div class="flex flex-col lg:flex-row gap-8">
74
- <!-- Left Column - Form and Stats -->
75
- <div class="lg:w-1/3">
76
  <!-- Add Device Form -->
77
- <div class="bg-white rounded-xl shadow-lg p-6 mb-8">
78
- <h2 class="text-xl font-bold mb-4 text-gray-800">Add New Device</h2>
79
  <form id="device-form" class="space-y-4">
80
  <div>
81
- <label class="block text-gray-700 mb-2">MAC Address</label>
82
- <input type="text" id="mac-address" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="AA:BB:CC:DD:EE:FF">
83
  <p class="text-red-500 text-sm mt-1 hidden" id="mac-error">MAC address is required and must be unique</p>
84
  </div>
 
85
  <div>
86
- <label class="block text-gray-700 mb-2">Device Name</label>
87
- <input type="text" id="device-name" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="e.g. John's iPhone">
88
  </div>
 
89
  <div>
90
- <label class="block text-gray-700 mb-2">User Name</label>
91
- <input type="text" id="user-name" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="e.g. John Doe">
92
  </div>
 
93
  <div>
94
- <label class="block text-gray-700 mb-2">Paid Amount (₹)</label>
95
- <input type="number" id="paid-amount" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="e.g. 500">
96
  <p class="text-red-500 text-sm mt-1 hidden" id="amount-error">Please enter a valid amount</p>
97
  </div>
98
- <button type="submit" class="w-full bg-indigo-600 text-white py-2 rounded-lg hover:bg-indigo-700 transition duration-300 flex items-center justify-center">
 
99
  <i class="fas fa-plus-circle mr-2"></i> Add New Device
100
  </button>
101
  </form>
102
  </div>
103
-
104
- <!-- Payment Statistics -->
105
- <div class="bg-white rounded-xl shadow-lg p-6">
106
- <h2 class="text-xl font-bold mb-4 text-gray-800">Payment Statistics</h2>
107
- <div class="mb-6">
108
- <div class="flex justify-between mb-1">
109
- <span>Total Revenue</span>
110
- <span id="revenue-stat">₹0</span>
111
- </div>
112
- <div class="h-2 bg-gray-200 rounded-full">
113
- <div class="h-2 bg-green-500 rounded-full" style="width: 0%" id="revenue-bar"></div>
114
- </div>
115
- </div>
116
- <div class="mb-6">
117
- <div class="flex justify-between mb-1">
118
- <span>Avg. Payment</span>
119
- <span id="avg-payment">₹0</span>
120
- </div>
121
- <div class="h-2 bg-gray-200 rounded-full">
122
- <div class="h-2 bg-blue-500 rounded-full" style="width: 0%" id="avg-payment-bar"></div>
123
- </div>
124
- </div>
125
- <div>
126
- <div class="flex justify-between mb-1">
127
- <span>Unpaid Devices</span>
128
- <span id="unpaid-count">0</span>
129
- </div>
130
- <div class="h-2 bg-gray-200 rounded-full">
131
- <div class="h-2 bg-red-500 rounded-full" style="width: 0%" id="unpaid-bar"></div>
132
- </div>
133
  </div>
134
  </div>
135
  </div>
136
-
137
  <!-- Right Column - Device Table -->
138
- <div class="lg:w-2/3">
139
- <div class="bg-white rounded-xl shadow-lg p-6">
140
  <div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-6">
141
- <h2 class="text-xl font-bold text-gray-800 mb-4 md:mb-0">Registered Devices</h2>
142
- <div class="flex space-x-3 w-full md:w-auto">
143
- <div class="relative w-full md:w-64">
144
- <input type="text" id="search-input" class="w-full pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="Search devices...">
145
- <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
146
- </div>
147
- <button id="export-btn" class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition duration-300 flex items-center">
148
- <i class="fas fa-file-export mr-2"></i> CSV
149
  </button>
150
  </div>
151
  </div>
152
 
153
  <div class="overflow-x-auto">
154
- <table class="min-w-full divide-y divide-gray-200">
155
  <thead>
156
- <tr>
157
- <th class="px-4 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">#</th>
158
- <th class="px-4 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">MAC Address</th>
159
- <th class="px-4 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Device Name</th>
160
- <th class="px-4 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">User Name</th>
161
- <th class="px-4 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Paid (₹)</th>
162
- <th class="px-4 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Added Time</th>
163
- <th class="px-4 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
164
- <th class="px-4 py-3 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
165
  </tr>
166
  </thead>
167
- <tbody id="device-table" class="bg-white divide-y divide-gray-200">
168
  <!-- Device rows will be populated here -->
169
  </tbody>
170
  </table>
 
 
 
 
 
 
 
 
171
  </div>
172
 
173
  <div class="mt-6 flex flex-col sm:flex-row justify-between items-center border-t pt-4">
174
  <div class="mb-4 sm:mb-0">
175
- <p class="text-gray-600">Total Paid Amount: <span class="font-bold" id="total-paid">₹0</span></p>
176
  </div>
177
  <div class="flex space-x-2">
178
- <button class="px-4 py-2 border rounded-lg hover:bg-gray-100">Previous</button>
179
- <button class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">1</button>
180
- <button class="px-4 py-2 border rounded-lg hover:bg-gray-100">Next</button>
 
 
 
 
 
181
  </div>
182
  </div>
183
  </div>
184
  </div>
185
  </div>
186
  </div>
187
-
188
- <!-- Edit Device Modal -->
189
- <div id="edit-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
190
- <div class="bg-white rounded-xl shadow-lg p-6 w-full max-w-md">
191
- <div class="flex justify-between items-center mb-4">
192
- <h3 class="text-xl font-bold text-gray-800">Edit Device</h3>
193
- <button id="close-modal" class="text-gray-500 hover:text-gray-700">
194
- <i class="fas fa-times"></i>
195
- </button>
196
- </div>
197
- <form id="edit-form" class="space-y-4">
198
- <input type="hidden" id="edit-id">
199
- <div>
200
- <label class="block text-gray-700 mb-2">MAC Address</label>
201
- <input type="text" id="edit-mac" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" readonly>
202
- </div>
203
- <div>
204
- <label class="block text-gray-700 mb-2">Device Name</label>
205
- <input type="text" id="edit-device-name" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500">
206
- </div>
207
- <div>
208
- <label class="block text-gray-700 mb-2">User Name</label>
209
- <input type="text" id="edit-user-name" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500">
210
- </div>
211
- <div>
212
- <label class="block text-gray-700 mb-2">Paid Amount (₹)</label>
213
- <input type="number" id="edit-paid-amount" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500">
214
- </div>
215
- <div class="flex space-x-4 pt-2">
216
- <button type="submit" class="flex-1 bg-indigo-600 text-white py-2 rounded-lg hover:bg-indigo-700 transition duration-300">Update</button>
217
- <button type="button" id="cancel-edit" class="flex-1 bg-gray-300 text-gray-700 py-2 rounded-lg hover:bg-gray-400 transition duration-300">Cancel</button>
218
- </div>
219
- </form>
220
- </div>
221
- </div>
222
-
223
  <script>
224
  // Initialize device data from localStorage or empty array
225
  let devices = JSON.parse(localStorage.getItem('networkDevices')) || [];
226
- let editDeviceId = null;
227
-
228
  // DOM elements
229
  const deviceForm = document.getElementById('device-form');
230
  const deviceTable = document.getElementById('device-table');
231
- const editModal = document.getElementById('edit-modal');
232
- const editForm = document.getElementById('edit-form');
233
- const searchInput = document.getElementById('search-input');
234
  const exportBtn = document.getElementById('export-btn');
235
-
236
  // Initialize the app
237
  document.addEventListener('DOMContentLoaded', () => {
238
  renderDeviceTable();
239
  updateSummary();
240
- attachEventListeners();
 
241
  });
242
-
243
- // Event listeners
244
- function attachEventListeners() {
245
  deviceForm.addEventListener('submit', addNewDevice);
246
- editForm.addEventListener('submit', updateDevice);
247
- document.getElementById('close-modal').addEventListener('click', closeEditModal);
248
- document.getElementById('cancel-edit').addEventListener('click', closeEditModal);
 
 
 
249
  searchInput.addEventListener('input', filterDevices);
250
  exportBtn.addEventListener('click', exportToCSV);
251
  }
252
-
253
  // Add new device
254
  function addNewDevice(e) {
255
  e.preventDefault();
@@ -281,12 +526,15 @@
281
  isValid = false;
282
  }
283
 
284
- if (isNaN(paidAmount) {
285
  document.getElementById('amount-error').classList.remove('hidden');
286
  isValid = false;
287
  }
288
 
289
- if (!isValid) return;
 
 
 
290
 
291
  // Create new device object
292
  const newDevice = {
@@ -307,52 +555,52 @@
307
  deviceForm.reset();
308
  renderDeviceTable();
309
  updateSummary();
 
310
 
311
  // Show success message
312
- showNotification('Device added successfully!', 'success');
313
  }
314
-
315
  // Render device table
316
- function renderDeviceTable(filteredDevices = null) {
317
- const devicesToRender = filteredDevices || devices;
318
  deviceTable.innerHTML = '';
319
 
320
- if (devicesToRender.length === 0) {
321
- deviceTable.innerHTML = `
322
- <tr>
323
- <td colspan="8" class="px-4 py-8 text-center text-gray-500">
324
- <i class="fas fa-inbox text-4xl mb-2"></i>
325
- <p>No devices found. Add a new device to get started.</p>
326
- </td>
327
- </tr>
328
- `;
329
  return;
330
  }
331
 
332
- devicesToRender.forEach((device, index) => {
 
 
333
  const row = document.createElement('tr');
 
334
  row.innerHTML = `
335
- <td class="px-4 py-3 whitespace-nowrap">${index + 1}</td>
336
- <td class="px-4 py-3 whitespace-nowrap font-mono">${device.mac}</td>
337
- <td class="px-4 py-3">${device.deviceName}</td>
338
- <td class="px-4 py-3">${device.userName}</td>
339
- <td class="px-4 py-3 font-medium ${device.paidAmount > 0 ? 'text-green-600' : 'text-red-600'}">₹${device.paidAmount}</td>
340
- <td class="px-4 py-3 whitespace-nowrap">${device.addedTime}</td>
341
- <td class="px-4 py-3">
342
- <span class="px-2 py-1 rounded-full text-xs font-medium ${device.status === 'Active' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}">
 
 
343
  ${device.status}
344
  </span>
345
  </td>
346
- <td class="px-4 py-3 whitespace-nowrap">
347
- <button class="text-blue-600 hover:text-blue-800 mr-2 edit-btn" data-id="${device.id}">
348
- <i class="fas fa-edit"></i>
349
- </button>
350
- <button class="text-red-600 hover:text-red-800 mr-2 block-btn" data-id="${device.id}">
351
- <i class="fas fa-ban"></i>
352
- </button>
353
- <button class="text-gray-600 hover:text-gray-800 delete-btn" data-id="${device.id}">
354
- <i class="fas fa-trash"></i>
355
- </button>
 
 
356
  </td>
357
  `;
358
  deviceTable.appendChild(row);
@@ -360,90 +608,118 @@
360
 
361
  // Attach event listeners to action buttons
362
  document.querySelectorAll('.edit-btn').forEach(btn => {
363
- btn.addEventListener('click', () => openEditModal(btn.dataset.id));
364
  });
365
 
366
  document.querySelectorAll('.block-btn').forEach(btn => {
367
- btn.addEventListener('click', () => blockDevice(btn.dataset.id));
368
  });
369
 
370
  document.querySelectorAll('.delete-btn').forEach(btn => {
371
  btn.addEventListener('click', () => deleteDevice(btn.dataset.id));
372
  });
373
  }
374
-
375
  // Update summary stats
376
  function updateSummary() {
377
  const totalDevices = devices.length;
378
  const activeDevices = devices.filter(d => d.status === 'Active').length;
379
  const blockedDevices = devices.filter(d => d.status === 'Blocked').length;
380
  const totalRevenue = devices.reduce((sum, device) => sum + device.paidAmount, 0);
381
- const unpaidDevices = devices.filter(d => d.paidAmount <= 0).length;
382
- const avgPayment = totalDevices > 0 ? totalRevenue / totalDevices : 0;
383
 
384
- // Update dashboard cards
385
  document.getElementById('total-devices').textContent = totalDevices;
386
  document.getElementById('active-devices').textContent = activeDevices;
387
  document.getElementById('blocked-devices').textContent = blockedDevices;
388
  document.getElementById('total-revenue').textContent = `₹${totalRevenue.toFixed(2)}`;
389
-
390
- // Update payment stats
391
- document.getElementById('revenue-stat').textContent = `₹${totalRevenue.toFixed(2)}`;
392
- document.getElementById('avg-payment').textContent = `₹${avgPayment.toFixed(2)}`;
393
- document.getElementById('unpaid-count').textContent = unpaidDevices;
394
  document.getElementById('total-paid').textContent = `₹${totalRevenue.toFixed(2)}`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
 
396
- // Update progress bars
397
- const maxRevenue = Math.max(1000, totalRevenue);
398
- document.getElementById('revenue-bar').style.width = `${(totalRevenue / maxRevenue) * 100}%`;
399
- document.getElementById('avg-payment-bar').style.width = `${(avgPayment / 500) * 100}%`;
400
- document.getElementById('unpaid-bar').style.width = `${(unpaidDevices / totalDevices) * 100 || 0}%`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
  }
402
-
403
- // Open edit modal
404
- function openEditModal(deviceId) {
405
  const device = devices.find(d => d.id == deviceId);
406
  if (!device) return;
407
 
408
- document.getElementById('edit-id').value = device.id;
409
- document.getElementById('edit-mac').value = device.mac;
410
- document.getElementById('edit-device-name').value = device.deviceName;
411
- document.getElementById('edit-user-name').value = device.userName;
412
- document.getElementById('edit-paid-amount').value = device.paidAmount;
413
 
414
- editModal.classList.remove('hidden');
415
- }
416
-
417
- // Close edit modal
418
- function closeEditModal() {
419
- editModal.classList.add('hidden');
420
- }
421
-
422
- // Update device
423
- function updateDevice(e) {
424
- e.preventDefault();
425
 
426
- const deviceId = document.getElementById('edit-id').value;
427
- const device = devices.find(d => d.id == deviceId);
428
- if (!device) return;
 
 
429
 
430
- device.deviceName = document.getElementById('edit-device-name').value.trim();
431
- device.userName = document.getElementById('edit-user-name').value.trim();
432
- device.paidAmount = parseFloat(document.getElementById('edit-paid-amount').value);
433
 
434
  // Update storage and UI
435
  localStorage.setItem('networkDevices', JSON.stringify(devices));
436
  renderDeviceTable();
437
  updateSummary();
438
- closeEditModal();
439
 
440
- // Show success message
441
- showNotification('Device updated successfully!', 'success');
442
  }
443
-
 
 
 
 
 
 
444
  // Block device
445
- function blockDevice(deviceId) {
446
- const device = devices.find(d => d.id == deviceId);
 
 
447
  if (!device) return;
448
 
449
  device.status = device.status === 'Active' ? 'Blocked' : 'Active';
@@ -453,14 +729,14 @@
453
  renderDeviceTable();
454
  updateSummary();
455
 
 
 
 
456
  // Show notification
457
  const action = device.status === 'Blocked' ? 'blocked' : 'unblocked';
458
- showNotification(`Device has been ${action}`, 'info');
459
-
460
- // Show alert as requested
461
- alert(`Device with MAC ${device.mac} has been ${action}`);
462
  }
463
-
464
  // Delete device
465
  function deleteDevice(deviceId) {
466
  if (!confirm('Are you sure you want to delete this device?')) return;
@@ -471,11 +747,11 @@
471
  localStorage.setItem('networkDevices', JSON.stringify(devices));
472
  renderDeviceTable();
473
  updateSummary();
 
474
 
475
- // Show success message
476
- showNotification('Device deleted successfully!', 'success');
477
  }
478
-
479
  // Filter devices
480
  function filterDevices() {
481
  const searchTerm = searchInput.value.toLowerCase();
@@ -491,13 +767,72 @@
491
  device.userName.toLowerCase().includes(searchTerm)
492
  );
493
 
494
- renderDeviceTable(filtered);
495
  }
496
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
497
  // Export to CSV
498
  function exportToCSV() {
499
  if (devices.length === 0) {
500
- showNotification('No devices to export', 'warning');
501
  return;
502
  }
503
 
@@ -520,9 +855,9 @@
520
  link.click();
521
  document.body.removeChild(link);
522
 
523
- showNotification('CSV exported successfully!', 'success');
524
  }
525
-
526
  // Helper functions
527
  function isValidMAC(mac) {
528
  // Simple MAC validation
@@ -539,9 +874,59 @@
539
  return devices.some(d => d.mac === formattedMAC);
540
  }
541
 
542
- function showNotification(message, type) {
543
- // In a real app, this would show a toast notification
544
- alert(`${type.toUpperCase()}: ${message}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  }
546
  </script>
547
  </body>
 
7
  <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
10
+ <style>
11
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
12
+
13
+ body {
14
+ font-family: 'Inter', sans-serif;
15
+ background: linear-gradient(135deg, #f5f7fa 0%, #e4e7f1 100%);
16
+ min-height: 100vh;
17
+ }
18
+
19
+ .card {
20
+ background: rgba(255, 255, 255, 0.85);
21
+ backdrop-filter: blur(10px);
22
+ border-radius: 16px;
23
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
24
+ transition: all 0.3s ease;
25
+ }
26
+
27
+ .card:hover {
28
+ box-shadow: 0 15px 40px rgba(0, 0, 0, 0.1);
29
+ transform: translateY(-5px);
30
+ }
31
+
32
+ .device-table tr {
33
+ transition: background 0.2s;
34
+ }
35
+
36
+ .device-table tr:hover {
37
+ background-color: #f8f9fc;
38
+ }
39
+
40
+ .status-badge {
41
+ padding: 4px 10px;
42
+ border-radius: 20px;
43
+ font-size: 12px;
44
+ font-weight: 500;
45
+ }
46
+
47
+ .active-badge {
48
+ background-color: #e6f4ea;
49
+ color: #0f9d58;
50
+ }
51
+
52
+ .blocked-badge {
53
+ background-color: #fce8e6;
54
+ color: #d93025;
55
+ }
56
+
57
+ .form-input {
58
+ border: 1px solid #e2e8f0;
59
+ border-radius: 10px;
60
+ padding: 12px 16px;
61
+ transition: all 0.3s;
62
+ }
63
+
64
+ .form-input:focus {
65
+ border-color: #6366f1;
66
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15);
67
+ outline: none;
68
+ }
69
+
70
+ .toast {
71
+ position: fixed;
72
+ bottom: 30px;
73
+ right: 30px;
74
+ padding: 16px 24px;
75
+ border-radius: 12px;
76
+ color: white;
77
+ font-weight: 500;
78
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
79
+ z-index: 1000;
80
+ transform: translateY(100px);
81
+ opacity: 0;
82
+ transition: all 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55);
83
+ }
84
+
85
+ .toast.show {
86
+ transform: translateY(0);
87
+ opacity: 1;
88
+ }
89
+
90
+ .toast.success {
91
+ background: linear-gradient(135deg, #0f9d58 0%, #1db954 100%);
92
+ }
93
+
94
+ .toast.error {
95
+ background: linear-gradient(135deg, #d93025 0%, #ea4335 100%);
96
+ }
97
+
98
+ .toast.info {
99
+ background: linear-gradient(135deg, #1a73e8 0%, #4285f4 100%);
100
+ }
101
+
102
+ .btn-primary {
103
+ background: linear-gradient(135deg, #6366f1 0%, #818cf8 100%);
104
+ color: white;
105
+ border-radius: 10px;
106
+ padding: 12px 24px;
107
+ font-weight: 500;
108
+ transition: all 0.3s;
109
+ border: none;
110
+ cursor: pointer;
111
+ }
112
+
113
+ .btn-primary:hover {
114
+ transform: translateY(-2px);
115
+ box-shadow: 0 10px 20px rgba(99, 102, 241, 0.3);
116
+ }
117
+
118
+ .btn-primary:active {
119
+ transform: translateY(0);
120
+ }
121
+
122
+ .btn-blocked {
123
+ background: linear-gradient(135deg, #d93025 0%, #ea4335 100%);
124
+ }
125
+
126
+ .btn-success {
127
+ background: linear-gradient(135deg, #0f9d58 0%, #1db954 100%);
128
+ }
129
+
130
+ .action-btn {
131
+ width: 36px;
132
+ height: 36px;
133
+ border-radius: 10px;
134
+ display: inline-flex;
135
+ align-items: center;
136
+ justify-content: center;
137
+ cursor: pointer;
138
+ transition: all 0.2s;
139
+ color: #4b5563;
140
+ }
141
+
142
+ .action-btn:hover {
143
+ transform: scale(1.1);
144
+ color: #6366f1;
145
+ }
146
+
147
+ .edit-btn:hover {
148
+ background-color: #eef2ff;
149
+ }
150
+
151
+ .block-btn:hover {
152
+ background-color: #fef2f2;
153
+ color: #ef4444;
154
+ }
155
+
156
+ .delete-btn:hover {
157
+ background-color: #fef2f2;
158
+ color: #ef4444;
159
+ }
160
+
161
+ .mac-address {
162
+ font-family: 'Courier New', monospace;
163
+ background: #f8fafc;
164
+ padding: 4px 8px;
165
+ border-radius: 6px;
166
+ font-weight: 500;
167
+ }
168
+
169
+ .chart-container {
170
+ background: white;
171
+ border-radius: 16px;
172
+ padding: 20px;
173
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
174
+ }
175
+
176
+ .modal-overlay {
177
+ position: fixed;
178
+ top: 0;
179
+ left: 0;
180
+ right: 0;
181
+ bottom: 0;
182
+ background: rgba(0, 0, 0, 0.6);
183
+ display: flex;
184
+ align-items: center;
185
+ justify-content: center;
186
+ z-index: 1000;
187
+ opacity: 0;
188
+ pointer-events: none;
189
+ transition: opacity 0.3s;
190
+ }
191
+
192
+ .modal-overlay.active {
193
+ opacity: 1;
194
+ pointer-events: all;
195
+ }
196
+
197
+ .modal-content {
198
+ background: white;
199
+ border-radius: 16px;
200
+ width: 90%;
201
+ max-width: 500px;
202
+ transform: translateY(20px);
203
+ opacity: 0;
204
+ transition: all 0.3s;
205
+ }
206
+
207
+ .modal-overlay.active .modal-content {
208
+ transform: translateY(0);
209
+ opacity: 1;
210
+ }
211
+
212
+ .pagination-btn {
213
+ width: 36px;
214
+ height: 36px;
215
+ border-radius: 10px;
216
+ display: inline-flex;
217
+ align-items: center;
218
+ justify-content: center;
219
+ background: #f1f5f9;
220
+ color: #4b5563;
221
+ font-weight: 500;
222
+ cursor: pointer;
223
+ transition: all 0.2s;
224
+ }
225
+
226
+ .pagination-btn.active {
227
+ background: #6366f1;
228
+ color: white;
229
+ }
230
+
231
+ .pagination-btn:hover:not(.active) {
232
+ background: #e2e8f0;
233
+ }
234
+ </style>
235
  </head>
236
+ <body class="min-h-screen py-8 px-4">
237
+ <!-- Toast Container -->
238
+ <div id="toast-container"></div>
239
+
240
+ <!-- Modal -->
241
+ <div class="modal-overlay" id="block-modal">
242
+ <div class="modal-content">
243
+ <div class="p-6">
244
+ <div class="flex justify-between items-center mb-4">
245
+ <h3 class="text-xl font-bold text-gray-800">Confirm Block Action</h3>
246
+ <button class="action-btn close-modal">
247
+ <i class="fas fa-times"></i>
248
+ </button>
249
+ </div>
250
+ <p class="text-gray-600 mb-6">Are you sure you want to block this device? The device will lose network access until unblocked.</p>
251
+ <div class="flex justify-between">
252
+ <button class="btn-primary close-modal">Cancel</button>
253
+ <button class="btn-primary btn-blocked" id="confirm-block">Block Device</button>
254
+ </div>
255
  </div>
256
+ </div>
257
+ </div>
258
+
259
+ <div class="max-w-7xl mx-auto">
260
+ <!-- Header -->
261
+ <div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-8">
262
+ <div>
263
+ <h1 class="text-3xl md:text-4xl font-bold text-gray-800">Network Device Monitor</h1>
264
+ <p class="text-gray-600 mt-2">Track, manage, and monitor all network devices</p>
265
+ </div>
266
+ <div class="flex items-center space-x-4 mt-4 md:mt-0">
267
  <div class="relative">
268
+ <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
269
+ <i class="fas fa-search text-gray-400"></i>
270
+ </div>
271
+ <input type="text" id="global-search" placeholder="Search devices..." class="pl-10 pr-4 py-2 form-input w-full md:w-64">
272
  </div>
273
+ <div class="flex items-center bg-white rounded-xl shadow py-2 px-4">
274
+ <div class="bg-indigo-100 p-2 rounded-lg mr-3">
275
+ <i class="fas fa-user text-indigo-600"></i>
276
+ </div>
277
+ <div>
278
+ <p class="text-sm font-medium text-gray-800">Admin User</p>
279
+ <p class="text-xs text-gray-500">Network Admin</p>
280
+ </div>
281
  </div>
282
  </div>
283
  </div>
284
+
285
+ <!-- Stats Cards -->
286
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
287
+ <div class="card p-6">
288
+ <div class="flex justify-between">
289
+ <div>
290
+ <p class="text-gray-500">Total Devices</p>
291
+ <p class="text-2xl font-bold text-gray-800" id="total-devices">0</p>
292
+ </div>
293
+ <div class="bg-blue-100 p-3 rounded-lg">
294
+ <i class="fas fa-network-wired text-blue-600 text-xl"></i>
295
+ </div>
296
  </div>
297
+ <div class="mt-4">
298
+ <div class="flex items-center text-sm text-green-600">
299
+ <i class="fas fa-arrow-up mr-1"></i>
300
+ <span>12% from last month</span>
301
+ </div>
302
  </div>
303
  </div>
304
+
305
+ <div class="card p-6">
306
+ <div class="flex justify-between">
307
+ <div>
308
+ <p class="text-gray-500">Active Devices</p>
309
+ <p class="text-2xl font-bold text-gray-800" id="active-devices">0</p>
310
+ </div>
311
+ <div class="bg-green-100 p-3 rounded-lg">
312
+ <i class="fas fa-check-circle text-green-600 text-xl"></i>
313
+ </div>
314
  </div>
315
+ <div class="mt-4">
316
+ <div class="flex items-center text-sm text-green-600">
317
+ <i class="fas fa-arrow-up mr-1"></i>
318
+ <span>8% from last month</span>
319
+ </div>
320
  </div>
321
  </div>
322
+
323
+ <div class="card p-6">
324
+ <div class="flex justify-between">
325
+ <div>
326
+ <p class="text-gray-500">Blocked Devices</p>
327
+ <p class="text-2xl font-bold text-gray-800" id="blocked-devices">0</p>
328
+ </div>
329
+ <div class="bg-red-100 p-3 rounded-lg">
330
+ <i class="fas fa-ban text-red-600 text-xl"></i>
331
+ </div>
332
  </div>
333
+ <div class="mt-4">
334
+ <div class="flex items-center text-sm text-red-600">
335
+ <i class="fas fa-arrow-down mr-1"></i>
336
+ <span>3% from last month</span>
337
+ </div>
338
  </div>
339
  </div>
340
+
341
+ <div class="card p-6">
342
+ <div class="flex justify-between">
343
+ <div>
344
+ <p class="text-gray-500">Total Revenue</p>
345
+ <p class="text-2xl font-bold text-gray-800" id="total-revenue">₹0</p>
346
+ </div>
347
+ <div class="bg-purple-100 p-3 rounded-lg">
348
+ <i class="fas fa-rupee-sign text-purple-600 text-xl"></i>
349
+ </div>
350
  </div>
351
+ <div class="mt-4">
352
+ <div class="flex items-center text-sm text-green-600">
353
+ <i class="fas fa-arrow-up mr-1"></i>
354
+ <span>15% from last month</span>
355
+ </div>
356
  </div>
357
  </div>
358
  </div>
359
+
360
  <div class="flex flex-col lg:flex-row gap-8">
361
+ <!-- Left Column - Form and Charts -->
362
+ <div class="lg:w-2/5">
363
  <!-- Add Device Form -->
364
+ <div class="card p-6 mb-8">
365
+ <h2 class="text-xl font-bold text-gray-800 mb-4">Register New Device</h2>
366
  <form id="device-form" class="space-y-4">
367
  <div>
368
+ <label class="block text-gray-700 mb-2 font-medium">MAC Address</label>
369
+ <input type="text" id="mac-address" class="w-full form-input" placeholder="AA:BB:CC:DD:EE:FF">
370
  <p class="text-red-500 text-sm mt-1 hidden" id="mac-error">MAC address is required and must be unique</p>
371
  </div>
372
+
373
  <div>
374
+ <label class="block text-gray-700 mb-2 font-medium">Device Name</label>
375
+ <input type="text" id="device-name" class="w-full form-input" placeholder="e.g. John's iPhone">
376
  </div>
377
+
378
  <div>
379
+ <label class="block text-gray-700 mb-2 font-medium">User Name</label>
380
+ <input type="text" id="user-name" class="w-full form-input" placeholder="e.g. John Doe">
381
  </div>
382
+
383
  <div>
384
+ <label class="block text-gray-700 mb-2 font-medium">Paid Amount (₹)</label>
385
+ <input type="number" id="paid-amount" class="w-full form-input" placeholder="e.g. 500">
386
  <p class="text-red-500 text-sm mt-1 hidden" id="amount-error">Please enter a valid amount</p>
387
  </div>
388
+
389
+ <button type="submit" class="btn-primary w-full flex items-center justify-center">
390
  <i class="fas fa-plus-circle mr-2"></i> Add New Device
391
  </button>
392
  </form>
393
  </div>
394
+
395
+ <!-- Payment Chart -->
396
+ <div class="card p-6">
397
+ <h2 class="text-xl font-bold text-gray-800 mb-4">Payment Statistics</h2>
398
+ <div class="chart-container">
399
+ <canvas id="payment-chart"></canvas>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  </div>
401
  </div>
402
  </div>
403
+
404
  <!-- Right Column - Device Table -->
405
+ <div class="lg:w-3/5">
406
+ <div class="card p-6">
407
  <div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-6">
408
+ <h2 class="text-xl font-bold text-gray-800">Registered Devices</h2>
409
+ <div class="flex space-x-3 mt-4 md:mt-0 w-full md:w-auto">
410
+ <button id="export-btn" class="btn-primary flex items-center">
411
+ <i class="fas fa-file-export mr-2"></i> Export CSV
 
 
 
 
412
  </button>
413
  </div>
414
  </div>
415
 
416
  <div class="overflow-x-auto">
417
+ <table class="w-full">
418
  <thead>
419
+ <tr class="text-left text-gray-500 text-sm font-medium border-b">
420
+ <th class="pb-3">#</th>
421
+ <th class="pb-3">MAC Address</th>
422
+ <th class="pb-3">Device Name</th>
423
+ <th class="pb-3">User Name</th>
424
+ <th class="pb-3">Paid (₹)</th>
425
+ <th class="pb-3">Added Time</th>
426
+ <th class="pb-3">Status</th>
427
+ <th class="pb-3 text-right">Actions</th>
428
  </tr>
429
  </thead>
430
+ <tbody id="device-table" class="device-table">
431
  <!-- Device rows will be populated here -->
432
  </tbody>
433
  </table>
434
+
435
+ <div id="empty-state" class="py-12 text-center">
436
+ <div class="mb-4">
437
+ <i class="fas fa-inbox text-4xl text-gray-300"></i>
438
+ </div>
439
+ <h3 class="text-lg font-medium text-gray-700">No devices registered</h3>
440
+ <p class="text-gray-500 mt-1">Add a new device to start monitoring</p>
441
+ </div>
442
  </div>
443
 
444
  <div class="mt-6 flex flex-col sm:flex-row justify-between items-center border-t pt-4">
445
  <div class="mb-4 sm:mb-0">
446
+ <p class="text-gray-700 font-medium">Total Paid Amount: <span class="text-indigo-600" id="total-paid">₹0</span></p>
447
  </div>
448
  <div class="flex space-x-2">
449
+ <div class="pagination-btn">
450
+ <i class="fas fa-chevron-left"></i>
451
+ </div>
452
+ <div class="pagination-btn active">1</div>
453
+ <div class="pagination-btn">2</div>
454
+ <div class="pagination-btn">
455
+ <i class="fas fa-chevron-right"></i>
456
+ </div>
457
  </div>
458
  </div>
459
  </div>
460
  </div>
461
  </div>
462
  </div>
463
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
  <script>
465
  // Initialize device data from localStorage or empty array
466
  let devices = JSON.parse(localStorage.getItem('networkDevices')) || [];
467
+ let currentBlockDevice = null;
468
+
469
  // DOM elements
470
  const deviceForm = document.getElementById('device-form');
471
  const deviceTable = document.getElementById('device-table');
472
+ const emptyState = document.getElementById('empty-state');
473
+ const blockModal = document.getElementById('block-modal');
474
+ const searchInput = document.getElementById('global-search');
475
  const exportBtn = document.getElementById('export-btn');
476
+
477
  // Initialize the app
478
  document.addEventListener('DOMContentLoaded', () => {
479
  renderDeviceTable();
480
  updateSummary();
481
+ setupEventListeners();
482
+ setupCharts();
483
  });
484
+
485
+ // Setup event listeners
486
+ function setupEventListeners() {
487
  deviceForm.addEventListener('submit', addNewDevice);
488
+ document.querySelectorAll('.close-modal').forEach(btn => {
489
+ btn.addEventListener('click', () => {
490
+ blockModal.classList.remove('active');
491
+ });
492
+ });
493
+ document.getElementById('confirm-block').addEventListener('click', blockDevice);
494
  searchInput.addEventListener('input', filterDevices);
495
  exportBtn.addEventListener('click', exportToCSV);
496
  }
497
+
498
  // Add new device
499
  function addNewDevice(e) {
500
  e.preventDefault();
 
526
  isValid = false;
527
  }
528
 
529
+ if (isNaN(paidAmount)) {
530
  document.getElementById('amount-error').classList.remove('hidden');
531
  isValid = false;
532
  }
533
 
534
+ if (!isValid) {
535
+ showToast('Please fill all fields correctly', 'error');
536
+ return;
537
+ }
538
 
539
  // Create new device object
540
  const newDevice = {
 
555
  deviceForm.reset();
556
  renderDeviceTable();
557
  updateSummary();
558
+ setupCharts();
559
 
560
  // Show success message
561
+ showToast('Device added successfully!', 'success');
562
  }
563
+
564
  // Render device table
565
+ function renderDeviceTable() {
 
566
  deviceTable.innerHTML = '';
567
 
568
+ if (devices.length === 0) {
569
+ emptyState.classList.remove('hidden');
 
 
 
 
 
 
 
570
  return;
571
  }
572
 
573
+ emptyState.classList.add('hidden');
574
+
575
+ devices.forEach((device, index) => {
576
  const row = document.createElement('tr');
577
+ row.className = 'py-3 border-b';
578
  row.innerHTML = `
579
+ <td class="py-4">${index + 1}</td>
580
+ <td class="py-4">
581
+ <span class="mac-address">${device.mac}</span>
582
+ </td>
583
+ <td class="py-4 font-medium">${device.deviceName}</td>
584
+ <td class="py-4">${device.userName}</td>
585
+ <td class="py-4 font-medium ${device.paidAmount > 0 ? 'text-green-600' : 'text-red-600'}">₹${device.paidAmount}</td>
586
+ <td class="py-4 text-sm text-gray-500">${device.addedTime}</td>
587
+ <td class="py-4">
588
+ <span class="status-badge ${device.status === 'Active' ? 'active-badge' : 'blocked-badge'}">
589
  ${device.status}
590
  </span>
591
  </td>
592
+ <td class="py-4 text-right">
593
+ <div class="inline-flex space-x-2">
594
+ <button class="action-btn edit-btn" data-id="${device.id}">
595
+ <i class="fas fa-edit"></i>
596
+ </button>
597
+ <button class="action-btn block-btn" data-id="${device.id}">
598
+ <i class="fas fa-ban"></i>
599
+ </button>
600
+ <button class="action-btn delete-btn" data-id="${device.id}">
601
+ <i class="fas fa-trash"></i>
602
+ </button>
603
+ </div>
604
  </td>
605
  `;
606
  deviceTable.appendChild(row);
 
608
 
609
  // Attach event listeners to action buttons
610
  document.querySelectorAll('.edit-btn').forEach(btn => {
611
+ btn.addEventListener('click', () => editDevice(btn.dataset.id));
612
  });
613
 
614
  document.querySelectorAll('.block-btn').forEach(btn => {
615
+ btn.addEventListener('click', () => openBlockModal(btn.dataset.id));
616
  });
617
 
618
  document.querySelectorAll('.delete-btn').forEach(btn => {
619
  btn.addEventListener('click', () => deleteDevice(btn.dataset.id));
620
  });
621
  }
622
+
623
  // Update summary stats
624
  function updateSummary() {
625
  const totalDevices = devices.length;
626
  const activeDevices = devices.filter(d => d.status === 'Active').length;
627
  const blockedDevices = devices.filter(d => d.status === 'Blocked').length;
628
  const totalRevenue = devices.reduce((sum, device) => sum + device.paidAmount, 0);
 
 
629
 
 
630
  document.getElementById('total-devices').textContent = totalDevices;
631
  document.getElementById('active-devices').textContent = activeDevices;
632
  document.getElementById('blocked-devices').textContent = blockedDevices;
633
  document.getElementById('total-revenue').textContent = `₹${totalRevenue.toFixed(2)}`;
 
 
 
 
 
634
  document.getElementById('total-paid').textContent = `₹${totalRevenue.toFixed(2)}`;
635
+ }
636
+
637
+ // Setup charts
638
+ function setupCharts() {
639
+ const ctx = document.getElementById('payment-chart').getContext('2d');
640
+
641
+ // Payment status data
642
+ const paidDevices = devices.filter(d => d.paidAmount > 0).length;
643
+ const unpaidDevices = devices.length - paidDevices;
644
+
645
+ // Device status data
646
+ const activeDevices = devices.filter(d => d.status === 'Active').length;
647
+ const blockedDevices = devices.filter(d => d.status === 'Blocked').length;
648
+
649
+ // Destroy existing chart if it exists
650
+ if (window.paymentChart) {
651
+ window.paymentChart.destroy();
652
+ }
653
 
654
+ window.paymentChart = new Chart(ctx, {
655
+ type: 'doughnut',
656
+ data: {
657
+ labels: ['Paid Devices', 'Unpaid Devices'],
658
+ datasets: [{
659
+ data: [paidDevices, unpaidDevices],
660
+ backgroundColor: ['#10B981', '#EF4444'],
661
+ borderWidth: 0,
662
+ }]
663
+ },
664
+ options: {
665
+ responsive: true,
666
+ maintainAspectRatio: false,
667
+ plugins: {
668
+ legend: {
669
+ position: 'bottom',
670
+ labels: {
671
+ usePointStyle: true,
672
+ padding: 20
673
+ }
674
+ }
675
+ },
676
+ cutout: '65%'
677
+ }
678
+ });
679
  }
680
+
681
+ // Edit device
682
+ function editDevice(deviceId) {
683
  const device = devices.find(d => d.id == deviceId);
684
  if (!device) return;
685
 
686
+ // For simplicity, we'll use prompts
687
+ const newDeviceName = prompt('Enter new device name:', device.deviceName);
688
+ if (!newDeviceName) return;
 
 
689
 
690
+ const newUserName = prompt('Enter new user name:', device.userName);
691
+ if (!newUserName) return;
 
 
 
 
 
 
 
 
 
692
 
693
+ const newPaidAmount = parseFloat(prompt('Enter new paid amount:', device.paidAmount));
694
+ if (isNaN(newPaidAmount)) {
695
+ showToast('Invalid amount entered', 'error');
696
+ return;
697
+ }
698
 
699
+ device.deviceName = newDeviceName;
700
+ device.userName = newUserName;
701
+ device.paidAmount = newPaidAmount;
702
 
703
  // Update storage and UI
704
  localStorage.setItem('networkDevices', JSON.stringify(devices));
705
  renderDeviceTable();
706
  updateSummary();
707
+ setupCharts();
708
 
709
+ showToast('Device updated successfully!', 'success');
 
710
  }
711
+
712
+ // Open block modal
713
+ function openBlockModal(deviceId) {
714
+ currentBlockDevice = deviceId;
715
+ blockModal.classList.add('active');
716
+ }
717
+
718
  // Block device
719
+ function blockDevice() {
720
+ if (!currentBlockDevice) return;
721
+
722
+ const device = devices.find(d => d.id == currentBlockDevice);
723
  if (!device) return;
724
 
725
  device.status = device.status === 'Active' ? 'Blocked' : 'Active';
 
729
  renderDeviceTable();
730
  updateSummary();
731
 
732
+ // Close modal
733
+ blockModal.classList.remove('active');
734
+
735
  // Show notification
736
  const action = device.status === 'Blocked' ? 'blocked' : 'unblocked';
737
+ showToast(`Device ${device.mac} has been ${action}`, 'info');
 
 
 
738
  }
739
+
740
  // Delete device
741
  function deleteDevice(deviceId) {
742
  if (!confirm('Are you sure you want to delete this device?')) return;
 
747
  localStorage.setItem('networkDevices', JSON.stringify(devices));
748
  renderDeviceTable();
749
  updateSummary();
750
+ setupCharts();
751
 
752
+ showToast('Device deleted successfully!', 'success');
 
753
  }
754
+
755
  // Filter devices
756
  function filterDevices() {
757
  const searchTerm = searchInput.value.toLowerCase();
 
767
  device.userName.toLowerCase().includes(searchTerm)
768
  );
769
 
770
+ renderFilteredDevices(filtered);
771
  }
772
+
773
+ // Render filtered devices
774
+ function renderFilteredDevices(filteredDevices) {
775
+ deviceTable.innerHTML = '';
776
+
777
+ if (filteredDevices.length === 0) {
778
+ emptyState.classList.remove('hidden');
779
+ return;
780
+ }
781
+
782
+ emptyState.classList.add('hidden');
783
+
784
+ filteredDevices.forEach((device, index) => {
785
+ const row = document.createElement('tr');
786
+ row.className = 'py-3 border-b';
787
+ row.innerHTML = `
788
+ <td class="py-4">${index + 1}</td>
789
+ <td class="py-4">
790
+ <span class="mac-address">${device.mac}</span>
791
+ </td>
792
+ <td class="py-4 font-medium">${device.deviceName}</td>
793
+ <td class="py-4">${device.userName}</td>
794
+ <td class="py-4 font-medium ${device.paidAmount > 0 ? 'text-green-600' : 'text-red-600'}">₹${device.paidAmount}</td>
795
+ <td class="py-4 text-sm text-gray-500">${device.addedTime}</td>
796
+ <td class="py-4">
797
+ <span class="status-badge ${device.status === 'Active' ? 'active-badge' : 'blocked-badge'}">
798
+ ${device.status}
799
+ </span>
800
+ </td>
801
+ <td class="py-4 text-right">
802
+ <div class="inline-flex space-x-2">
803
+ <button class="action-btn edit-btn" data-id="${device.id}">
804
+ <i class="fas fa-edit"></i>
805
+ </button>
806
+ <button class="action-btn block-btn" data-id="${device.id}">
807
+ <i class="fas fa-ban"></i>
808
+ </button>
809
+ <button class="action-btn delete-btn" data-id="${device.id}">
810
+ <i class="fas fa-trash"></i>
811
+ </button>
812
+ </div>
813
+ </td>
814
+ `;
815
+ deviceTable.appendChild(row);
816
+ });
817
+
818
+ // Reattach event listeners
819
+ document.querySelectorAll('.edit-btn').forEach(btn => {
820
+ btn.addEventListener('click', () => editDevice(btn.dataset.id));
821
+ });
822
+
823
+ document.querySelectorAll('.block-btn').forEach(btn => {
824
+ btn.addEventListener('click', () => openBlockModal(btn.dataset.id));
825
+ });
826
+
827
+ document.querySelectorAll('.delete-btn').forEach(btn => {
828
+ btn.addEventListener('click', () => deleteDevice(btn.dataset.id));
829
+ });
830
+ }
831
+
832
  // Export to CSV
833
  function exportToCSV() {
834
  if (devices.length === 0) {
835
+ showToast('No devices to export', 'warning');
836
  return;
837
  }
838
 
 
855
  link.click();
856
  document.body.removeChild(link);
857
 
858
+ showToast('CSV exported successfully!', 'success');
859
  }
860
+
861
  // Helper functions
862
  function isValidMAC(mac) {
863
  // Simple MAC validation
 
874
  return devices.some(d => d.mac === formattedMAC);
875
  }
876
 
877
+ function showToast(message, type = 'info') {
878
+ const container = document.getElementById('toast-container');
879
+ const toast = document.createElement('div');
880
+ toast.className = `toast ${type}`;
881
+ toast.textContent = message;
882
+ container.appendChild(toast);
883
+
884
+ // Show toast
885
+ setTimeout(() => {
886
+ toast.classList.add('show');
887
+ }, 10);
888
+
889
+ // Remove toast after delay
890
+ setTimeout(() => {
891
+ toast.classList.remove('show');
892
+ setTimeout(() => {
893
+ toast.remove();
894
+ }, 400);
895
+ }, 3000);
896
+ }
897
+
898
+ // Initialize sample data if empty
899
+ if (devices.length === 0) {
900
+ devices = [
901
+ {
902
+ id: 1,
903
+ mac: 'AA:BB:CC:DD:EE:FF',
904
+ deviceName: 'John\'s iPhone',
905
+ userName: 'John Smith',
906
+ paidAmount: 500,
907
+ addedTime: new Date().toLocaleString(),
908
+ status: 'Active'
909
+ },
910
+ {
911
+ id: 2,
912
+ mac: '11:22:33:44:55:66',
913
+ deviceName: 'Office Printer',
914
+ userName: 'Office Admin',
915
+ paidAmount: 0,
916
+ addedTime: new Date().toLocaleString(),
917
+ status: 'Active'
918
+ },
919
+ {
920
+ id: 3,
921
+ mac: 'FF:EE:DD:CC:BB:AA',
922
+ deviceName: 'Sarah\'s Laptop',
923
+ userName: 'Sarah Johnson',
924
+ paidAmount: 750,
925
+ addedTime: new Date().toLocaleString(),
926
+ status: 'Blocked'
927
+ }
928
+ ];
929
+ localStorage.setItem('networkDevices', JSON.stringify(devices));
930
  }
931
  </script>
932
  </body>