sameernotes commited on
Commit
1a6c663
·
verified ·
1 Parent(s): 133f334

Upload admin.html

Browse files
Files changed (1) hide show
  1. admin.html +613 -0
admin.html ADDED
@@ -0,0 +1,613 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Hindi OCR App - Admin Panel</title>
7
+ <style>
8
+ /* --- REUSABLE STYLES (from translation.html) --- */
9
+ :root {
10
+ --primary-color: #4a90e2; /* Consistent primary color */
11
+ --secondary-color: #f8f9fa;
12
+ --text-color: #2c3e50;
13
+ --border-radius: 12px;
14
+ --transition: all 0.3s ease;
15
+ }
16
+
17
+ * {
18
+ margin: 0;
19
+ padding: 0;
20
+ box-sizing: border-box;
21
+ }
22
+
23
+ body {
24
+ font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; /* Consistent font */
25
+ line-height: 1.6;
26
+ color: var(--text-color);
27
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); /* Consistent background */
28
+ min-height: 100vh;
29
+ padding: 2rem;
30
+ }
31
+
32
+ .container {
33
+ max-width: 1000px;
34
+ margin: 0 auto;
35
+ background: white;
36
+ padding: 2rem;
37
+ border-radius: var(--border-radius);
38
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
39
+ }
40
+
41
+ h1 {
42
+ color: var(--primary-color);
43
+ text-align: center;
44
+ margin-bottom: 2rem;
45
+ font-size: 2.5rem;
46
+ font-weight: 700;
47
+ }
48
+
49
+ h2 {
50
+ color: var(--text-color);
51
+ margin-bottom: 1.5rem;
52
+ font-size: 1.8rem;
53
+ }
54
+
55
+ label {
56
+ display: block;
57
+ margin-bottom: 0.5rem;
58
+ font-weight: 600;
59
+ color: var(--text-color);
60
+ }
61
+
62
+ input[type="text"], input[type="password"], input[type="email"] {
63
+ width: 100%;
64
+ padding: 1rem;
65
+ margin-bottom: 1.5rem;
66
+ border: 2px solid #e1e8ed;
67
+ border-radius: var(--border-radius);
68
+ font-size: 1rem;
69
+ transition: var(--transition);
70
+ background: white;
71
+ }
72
+
73
+
74
+ input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus {
75
+ outline: none;
76
+ border-color: var(--primary-color);
77
+ box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
78
+ }
79
+
80
+ button {
81
+ background: var(--primary-color);
82
+ color: white;
83
+ padding: 1rem 2rem;
84
+ border: none;
85
+ border-radius: var(--border-radius);
86
+ font-size: 1.1rem;
87
+ cursor: pointer;
88
+ transition: var(--transition);
89
+ width: 100%;
90
+ margin-top: 1rem;
91
+ }
92
+
93
+ button:hover {
94
+ transform: translateY(-2px);
95
+ box-shadow: 0 5px 15px rgba(74, 144, 226, 0.3);
96
+ }
97
+ /* --- ERROR MESSAGE --- */
98
+ .error-message {
99
+ background: #fee2e2;
100
+ color: #dc2626;
101
+ padding: 1rem;
102
+ border-radius: var(--border-radius);
103
+ margin-top: 1rem;
104
+ display: none; /* Hidden by default */
105
+ }
106
+ /* --- BUTTONS --- */
107
+ .button-secondary {
108
+ background-color: var(--secondary-color);
109
+ color: var(--primary-color);
110
+ border: 2px solid var(--primary-color);
111
+ width: auto;
112
+ }
113
+ .button-secondary:hover {
114
+ background-color: rgba(74, 144, 226, 0.1);
115
+ box-shadow: 0 5px 15px rgba(74, 144, 226, 0.3);
116
+ }
117
+ /* --- NAVIGATION BAR --- */
118
+ nav {
119
+ display: flex;
120
+ flex-wrap: wrap; /* Allow wrapping on smaller screens */
121
+ gap: 1rem;
122
+ justify-content: center; /* Center items */
123
+ margin-bottom: 2rem;
124
+ border-bottom: 2px solid var(--secondary-color);
125
+ padding-bottom: 1rem;
126
+ }
127
+ nav a {
128
+ color: var(--primary-color);
129
+ text-decoration: none;
130
+ padding: 0.5rem 1rem;
131
+ border-radius: var(--border-radius);
132
+ transition: var(--transition);
133
+ }
134
+ nav a:hover {
135
+ background-color: rgba(74, 144, 226, 0.1);
136
+ }
137
+ nav a.active {
138
+ background-color: var(--primary-color);
139
+ color: white;
140
+ }
141
+ .subtitle {
142
+ text-align: center;
143
+ color: #64748b;
144
+ margin-bottom: 1rem;
145
+ }
146
+
147
+ .attribution {
148
+ text-align: center;
149
+ color: #64748b;
150
+ font-size: 0.875rem;
151
+ margin-bottom: 2rem;
152
+ }
153
+ /* --- LOGOUT BUTTON --- */
154
+ .logout-button {
155
+ position: absolute;
156
+ top: 1rem;
157
+ right: 1rem;
158
+ width: auto; /* Let the button size itself based on content */
159
+ }
160
+
161
+ .logout-button svg {
162
+ margin-right: 0.5rem;
163
+ }
164
+ /* --- ADMIN TABLE STYLES --- */
165
+ .admin-table {
166
+ width: 100%;
167
+ border-collapse: collapse;
168
+ margin-top: 1rem; /* Reduced margin */
169
+ }
170
+ .admin-table th, .admin-table td {
171
+ border: 1px solid #e1e8ed; /* Lighter border */
172
+ padding: 0.75rem; /* Reduced padding */
173
+ text-align: left;
174
+ font-size: 0.9rem; /* Smaller font size */
175
+ }
176
+ .admin-table th {
177
+ background-color: var(--secondary-color);
178
+ font-weight: 600; /* Use font-weight from variables */
179
+ color: var(--text-color);
180
+ }
181
+ /* --- ADMIN BUTTONS (Pagination) --- */
182
+ .admin-buttons {
183
+ display: flex;
184
+ gap: 0.5rem; /* Reduced gap */
185
+ justify-content: center;
186
+ margin-top: 1rem; /* Reduced margin */
187
+ }
188
+
189
+ .admin-buttons button {
190
+ width: auto; /* Let buttons size to content */
191
+ padding: 0.5rem 1rem; /* Smaller padding */
192
+ font-size: 0.9rem;
193
+ margin-top: 0; /* Remove top margin from generic button style */
194
+ }
195
+ /* --- RESPONSIVE --- */
196
+ @media (max-width: 768px) {
197
+ body {
198
+ padding: 1rem;
199
+ }
200
+
201
+ .container {
202
+ padding: 1rem;
203
+ }
204
+ nav {
205
+ justify-content: space-between; /* Adjust as needed */
206
+ }
207
+
208
+ nav a {
209
+ padding: 0.5rem; /* Smaller padding on mobile */
210
+ }
211
+ .admin-table th,
212
+ .admin-table td {
213
+ padding: 0.5rem; /*Even smaller padding on mobile*/
214
+ font-size: 0.8rem;
215
+ }
216
+
217
+ .admin-buttons button {
218
+ padding: 0.4rem 0.8rem; /*Smaller padding on mobile*/
219
+ font-size: 0.8rem;
220
+ }
221
+ }
222
+ .credits {
223
+ text-align: center;
224
+ margin-top: 2rem;
225
+ color: var(--text-color);
226
+ font-size: 0.875rem;
227
+ }
228
+ .feedback-form {
229
+ padding: 2rem;
230
+ background: var(--secondary-color);
231
+ border-radius: var(--border-radius);
232
+ margin-bottom: 2rem;
233
+ }
234
+
235
+ </style>
236
+ </head>
237
+ <body>
238
+ <div class="container" id="admin-app-container" style="display: none;">
239
+ <header>
240
+ <nav>
241
+ <a href="home.html">Home</a>
242
+ <a href="translation.html" target="_blank">translation</a> <!-- Open in new tab -->
243
+ <a href="gender_predictor.html" target="_blank">Gender predictor</a> <!-- Open in new tab -->
244
+ <a href="index.html">OCR App</a>
245
+ <a href="features.html" target="_blank">Key Features</a>
246
+ <a href="feedback.html" target="_blank">Feedback</a>
247
+ <a href="contact.html" target="_blank">Contact Us</a>
248
+ <a href="admin.html" class="active">Admin Panel</a>
249
+ </nav>
250
+ <button id="adminLogoutButton" class="logout-button button-secondary">
251
+ Logout
252
+ </button>
253
+ <h1>Hindi OCR Admin Panel</h1>
254
+ <p class="subtitle">Manage users and feedback for the Hindi OCR Application</p>
255
+ <p class="attribution">Powered by Sakshi's Hindi OCR Engine</p>
256
+
257
+ </header>
258
+
259
+ <div class="main-content">
260
+ <div class="container">
261
+ <h2> User Management</h2>
262
+ <div class="error-message" id="userErrorMessage"></div>
263
+ <div class = "feedback-form">
264
+ <table class="admin-table" id="userTable">
265
+ <thead>
266
+ <tr>
267
+ <th>ID</th>
268
+ <th>Username</th>
269
+ <th>Email</th>
270
+ <th>Is Active</th>
271
+ <th>Is Admin</th>
272
+ <th>Actions</th>
273
+ </tr>
274
+ </thead>
275
+ <tbody id="userTableBody">
276
+ <tr><td colspan="6">Loading users...</td></tr>
277
+ </tbody>
278
+ </table>
279
+ <div class="admin-buttons" id="userPagination">
280
+ <button id="prevUsers" disabled>< Previous</button>
281
+ <button id="nextUsers">Next ></button>
282
+ </div>
283
+ </div>
284
+ </div>
285
+
286
+ <div class="container">
287
+ <h2>Feedback Management</h2>
288
+ <div class="error-message" id="feedbackErrorMessage"></div>
289
+ <div class = "feedback-form">
290
+ <table class="admin-table" id="feedbackTable">
291
+ <thead>
292
+ <tr>
293
+ <th>ID</th>
294
+ <th>Username</th>
295
+ <th>Comment</th>
296
+ <th>Created At</th>
297
+ </tr>
298
+ </thead>
299
+ <tbody id="feedbackTableBody">
300
+ <tr><td colspan="4">Loading feedback...</td></tr>
301
+ </tbody>
302
+ </table>
303
+ <div class="admin-buttons" id="feedbackPagination">
304
+ <button id="prevFeedback" disabled>< Previous</button>
305
+ <button id="nextFeedback">Next ></button>
306
+ </div>
307
+ </div>
308
+ </div>
309
+ </div>
310
+
311
+ <div class="credits">
312
+ <p>Powered by <strong>D SAKSHI</strong> (MCA Final Year BIT Durg, Chhattisgarh) | © SlimShadow Org. All Rights Reserved.</p>
313
+ </div>
314
+ </div>
315
+
316
+ <div id="login-container" style="display:flex; justify-content: center; align-items: center;">
317
+ <div class="container" id="admin-login-card">
318
+ <h2>Admin Login</h2>
319
+ <p>Login to access the Admin Panel.</p>
320
+ <div class="error-message" id="adminLoginErrorMessage"></div>
321
+ <label for="adminUsername">Username</label>
322
+ <input type="text" id="adminUsername" placeholder="Username" value="admin">
323
+ <label for="adminPassword">Password</label>
324
+ <input type="password" id="adminPassword" placeholder="Password" value="adminpassword">
325
+ <button id="adminLoginButton">Login</button>
326
+ </div>
327
+ </div>
328
+
329
+ <script>
330
+ const API_BASE_URL = 'https://sameernotes-ocr.hf.space';
331
+ let adminAccessToken = null;
332
+ const adminAppContainer = document.getElementById('admin-app-container');
333
+ const loginContainer = document.getElementById('login-container');
334
+ const adminLoginCard = document.getElementById('admin-login-card');
335
+
336
+ // Admin Login Elements
337
+ const adminUsernameInput = document.getElementById('adminUsername');
338
+ const adminPasswordInput = document.getElementById('adminPassword');
339
+ const adminLoginButton = document.getElementById('adminLoginButton');
340
+ const adminLoginErrorMessage = document.getElementById('adminLoginErrorMessage');
341
+ const adminLogoutButton = document.getElementById('adminLogoutButton');
342
+
343
+ // User Table Elements
344
+ const userTableBody = document.getElementById('userTableBody');
345
+ const userErrorMessage = document.getElementById('userErrorMessage');
346
+ const prevUsersButton = document.getElementById('prevUsers');
347
+ const nextUsersButton = document.getElementById('nextUsers');
348
+ let currentUserPage = 0;
349
+ const usersPerPage = 5; // Adjust as needed
350
+
351
+ // Feedback Table Elements
352
+ const feedbackTableBody = document.getElementById('feedbackTableBody');
353
+ const feedbackErrorMessage = document.getElementById('feedbackErrorMessage');
354
+ const prevFeedbackButton = document.getElementById('prevFeedback');
355
+ const nextFeedbackButton = document.getElementById('nextFeedback');
356
+ let currentFeedbackPage = 0;
357
+ const feedbackPerPage = 5; // Adjust as needed
358
+
359
+
360
+ adminLoginButton.addEventListener('click', async () => {
361
+ const username = adminUsernameInput.value;
362
+ const password = adminPasswordInput.value;
363
+
364
+ if (!username || !password) {
365
+ showAdminLoginError("Please fill in all fields.");
366
+ return;
367
+ }
368
+
369
+ const formData = new URLSearchParams();
370
+ formData.append('username', username);
371
+ formData.append('password', password);
372
+
373
+ try {
374
+ const response = await fetch(`${API_BASE_URL}/token`, {
375
+ method: 'POST',
376
+ headers: {
377
+ 'Content-Type': 'application/x-www-form-urlencoded'
378
+ },
379
+ body: formData.toString()
380
+ });
381
+
382
+ if (!response.ok) {
383
+ const errorData = await response.json();
384
+ showAdminLoginError(errorData.detail || "Login failed");
385
+ return;
386
+ }
387
+
388
+ const data = await response.json();
389
+ adminAccessToken = data.access_token;
390
+ loginContainer.style.display = 'none';
391
+ adminAppContainer.style.display = 'block';
392
+ adminLoginErrorMessage.style.display = 'none';
393
+ loadUsers(); // Load users table after login
394
+ loadFeedback(); // Load feedback table after login
395
+
396
+
397
+ } catch (error) {
398
+ showAdminLoginError( "Error during login. Please try again.");
399
+ console.error("Admin Login error:", error);
400
+ }
401
+ });
402
+
403
+ adminLogoutButton.addEventListener('click', () => {
404
+ adminAccessToken = null;
405
+ adminAppContainer.style.display = 'none';
406
+ loginContainer.style.display = 'flex';
407
+ // Redirect to index.html
408
+ window.location.href = "index.html";
409
+ });
410
+
411
+
412
+ async function loadUsers() {
413
+ userTableBody.innerHTML = '<tr><td colspan="6">Loading users...</td></tr>';
414
+ userErrorMessage.style.display = 'none';
415
+
416
+ try {
417
+ const response = await fetch(`${API_BASE_URL}/admin/users/?skip=${currentUserPage * usersPerPage}&limit=${usersPerPage}`, {
418
+ headers: {
419
+ 'Authorization': `Bearer ${adminAccessToken}`
420
+ }
421
+ });
422
+
423
+ if (!response.ok) {
424
+ if (response.status === 403) {
425
+ showUserError( "Unauthorized: Admin access required.");
426
+ } else {
427
+ showUserError( `Failed to load users. Status: ${response.status}`);
428
+ }
429
+ userTableBody.innerHTML = '<tr><td colspan="6">Error loading users.</td></tr>';
430
+ return;
431
+ }
432
+
433
+ const users = await response.json();
434
+ if (users.length === 0 && currentUserPage > 0) {
435
+ currentUserPage--; // Adjust page if no users on current page and not on first page
436
+ await loadUsers(); // Reload users with adjusted page
437
+ return;
438
+ }
439
+ populateUserTable(users);
440
+
441
+
442
+ } catch (error) {
443
+ showUserError("Error loading users. Please check console.");
444
+ userTableBody.innerHTML = '<tr><td colspan="6">Error loading users.</td></tr>';
445
+ console.error("Error fetching users:", error);
446
+ }
447
+ }
448
+
449
+ function populateUserTable(users) {
450
+ userTableBody.innerHTML = '';
451
+ if (users.length === 0) {
452
+ userTableBody.innerHTML = '<tr><td colspan="6">No users found.</td></tr>';
453
+ return;
454
+ }
455
+
456
+ users.forEach(user => {
457
+ const row = userTableBody.insertRow();
458
+ row.insertCell(0).textContent = user.id;
459
+ row.insertCell(1).textContent = user.username;
460
+ row.insertCell(2).textContent = user.email;
461
+ row.insertCell(3).textContent = user.is_active ? 'Yes' : 'No';
462
+ row.insertCell(4).textContent = user.is_admin ? 'Yes' : 'No';
463
+ const actionsCell = row.insertCell(5);
464
+ actionsCell.innerHTML = `<button class="button-secondary" onclick="deleteUser(${user.id})">Delete</button>`;
465
+ });
466
+
467
+ // Update pagination button states
468
+ prevUsersButton.disabled = currentUserPage === 0;
469
+ nextUsersButton.disabled = users.length < usersPerPage; // Disable if fewer users than per page, assuming last page
470
+ }
471
+
472
+ prevUsersButton.addEventListener('click', async () => {
473
+ if (currentUserPage > 0) {
474
+ currentUserPage--;
475
+ await loadUsers();
476
+ }
477
+ });
478
+
479
+ nextUsersButton.addEventListener('click', async () => {
480
+ currentUserPage++;
481
+ await loadUsers();
482
+ });
483
+
484
+
485
+ async function deleteUser(userId) {
486
+ if (confirm(`Are you sure you want to delete user ID ${userId}?`)) {
487
+ try {
488
+ const response = await fetch(`${API_BASE_URL}/admin/users/${userId}`, {
489
+ method: 'DELETE',
490
+ headers: {
491
+ 'Authorization': `Bearer ${adminAccessToken}`
492
+ }
493
+ });
494
+
495
+ if (!response.ok) {
496
+ const errorData = await response.json();
497
+ showUserError( errorData.detail || `Failed to delete user. Status: ${response.status}`);
498
+ return;
499
+ }
500
+
501
+ userErrorMessage.style.display = 'none';
502
+ alert(`User ID ${userId} deleted successfully.`);
503
+ loadUsers(); // Reload user list
504
+ } catch (error) {
505
+ showUserError("Error deleting user. Please check console.");
506
+ console.error("Error deleting user:", error);
507
+ }
508
+ }
509
+ }
510
+
511
+
512
+ async function loadFeedback() {
513
+ feedbackTableBody.innerHTML = '<tr><td colspan="4">Loading feedback...</td></tr>';
514
+ feedbackErrorMessage.style.display = 'none';
515
+
516
+ try {
517
+ const response = await fetch(`${API_BASE_URL}/admin/feedback/?skip=${currentFeedbackPage * feedbackPerPage}&limit=${feedbackPerPage}`, {
518
+ headers: {
519
+ 'Authorization': `Bearer ${adminAccessToken}`
520
+ }
521
+ });
522
+
523
+ if (!response.ok) {
524
+ if (response.status === 403) {
525
+ showFeedbackError( "Unauthorized access.");
526
+ } else {
527
+ showFeedbackError( `Failed to load feedback. Status: ${response.status}`);
528
+ }
529
+ feedbackTableBody.innerHTML = '<tr><td colspan="4">Error loading feedback.</td></tr>';
530
+ return;
531
+ }
532
+
533
+ const feedbackData = await response.json();
534
+ if (feedbackData.length === 0 && currentFeedbackPage > 0) {
535
+ currentFeedbackPage--;
536
+ await loadFeedback();
537
+ return;
538
+ }
539
+ populateFeedbackTable(feedbackData);
540
+
541
+
542
+ } catch (error) {
543
+ showFeedbackError("Error loading feedback. Please check console.");
544
+ feedbackTableBody.innerHTML = '<tr><td colspan="4">Error loading feedback.</td></tr>';
545
+ console.error("Error fetching feedback:", error);
546
+ }
547
+ }
548
+
549
+ function populateFeedbackTable(feedbackData) {
550
+ feedbackTableBody.innerHTML = '';
551
+ if (feedbackData.length === 0) {
552
+ feedbackTableBody.innerHTML = '<tr><td colspan="4">No feedback found.</td></tr>';
553
+ return;
554
+ }
555
+
556
+ feedbackData.forEach(feedback => {
557
+ const row = feedbackTableBody.insertRow();
558
+ row.insertCell(0).textContent = feedback.id;
559
+ row.insertCell(1).textContent = feedback.username;
560
+ row.insertCell(2).textContent = feedback.comment;
561
+ row.insertCell(3).textContent = new Date(feedback.created_at).toLocaleString();
562
+ });
563
+
564
+ prevFeedbackButton.disabled = currentFeedbackPage === 0;
565
+ nextFeedbackButton.disabled = feedbackData.length < feedbackPerPage;
566
+ }
567
+
568
+
569
+ prevFeedbackButton.addEventListener('click', async () => {
570
+ if (currentFeedbackPage > 0) {
571
+ currentFeedbackPage--;
572
+ await loadFeedback();
573
+ }
574
+ });
575
+
576
+ nextFeedbackButton.addEventListener('click', async () => {
577
+ currentFeedbackPage++;
578
+ await loadFeedback();
579
+ });
580
+
581
+ function showAdminLoginError(message) {
582
+ adminLoginErrorMessage.textContent = message;
583
+ adminLoginErrorMessage.style.display = 'block';
584
+ setTimeout(() => {
585
+ adminLoginErrorMessage.style.display = 'none';
586
+ }, 5000); // Hide after 5 seconds
587
+
588
+ }
589
+ function showUserError(message) {
590
+ userErrorMessage.textContent = message;
591
+ userErrorMessage.style.display = 'block';
592
+ setTimeout(() => {
593
+ userErrorMessage.style.display = 'none';
594
+ }, 5000);
595
+ }
596
+
597
+ function showFeedbackError(message) {
598
+ feedbackErrorMessage.textContent = message;
599
+ feedbackErrorMessage.style.display = 'block';
600
+ setTimeout(() => {
601
+ feedbackErrorMessage.style.display = 'none';
602
+ }, 5000);
603
+ }
604
+
605
+ // --- Initial Check for Admin Token ---
606
+ // For simplicity, always start at admin login for this example
607
+ loginContainer.style.display = 'flex';
608
+ adminAppContainer.style.display = 'none';
609
+
610
+
611
+ </script>
612
+ </body>
613
+ </html>