-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
726 lines (630 loc) · 30.9 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Added viewport meta tag for mobile responsiveness -->
<title>Monitoraggio Moduli</title>
<!-- Bootstrap CSS for styling -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
<style>
body {
padding: 15px; /* Reduced padding for smaller screens */
}
#logBox {
height: 150px; /* Reduced height for smaller screens */
overflow-y: scroll;
background-color: #f8f9fa;
padding: 10px;
border: 1px solid #ced4da;
border-radius: .25rem;
font-size: 0.9rem; /* Slightly smaller font in log box for mobile */
}
th {
cursor: pointer;
font-size: 0.95rem; /* Slightly smaller font in table headers for mobile */
}
td {
font-size: 0.9rem; /* Slightly smaller font in table cells for mobile */
}
.checked {
color: green;
font-weight: bold;
}
.unchecked {
color: grey;
font-weight: bold;
}
/* Hide the main application initially */
#mainApp {
display: none;
}
/* Sort arrow styles */
.sort-arrow {
margin-left: 5px;
}
/* Responsive adjustments - Adjusted breakpoints and styles for better mobile experience */
@media (max-width: 768px) { /* Adjusted breakpoint to medium devices */
body {
padding: 10px;
}
h1 {
font-size: 2rem; /* Slightly smaller main heading on mobile */
margin-bottom: 1.5rem;
}
#logBox {
height: 120px; /* Further reduced height for smaller screens */
font-size: 0.85rem; /* Even smaller font in log box for very small screens */
}
.btn {
width: 100%; /* Full width buttons on smaller screens */
margin-bottom: 8px; /* Slightly reduced margin for buttons */
font-size: 0.95rem; /* Slightly smaller button text for mobile */
}
.progress {
height: 15px; /* Reduced progress bar height for mobile */
}
#refreshCountdown {
font-size: 0.85rem; /* Even smaller countdown text for very small screens */
}
.table-responsive { /* Ensure table is always responsive on smaller screens */
overflow-x: auto;
-webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */
}
th, td {
padding: 0.5rem 0.5rem; /* Reduced padding in table cells for mobile */
white-space: nowrap; /* Prevent text wrapping in table cells to maintain layout */
font-size: 0.85rem; /* Even smaller font in table cells for very small screens */
}
th {
font-size: 0.9rem; /* Slightly larger font in table headers than cells */
}
}
/* Add transition for table rows */
#formsTable tbody tr {
transition: background-color 0.3s ease;
}
.row-updated {
background-color: #d1e7dd !important;
}
</style>
</head>
<body>
<div class="container">
<h1 class="mb-4">Monitoraggio Moduli</h1>
<!-- API Key Input -->
<div id="mainApp">
<div class="mb-3">
<label for="apiKey" class="form-label">Chiave API JotForm:</label>
<input type="password" class="form-control" id="apiKey" placeholder="Inserisci la tua Chiave API JotForm">
<div class="form-text">La tua chiave API viene utilizzata per accedere ai tuoi moduli e invii JotForm.</div>
</div>
<!-- Buttons -->
<div class="mb-3 d-grid gap-2 d-md-flex justify-content-md-start"> <!-- Using d-grid and gap for better button spacing on mobile -->
<button class="btn btn-primary me-md-2" id="retrieveFormsBtn">Recupera Moduli</button>
<button class="btn btn-danger" id="deleteSubmissionsBtn">Elimina Invii Selezionati</button>
</div>
<!-- Progress Bar -->
<div class="mb-3">
<label for="refreshProgress" class="form-label">Prossimo aggiornamento tra:</label>
<div class="progress">
<div id="refreshProgressBar" class="progress-bar" role="progressbar" style="width: 0%;" aria-valuemin="0" aria-valuemax="60"></div>
</div>
<small id="refreshCountdown" class="form-text text-muted">60 secondi</small>
</div>
<!-- Forms Table -->
<div class="table-responsive">
<table class="table table-striped table-hover table-bordered align-middle" id="formsTable">
<thead>
<tr>
<th data-column="select" class="text-center" style="width: 60px;">Seleziona</th> <!-- Fixed width for select column -->
<th data-column="title">Titolo <span class="sort-arrow"></span></th>
<th data-column="id" style="width: 150px;">ID <span class="sort-arrow"></span></th> <!-- Fixed width for ID column -->
<th data-column="status" style="width: 100px;">Stato <span class="sort-arrow"></span></th> <!-- Fixed width for Status column -->
<th data-column="submissions" class="text-end" style="width: 80px;">Invii <span class="sort-arrow"></span></th> <!-- Fixed width for Submissions column -->
<th data-column="lastSubmission" class="text-end" style="width: 180px;">Ultimo Invio <span class="sort-arrow"></span></th> <!-- Fixed width for Last Submission column -->
</tr>
</thead>
<tbody>
<!-- Dynamic Content -->
</tbody>
</table>
</div>
<!-- Log Box -->
<div class="mt-4">
<h5>Registro:</h5>
<div id="logBox"></div>
</div>
</div>
</div>
<!-- Password Authentication Modal -->
<div class="modal fade" id="authModal" tabindex="-1" aria-labelledby="authModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="authModalLabel">Autenticazione Necessaria</h5>
</div>
<div class="modal-body">
<form id="authForm">
<div class="mb-3">
<label for="userPassword" class="form-label">Inserisci la tua Password:</label>
<input type="password" class="form-control" id="userPassword" placeholder="Password" required>
</div>
<div id="authError" class="text-danger mb-3" style="display: none;">
Password non autorizzata.
</div>
<button type="submit" class="btn btn-primary">Invia</button>
</form>
</div>
</div>
</div>
</div>
<!-- Bootstrap JS and dependencies -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<!-- Main JavaScript -->
<script>
// JotForm API base URL for EU accounts
const BASE_URL = 'https://eu-api.jotform.com';
// Global variables to track sort state
let currentSortColumn = null;
let currentSortOrder = 'asc'; // 'asc' or 'desc'
// Global variable for the authentication modal instance
let authModalInstance;
// Progress Bar Variables
const refreshInterval = 60; // seconds
let timeLeft = refreshInterval;
let progressBarTimer;
// Global variable to keep track of selected forms
let selectedFormIds = new Set();
// Store form data to compare during refresh
let formDataMap = new Map();
// Event Listeners
document.getElementById('retrieveFormsBtn').addEventListener('click', () => {
retrieveForms();
});
document.getElementById('deleteSubmissionsBtn').addEventListener('click', deleteSelectedSubmissions);
document.querySelectorAll('#formsTable th').forEach(header => {
header.addEventListener('click', () => {
const column = header.getAttribute('data-column');
if (column && column !== 'select') {
sortTable(column);
}
});
});
// Function to log messages with timestamps
function logMessage(message) {
const logBox = document.getElementById('logBox');
const timestamp = new Date().toLocaleString();
logBox.innerHTML += `<div><strong>${timestamp}:</strong> ${message}</div>`;
logBox.scrollTop = logBox.scrollHeight;
}
// Function to retrieve all forms
async function retrieveForms() {
const apiKey = document.getElementById('apiKey').value.trim();
if (!apiKey) {
alert('Per favore inserisci la tua Chiave API JotForm.');
return;
}
logMessage('Recupero dei moduli...');
try {
// Add counts=true to get submission counts
const response = await fetch(`${BASE_URL}/user/forms?apiKey=${apiKey}&counts=true`);
if (!response.ok) {
throw new Error(`Errore HTTP! Stato: ${response.status}`);
}
const data = await response.json();
if (!data.content) {
logMessage('Struttura di risposta inaspettata durante il recupero dei moduli.');
return;
}
const forms = data.content;
// Map to store new form data
const newFormDataMap = new Map();
// Process each form
for (let [index, form] of forms.entries()) {
const formTitle = form.title || 'Senza Titolo';
const formId = form.id || 'N/A';
const formStatus = form.status || 'ATTIVATO';
const isActive = formStatus.toUpperCase() === 'ENABLED' || formStatus.toUpperCase() === 'ATTIVATO';
// Get submission count from form data
const submissionCount = form.count || 0;
logMessage(`Modulo ${index + 1}/${forms.length}: '${formTitle}' (ID: ${formId}) ha ${submissionCount} invii`);
const lastSubmissionDate = await getLastSubmissionDate(formId, apiKey);
// Store form data
newFormDataMap.set(formId, {
formTitle,
formId,
formStatus,
isActive,
submissionCount,
lastSubmissionDate
});
}
// Update the table with new data
updateTable(newFormDataMap);
// Update the formDataMap with new data
formDataMap = newFormDataMap;
logMessage(`Recuperati ${forms.length} moduli.`);
// Apply the current sort after refreshing the table
if (currentSortColumn) {
applyCurrentSort();
updateSortArrows();
} else {
updateSortArrows();
}
} catch (error) {
logMessage(`Errore nel recupero dei moduli: ${error.message}`);
console.error(error);
} finally {
resetProgressBarTimer();
}
}
// Function to get last submission date for a form
async function getLastSubmissionDate(formId, apiKey) {
try {
const response = await fetch(`${BASE_URL}/form/${formId}/submissions?apiKey=${apiKey}&limit=1&orderby=created_at&sort=desc`);
if (!response.ok) throw new Error(`Errore HTTP! Stato: ${response.status}`);
const data = await response.json();
if (data.content && data.content.length > 0) {
const createdAt = data.content[0].created_at; // e.g., '2024-12-03 01:23:09'
// Determine the UTC offset for Eastern Time (ET) at the date of submission
const [datePart, timePart] = createdAt.split(' ');
const [year, month, day] = datePart.split('-').map(Number);
const [hour, minute, second] = timePart.split(':').map(Number);
const submissionDate = new Date(Date.UTC(year, month - 1, day, hour, minute, second));
// Determine if the date is in Daylight Saving Time
const isDST = isDaylightSavingTimeInET(submissionDate);
// Adjust the time by adding the ET offset to UTC
const etOffset = isDST ? -4 : -5; // UTC offset for ET in hours
submissionDate.setUTCHours(submissionDate.getUTCHours() - etOffset);
// Format the date in Central European Time
const options = {
timeZone: 'Europe/Rome', // Central European Time zone
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit',
};
const formatter = new Intl.DateTimeFormat('it-IT', options);
return formatter.format(submissionDate);
} else {
return 'N/A';
}
} catch (error) {
logMessage(`Errore nel recuperare la data dell'ultimo invio per il modulo ${formId}: ${error.message}`);
return 'N/A';
}
}
// Helper function to determine if a date is in Daylight Saving Time in ET
function isDaylightSavingTimeInET(date) {
const year = date.getUTCFullYear();
// Second Sunday in March at 2:00 AM
const dstStart = new Date(Date.UTC(year, 2, 8, 7)); // March 8th at 2:00 AM ET
dstStart.setUTCDate(8 + (7 - dstStart.getUTCDay()) % 7);
// First Sunday in November at 2:00 AM
const dstEnd = new Date(Date.UTC(year, 10, 1, 6)); // November 1st at 2:00 AM ET
dstEnd.setUTCDate(1 + (7 - dstEnd.getUTCDay()) % 7);
return date >= dstStart && date < dstEnd;
}
// Function to update the table with new form data
function updateTable(newFormDataMap) {
const tbody = document.querySelector('#formsTable tbody');
const existingRows = tbody.querySelectorAll('tr');
// Map existing rows by formId for quick lookup
const existingRowsMap = new Map();
existingRows.forEach(row => {
const formId = row.getAttribute('data-form-id');
existingRowsMap.set(formId, row);
});
// Keep track of rows that have been updated or added
const processedFormIds = new Set();
newFormDataMap.forEach((formData, formId) => {
const existingRow = existingRowsMap.get(formId);
if (existingRow) {
// Update existing row if data has changed
const cells = existingRow.children;
const submissionCountCell = cells[4];
const lastSubmissionCell = cells[5];
const prevSubmissionCount = submissionCountCell.innerText;
const prevLastSubmission = lastSubmissionCell.innerText;
if (prevSubmissionCount != formData.submissionCount || prevLastSubmission != formData.lastSubmissionDate) {
submissionCountCell.innerText = formData.submissionCount;
lastSubmissionCell.innerText = formData.lastSubmissionDate;
// Highlight updated row
existingRow.classList.add('row-updated');
setTimeout(() => {
existingRow.classList.remove('row-updated');
}, 1000);
}
// Update checkbox state
const checkbox = existingRow.querySelector('.form-select-checkbox');
// Modified line: Disable checkbox if submissionCount is 0
checkbox.disabled = formData.submissionCount === 0;
// Update status badge
const statusCell = cells[3];
statusCell.innerHTML = formData.isActive ? '<span class="badge bg-success">Attivato</span>' : '<span class="badge bg-secondary">Disattivato</span>';
// Update row class for inactive forms
if (!formData.isActive) {
existingRow.classList.add('table-secondary');
} else {
existingRow.classList.remove('table-secondary');
}
processedFormIds.add(formId);
} else {
// Add new row
const row = document.createElement('tr');
row.setAttribute('data-form-id', formId);
row.innerHTML = `
<td class="text-center">
<input type="checkbox" class="form-select-checkbox" data-form-id="${formId}" ${formData.submissionCount > 0 ? '' : 'disabled'} ${selectedFormIds.has(formId) ? 'checked' : ''}>
</td>
<td>${formData.formTitle}</td>
<td>${formData.formId}</td>
<td>${formData.isActive ? '<span class="badge bg-success">Attivato</span>' : '<span class="badge bg-secondary">Disattivato</span>'}</td>
<td class="text-end">${formData.submissionCount}</td>
<td class="text-end">${formData.lastSubmissionDate}</td>
`;
if (!formData.isActive) {
row.classList.add('table-secondary');
}
tbody.appendChild(row);
// Add event listener to update selectedFormIds when the checkbox is changed
const checkbox = row.querySelector('.form-select-checkbox');
if (checkbox) {
checkbox.addEventListener('change', function() {
const formId = this.getAttribute('data-form-id');
if (this.checked) {
selectedFormIds.add(formId);
} else {
selectedFormIds.delete(formId);
}
});
}
// Highlight new row
row.classList.add('row-updated');
setTimeout(() => {
row.classList.remove('row-updated');
}, 1000);
processedFormIds.add(formId);
}
});
// Remove rows that are no longer present
existingRows.forEach(row => {
const formId = row.getAttribute('data-form-id');
if (!newFormDataMap.has(formId)) {
tbody.removeChild(row);
selectedFormIds.delete(formId);
}
});
}
// Function to delete selected submissions
async function deleteSelectedSubmissions() {
const apiKey = document.getElementById('apiKey').value.trim();
if (!apiKey) {
alert('Per favore inserisci la tua Chiave API JotForm.');
return;
}
const checkboxes = document.querySelectorAll('.form-select-checkbox:checked');
if (checkboxes.length === 0) {
alert('Per favore seleziona almeno un modulo con invii per eliminare gli invii.');
return;
}
if (!confirm(`Sei sicuro di voler eliminare gli invii per ${checkboxes.length} modulo/i? Questa azione non può essere annullata.`)) {
return;
}
for (let checkbox of checkboxes) {
const formId = checkbox.getAttribute('data-form-id');
const formTitle = checkbox.closest('tr').children[1].innerText;
logMessage(`Eliminazione degli invii per il modulo: ${formTitle} (ID: ${formId})`);
await deleteAllSubmissions(formId, apiKey);
// Update the table row
const row = checkbox.closest('tr');
row.children[4].innerText = '0';
row.children[5].innerText = 'N/A';
checkbox.checked = false;
checkbox.disabled = true; // Disable checkbox after deleting submissions
selectedFormIds.delete(formId); // Update the selected forms
// Update formDataMap
if (formDataMap.has(formId)) {
const formData = formDataMap.get(formId);
formData.submissionCount = 0;
formData.lastSubmissionDate = 'N/A';
}
}
alert('Processo di eliminazione completato. Controlla il registro per i dettagli.');
logMessage('Processo di eliminazione completato.');
}
// Function to delete all submissions for a form
async function deleteAllSubmissions(formId, apiKey) {
try {
let page = 1;
const limit = 100; // Adjust as needed
let hasMore = true;
while (hasMore) {
const response = await fetch(`${BASE_URL}/form/${formId}/submissions?apiKey=${apiKey}&limit=${limit}&page=${page}`);
if (!response.ok) throw new Error(`Errore HTTP! Stato: ${response.status}`);
const data = await response.json();
if (data.content && data.content.length > 0) {
for (let submission of data.content) {
const submissionId = submission.id;
const deleteResponse = await fetch(`${BASE_URL}/submission/${submissionId}?apiKey=${apiKey}`, {
method: 'DELETE'
});
if (deleteResponse.ok) {
logMessage(`Eliminato invio ID: ${submissionId}`);
} else {
logMessage(`Impossibile eliminare l'invio ID: ${submissionId}. Stato: ${deleteResponse.status}`);
}
}
// Check if there are more submissions
hasMore = data.currentPage < data.totalPages;
page++;
} else {
hasMore = false;
}
}
logMessage(`Tutti gli invii per il modulo ID ${formId} sono stati eliminati.`);
} catch (error) {
logMessage(`Errore nell'eliminare gli invii per il modulo ID ${formId}: ${error.message}`);
console.error(error);
}
}
// Function to sort the table based on a column
function sortTable(column) {
if (!column) return;
if (currentSortColumn === column) {
// Toggle sort order if the same column is clicked
currentSortOrder = currentSortOrder === 'asc' ? 'desc' : 'asc';
} else {
// Set to ascending order if a new column is clicked
currentSortOrder = 'asc';
currentSortColumn = column;
}
applyCurrentSort();
updateSortArrows();
}
// Helper function to get column index based on column name
function getColumnIndex(column) {
const columns = ['select', 'title', 'id', 'status', 'submissions', 'lastSubmission'];
return columns.indexOf(column) + 1;
}
// Apply the current sort after refreshing the table
function applyCurrentSort() {
if (!currentSortColumn) return; // No sort to apply
const tbody = document.querySelector('#formsTable tbody');
const rows = Array.from(tbody.querySelectorAll('tr'));
rows.sort((a, b) => {
let aText = a.querySelector(`td:nth-child(${getColumnIndex(currentSortColumn)})`).innerText.trim();
let bText = b.querySelector(`td:nth-child(${getColumnIndex(currentSortColumn)})`).innerText.trim();
// Handle numeric and date sorting
if (currentSortColumn === 'submissions') {
aText = parseInt(aText) || 0;
bText = parseInt(bText) || 0;
} else if (currentSortColumn === 'lastSubmission') {
aText = new Date(aText).getTime() || 0;
bText = new Date(bText).getTime() || 0;
} else {
aText = aText.toLowerCase();
bText = bText.toLowerCase();
}
if (aText < bText) return currentSortOrder === 'asc' ? -1 : 1;
if (aText > bText) return currentSortOrder === 'asc' ? 1 : -1;
return 0;
});
// Re-append sorted rows
rows.forEach(row => tbody.appendChild(row));
}
// Function to update the sort arrows in the table headers
function updateSortArrows() {
// Remove existing arrows
document.querySelectorAll('#formsTable th').forEach(header => {
const sortArrow = header.querySelector('.sort-arrow');
if (sortArrow) {
sortArrow.innerHTML = '';
}
});
// Add arrow to the currently sorted column
if (currentSortColumn) {
const header = document.querySelector(`#formsTable th[data-column="${currentSortColumn}"]`);
const sortArrow = header.querySelector('.sort-arrow');
if (sortArrow) {
sortArrow.innerHTML = currentSortOrder === 'asc' ? '<i class="bi bi-caret-up-fill"></i>' : '<i class="bi bi-caret-down-fill"></i>';
}
}
}
// Password Authentication Logic
document.getElementById('authForm').addEventListener('submit', async function(event) {
event.preventDefault(); // Prevent form submission
const userPassword = document.getElementById('userPassword').value.trim();
const authError = document.getElementById('authError');
authError.style.display = 'none'; // Hide previous error
if (!userPassword) {
authError.textContent = 'Per favore inserisci una password valida.';
authError.style.display = 'block';
return;
}
try {
// Fetch the whitelist.txt file
const response = await fetch('whitelist.txt');
if (!response.ok) {
throw new Error(`Impossibile recuperare la whitelist. Stato: ${response.status}`);
}
const whitelistData = await response.text();
const lines = whitelistData.split('\n').map(line => line.trim()).filter(line => line.length > 0);
const userEntries = lines.map(line => {
const [encodedPassword, encodedApiKey] = line.split(',');
const password = atob(encodedPassword);
const apiKey = atob(encodedApiKey);
return { password, apiKey };
});
const userEntry = userEntries.find(entry => entry.password === userPassword);
if (userEntry) {
// Authentication successful
authModalInstance.hide();
document.getElementById('mainApp').style.display = 'block';
logMessage(`Utente autenticato con successo.`);
const loadDefaultApiKey = confirm("Vuoi caricare la API key salvata in memoria per la tua utenza?");
if (loadDefaultApiKey) {
document.getElementById('apiKey').value = userEntry.apiKey;
logMessage('API key predefinita caricata.');
} else {
logMessage('Inserisci la tua API key personalizzata.');
}
// Retrieve forms after authentication
retrieveForms();
} else {
// Show error message
authError.textContent = 'Password non autorizzata.';
authError.style.display = 'block';
logMessage(`Tentativo di accesso non autorizzato.`);
}
} catch (error) {
authError.textContent = `Errore durante l'autenticazione: ${error.message}`;
authError.style.display = 'block';
logMessage(`Errore durante l'autenticazione: ${error.message}`);
console.error(error);
}
});
// Display the authentication modal on page load
document.addEventListener('DOMContentLoaded', function() {
authModalInstance = new bootstrap.Modal(document.getElementById('authModal'), {
backdrop: 'static',
keyboard: false
});
authModalInstance.show();
// Start the progress bar timer on initial page load
startProgressBarTimer();
});
// Progress Bar Functions
// Function to update the progress bar
function updateProgressBar() {
const progressBar = document.getElementById('refreshProgressBar');
const countdown = document.getElementById('refreshCountdown');
const percent = ((refreshInterval - timeLeft) / refreshInterval) * 100;
progressBar.style.width = percent + '%';
progressBar.setAttribute('aria-valuenow', refreshInterval - timeLeft);
countdown.innerText = `${timeLeft} secondi`;
}
// Function to start the progress bar timer
function startProgressBarTimer() {
timeLeft = refreshInterval;
updateProgressBar();
clearInterval(progressBarTimer);
progressBarTimer = setInterval(() => {
timeLeft--;
if (timeLeft <= 0) {
retrieveForms();
timeLeft = refreshInterval;
}
updateProgressBar();
}, 1000);
}
// Function to reset the progress bar timer
function resetProgressBarTimer() {
timeLeft = refreshInterval;
updateProgressBar();
clearInterval(progressBarTimer);
startProgressBarTimer();
}
</script>
</body>
</html>