Volunteer Time Log Auto-Filler

Quickly fill volunteer time log forms with saved information

Size

32.8 KB

Version

1.2.4

Created

Mar 6, 2026

Updated

15 days ago

1// ==UserScript==
2// @name		Volunteer Time Log Auto-Filler
3// @description		Quickly fill volunteer time log forms with saved information
4// @version		1.2.4
5// @match		https://*.forms.office.com/*
6// @icon		https://cdn.forms.office.net/images/favicon.ico
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('Volunteer Time Log Auto-Filler loaded');
12
13    // Helper function to parse time string like "10am - 3pm"
14    function parseTimeRange(timeString) {
15        const parts = timeString.toLowerCase().split('-').map(s => s.trim());
16        if (parts.length !== 2) {
17            throw new Error('Invalid time format. Use format like "10am - 3pm"');
18        }
19
20        const parseTime = (timeStr) => {
21            // Match formats like: 10am, 10:30am, 3.30pm, 3:30pm
22            const match = timeStr.match(/(\d+)[:.]?(\d+)?\s*(am|pm)/i);
23            if (!match) {
24                throw new Error('Invalid time format. Use format like "10am" or "10:30pm"');
25            }
26            let hour = parseInt(match[1]);
27            const minute = match[2] ? parseInt(match[2]) : 0;
28            const ampm = match[3].toLowerCase();
29
30            console.log(`Parsed time "${timeStr}": hour=${hour}, minute=${minute}, ampm=${ampm}`);
31            return { hour, minute, ampm };
32        };
33
34        return {
35            start: parseTime(parts[0]),
36            end: parseTime(parts[1])
37        };
38    }
39
40    // Helper function to parse date string
41    function parseDate(dateString) {
42        if (!dateString || dateString.trim() === '') {
43            // Return today's date if no date specified
44            const today = new Date();
45            return `${today.getMonth() + 1}/${today.getDate()}/${today.getFullYear()}`;
46        }
47        
48        // Try to parse dd/mm/yy or dd/mm/yyyy format
49        const parts = dateString.trim().split('/');
50        if (parts.length === 3) {
51            const day = parseInt(parts[0]);
52            const month = parseInt(parts[1]);
53            let year = parseInt(parts[2]);
54            
55            // Handle 2-digit year (yy format)
56            if (year < 100) {
57                // Assume 20xx for years 00-99
58                year = 2000 + year;
59            }
60            
61            // Validate the date
62            if (day >= 1 && day <= 31 && month >= 1 && month <= 12 && year >= 2000) {
63                // Return in M/d/yyyy format for the form
64                return `${month}/${day}/${year}`;
65            }
66        }
67        
68        throw new Error('Invalid date format. Use format like "25/12/24" or "25/12/2024"');
69    }
70
71    // Helper function to click dropdown and select option
72    async function selectDropdownOption(questionId, value) {
73        console.log(`Selecting dropdown for ${questionId} with value: ${value}`);
74        
75        // Find the question container
76        const questionContainer = document.querySelector(`#${questionId}`).closest('[data-automation-id="questionItem"]');
77        
78        // Click the dropdown button to open it
79        const dropdownButton = questionContainer.querySelector('[role="button"]');
80        if (!dropdownButton) {
81            console.error('Dropdown button not found');
82            return false;
83        }
84        
85        dropdownButton.click();
86        
87        // Wait for dropdown to open
88        await new Promise(resolve => setTimeout(resolve, 300));
89        
90        // Find and click the option
91        const options = document.querySelectorAll('[role="option"]');
92        for (const option of options) {
93            const optionText = option.textContent.trim();
94            // Try exact match first
95            if (optionText === value.toString()) {
96                option.click();
97                await new Promise(resolve => setTimeout(resolve, 200));
98                console.log(`Selected option: ${optionText}`);
99                return true;
100            }
101            // Try numeric match (e.g., "3" matches "03" or "3")
102            if (!isNaN(value) && !isNaN(optionText) && parseInt(optionText) === parseInt(value)) {
103                option.click();
104                await new Promise(resolve => setTimeout(resolve, 200));
105                console.log(`Selected option: ${optionText}`);
106                return true;
107            }
108        }
109        
110        console.error(`Option "${value}" not found. Available options:`, Array.from(options).map(o => o.textContent.trim()));
111        return false;
112    }
113
114    // Helper function to select checkbox option
115    async function selectCheckboxOption(questionId, value) {
116        console.log(`Selecting checkbox for ${questionId} with value: ${value}`);
117        
118        // Find the question container
119        const questionContainer = document.querySelector(`#${questionId}`).closest('[data-automation-id="questionItem"]');
120        
121        // Find all checkbox items
122        const checkboxItems = questionContainer.querySelectorAll('[data-automation-id="choiceItem"]');
123        
124        for (const item of checkboxItems) {
125            const label = item.querySelector('label');
126            if (label && label.textContent.trim() === value) {
127                // Try clicking the label instead of the checkbox span
128                label.click();
129                await new Promise(resolve => setTimeout(resolve, 300));
130                console.log(`Checkbox "${value}" selected`);
131                return true;
132            }
133        }
134        
135        console.error(`Checkbox option "${value}" not found`);
136        return false;
137    }
138
139    // Helper function to select radio button option
140    async function selectRadioOption(questionId, value) {
141        console.log(`Selecting radio for ${questionId} with value: ${value}`);
142        
143        // Find the question container
144        const questionContainer = document.querySelector(`#${questionId}`).closest('[data-automation-id="questionItem"]');
145        
146        // Find all radio items
147        const radioItems = questionContainer.querySelectorAll('[data-automation-id="choiceItem"]');
148        
149        for (const item of radioItems) {
150            const label = item.querySelector('label');
151            if (label && label.textContent.includes(value)) {
152                const radio = item.querySelector('[data-automation-id="radio"]');
153                if (radio) {
154                    radio.click();
155                    await new Promise(resolve => setTimeout(resolve, 200));
156                    console.log(`Radio "${value}" selected`);
157                    return true;
158                }
159            }
160        }
161        
162        console.error(`Radio option "${value}" not found`);
163        return false;
164    }
165
166    // History management functions
167    async function saveSubmissionToHistory(name, email, duration, date) {
168        try {
169            const history = await getHistory();
170            const submission = {
171                name: name,
172                email: email,
173                duration: duration,
174                date: date,
175                timestamp: new Date().toISOString(),
176                submittedAt: new Date().toLocaleString()
177            };
178            
179            history.push(submission);
180            await GM.setValue('volunteer_history', JSON.stringify(history));
181            console.log('Submission saved to history:', submission);
182            return true;
183        } catch (error) {
184            console.error('Error saving to history:', error);
185            return false;
186        }
187    }
188
189    async function getHistory() {
190        try {
191            const historyJson = await GM.getValue('volunteer_history', '[]');
192            return JSON.parse(historyJson);
193        } catch (error) {
194            console.error('Error loading history:', error);
195            return [];
196        }
197    }
198
199    async function clearHistory() {
200        try {
201            await GM.setValue('volunteer_history', '[]');
202            console.log('History cleared');
203            return true;
204        } catch (error) {
205            console.error('Error clearing history:', error);
206            return false;
207        }
208    }
209
210    async function deleteHistoryEntry(timestamp) {
211        try {
212            const history = await getHistory();
213            const filteredHistory = history.filter(entry => entry.timestamp !== timestamp);
214            await GM.setValue('volunteer_history', JSON.stringify(filteredHistory));
215            console.log('History entry deleted:', timestamp);
216            return true;
217        } catch (error) {
218            console.error('Error deleting history entry:', error);
219            return false;
220        }
221    }
222
223    // Helper function to format date from M/d/yyyy to dd/mm/yyyy
224    function formatDateToDDMMYYYY(dateString) {
225        try {
226            // Parse M/d/yyyy format
227            const parts = dateString.split('/');
228            if (parts.length === 3) {
229                const month = parts[0].padStart(2, '0');
230                const day = parts[1].padStart(2, '0');
231                const year = parts[2];
232                return `${day}/${month}/${year}`;
233            }
234            return dateString;
235        } catch (error) {
236            return dateString;
237        }
238    }
239
240    // Helper function to format submitted date to dd/mm/yyyy format
241    function formatSubmittedDate(dateString) {
242        try {
243            // Parse the locale date string and convert to dd/mm/yyyy
244            const date = new Date(dateString);
245            if (!isNaN(date.getTime())) {
246                const day = date.getDate().toString().padStart(2, '0');
247                const month = (date.getMonth() + 1).toString().padStart(2, '0');
248                const year = date.getFullYear();
249                const hours = date.getHours().toString().padStart(2, '0');
250                const minutes = date.getMinutes().toString().padStart(2, '0');
251                const seconds = date.getSeconds().toString().padStart(2, '0');
252                return `${day}/${month}/${year}, ${hours}:${minutes}:${seconds}`;
253            }
254            return dateString;
255        } catch (error) {
256            return dateString;
257        }
258    }
259
260    async function exportHistory() {
261        try {
262            const history = await getHistory();
263            const dataStr = JSON.stringify(history, null, 2);
264            const dataBlob = new Blob([dataStr], { type: 'application/json' });
265            const url = URL.createObjectURL(dataBlob);
266            
267            const link = document.createElement('a');
268            link.href = url;
269            link.download = `volunteer_history_${new Date().toISOString().split('T')[0]}.json`;
270            document.body.appendChild(link);
271            link.click();
272            document.body.removeChild(link);
273            URL.revokeObjectURL(url);
274            
275            console.log('History exported successfully');
276            return true;
277        } catch (error) {
278            console.error('Error exporting history:', error);
279            return false;
280        }
281    }
282
283    async function importHistory(fileContent) {
284        try {
285            const importedData = JSON.parse(fileContent);
286            if (!Array.isArray(importedData)) {
287                throw new Error('Invalid history file format');
288            }
289            
290            const currentHistory = await getHistory();
291            const mergedHistory = [...currentHistory, ...importedData];
292            
293            // Remove duplicates based on timestamp
294            const uniqueHistory = mergedHistory.filter((item, index, self) =>
295                index === self.findIndex((t) => t.timestamp === item.timestamp)
296            );
297            
298            await GM.setValue('volunteer_history', JSON.stringify(uniqueHistory));
299            console.log('History imported and merged successfully');
300            return true;
301        } catch (error) {
302            console.error('Error importing history:', error);
303            throw error;
304        }
305    }
306
307    function groupHistoryByNameAndDate(history) {
308        const grouped = {};
309        
310        history.forEach(entry => {
311            if (!grouped[entry.name]) {
312                grouped[entry.name] = {};
313            }
314            if (!grouped[entry.name][entry.date]) {
315                grouped[entry.name][entry.date] = [];
316            }
317            grouped[entry.name][entry.date].push(entry);
318        });
319        
320        return grouped;
321    }
322
323    // Main fill function
324    async function fillForm(name, email, duration, date) {
325        try {
326            console.log('Starting form fill...', { name, email, duration, date });
327
328            // Parse the time range
329            const times = parseTimeRange(duration);
330            console.log('Parsed times:', times);
331
332            // Parse the date
333            const dateString = parseDate(date);
334            console.log('Parsed date:', dateString);
335
336            // Fill Name (Question 1)
337            const nameInput = document.querySelector('#QuestionId_r77aee835933d418eb77c8e58d3a829d1').closest('[data-automation-id="questionItem"]').querySelector('input[data-automation-id="textInput"]');
338            if (nameInput) {
339                nameInput.value = name;
340                nameInput.dispatchEvent(new Event('input', { bubbles: true }));
341                console.log('Name filled');
342            }
343
344            // Fill Email (Question 2)
345            const emailInput = document.querySelector('#QuestionId_r4848a2931f5d4bc0bd59975b96f7eb72').closest('[data-automation-id="questionItem"]').querySelector('input[data-automation-id="textInput"]');
346            if (emailInput) {
347                emailInput.value = email;
348                emailInput.dispatchEvent(new Event('input', { bubbles: true }));
349                console.log('Email filled');
350            }
351
352            // Fill Date (Question 3)
353            const dateInput = document.querySelector('#DatePicker0-label');
354            if (dateInput) {
355                dateInput.value = dateString;
356                dateInput.dispatchEvent(new Event('input', { bubbles: true }));
357                dateInput.dispatchEvent(new Event('change', { bubbles: true }));
358                console.log('Date filled:', dateString);
359            }
360
361            await new Promise(resolve => setTimeout(resolve, 500));
362
363            // Fill Start Time Hour (Question 4)
364            await selectDropdownOption('QuestionId_r9b6cf34c00ab4e529f7e369ee8195e2b', times.start.hour);
365
366            // Fill Start Time Minute (Question 5)
367            await selectDropdownOption('QuestionId_rd5ab020ea2f649f88b10f0d255085a79', times.start.minute.toString().padStart(2, '0'));
368
369            // Fill Start Time AM/PM (Question 6)
370            await selectDropdownOption('QuestionId_r61065e1c0eef4882a2c871e4effbb4f7', times.start.ampm.toUpperCase());
371
372            // Fill End Time Hour (Question 7)
373            await selectDropdownOption('QuestionId_r32af9366f9d146ed918e5d1e83f406c4', times.end.hour);
374
375            // Fill End Time Minute (Question 8)
376            await selectDropdownOption('QuestionId_rde751812596e477d8b5d7211188e8855', times.end.minute.toString().padStart(2, '0'));
377
378            // Fill End Time AM/PM (Question 9)
379            await selectDropdownOption('QuestionId_r1a19b78c3c6945dea4f0e4bfc7c57036', times.end.ampm.toUpperCase());
380
381            // Fill Activity (Question 10) - "Routine care support"
382            await new Promise(resolve => setTimeout(resolve, 500));
383            await selectCheckboxOption('QuestionId_rfd71f44e7bdd415b93d23ab35c610db6', 'Routine care support');
384
385            // Skip Question 11 (additional information)
386
387            // Check the consent radio button (Question 12)
388            await new Promise(resolve => setTimeout(resolve, 500));
389            await selectRadioOption('QuestionId_r3d51ddc7fb884938b2b49391386e30df', 'Yes');
390
391            console.log('Form filled successfully!');
392            
393            // Save to history
394            await saveSubmissionToHistory(name, email, duration, dateString);
395            
396            return true;
397
398        } catch (error) {
399            console.error('Error filling form:', error);
400            alert('Error: ' + error.message);
401            return false;
402        }
403    }
404
405    // Clear form function
406    async function clearForm() {
407        try {
408            console.log('Clearing form...');
409
410            // Clear Name (Question 1)
411            const nameInput = document.querySelector('#QuestionId_r77aee835933d418eb77c8e58d3a829d1').closest('[data-automation-id="questionItem"]').querySelector('input[data-automation-id="textInput"]');
412            if (nameInput) {
413                nameInput.value = '';
414                nameInput.dispatchEvent(new Event('input', { bubbles: true }));
415            }
416
417            // Clear Email (Question 2)
418            const emailInput = document.querySelector('#QuestionId_r4848a2931f5d4bc0bd59975b96f7eb72').closest('[data-automation-id="questionItem"]').querySelector('input[data-automation-id="textInput"]');
419            if (emailInput) {
420                emailInput.value = '';
421                emailInput.dispatchEvent(new Event('input', { bubbles: true }));
422            }
423
424            // Clear Date (Question 3)
425            const dateInput = document.querySelector('#DatePicker0-label');
426            if (dateInput) {
427                dateInput.value = '';
428                dateInput.dispatchEvent(new Event('input', { bubbles: true }));
429                dateInput.dispatchEvent(new Event('change', { bubbles: true }));
430            }
431
432            // Clear all dropdowns and checkboxes by reloading the page
433            location.reload();
434
435            console.log('Form cleared!');
436            return true;
437
438        } catch (error) {
439            console.error('Error clearing form:', error);
440            return false;
441        }
442    }
443
444    // Create the UI panel
445    function createPanel() {
446        const panel = document.createElement('div');
447        panel.id = 'volunteer-autofill-panel';
448        panel.innerHTML = `
449            <div style="position: fixed; top: 20px; right: 20px; background: white; border: 2px solid #0078d4; border-radius: 8px; padding: 20px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 10000; width: 320px; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; max-height: 90vh; overflow-y: auto;">
450                <h3 style="margin: 0 0 15px 0; color: #0078d4; font-size: 18px;">Quick Fill Volunteer Log</h3>
451                
452                <!-- Tab Navigation -->
453                <div style="display: flex; margin-bottom: 15px; border-bottom: 2px solid #e0e0e0;">
454                    <button id="tab-form" class="tab-btn" style="flex: 1; padding: 10px; background: none; border: none; border-bottom: 3px solid #0078d4; color: #0078d4; font-weight: 600; cursor: pointer; font-size: 13px;">
455                        Form Fill
456                    </button>
457                    <button id="tab-history" class="tab-btn" style="flex: 1; padding: 10px; background: none; border: none; border-bottom: 3px solid transparent; color: #666; font-weight: 600; cursor: pointer; font-size: 13px;">
458                        History
459                    </button>
460                </div>
461
462                <!-- Form Tab Content -->
463                <div id="form-content" style="display: block;">
464                    <div style="margin-bottom: 12px;">
465                        <label style="display: block; margin-bottom: 5px; font-weight: 600; color: #333; font-size: 13px;">Select Person:</label>
466                        <select id="autofill-person" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; box-sizing: border-box; background: white;">
467                            <option value="">-- Select --</option>
468                            <option value="adrian">Adrian Chen</option>
469                            <option value="charlene">Charlene Eng</option>
470                        </select>
471                    </div>
472                    <div style="margin-bottom: 12px;">
473                        <label style="display: block; margin-bottom: 5px; font-weight: 600; color: #333; font-size: 13px;">Name:</label>
474                        <input type="text" id="autofill-name" placeholder="Enter your name" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; box-sizing: border-box;" readonly>
475                    </div>
476                    <div style="margin-bottom: 12px;">
477                        <label style="display: block; margin-bottom: 5px; font-weight: 600; color: #333; font-size: 13px;">Email:</label>
478                        <input type="email" id="autofill-email" placeholder="your.email@example.com" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; box-sizing: border-box;" readonly>
479                    </div>
480                    <div style="margin-bottom: 12px;">
481                        <label style="display: block; margin-bottom: 5px; font-weight: 600; color: #333; font-size: 13px;">Duration:</label>
482                        <input type="text" id="autofill-duration" placeholder="e.g., 10am - 3pm" value="10am - 2.45pm" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; box-sizing: border-box;">
483                        <small style="color: #666; font-size: 11px;">Format: 10am - 3pm or 10:30am - 3:45pm</small>
484                    </div>
485                    <div style="margin-bottom: 15px;">
486                        <label style="display: block; margin-bottom: 5px; font-weight: 600; color: #333; font-size: 13px;">Date (optional):</label>
487                        <input type="text" id="autofill-date" placeholder="Leave blank for today" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; box-sizing: border-box;">
488                        <small style="color: #666; font-size: 11px;">Leave blank for today, or enter like "25/12/24"</small>
489                    </div>
490                    <button id="autofill-btn" style="width: 100%; padding: 10px; background: #0078d4; color: white; border: none; border-radius: 4px; font-size: 14px; font-weight: 600; cursor: pointer; transition: background 0.2s;">
491                        Fill Form
492                    </button>
493                    <button id="clear-btn" style="width: 100%; padding: 10px; background: #d13438; color: white; border: none; border-radius: 4px; font-size: 14px; font-weight: 600; cursor: pointer; transition: background 0.2s; margin-top: 8px;">
494                        Clear Form
495                    </button>
496                    <div id="autofill-status" style="margin-top: 10px; font-size: 12px; color: #666; text-align: center;"></div>
497                </div>
498
499                <!-- History Tab Content -->
500                <div id="history-content" style="display: none;">
501                    <div style="margin-bottom: 15px;">
502                        <button id="export-btn" style="width: 48%; padding: 8px; background: #107c10; color: white; border: none; border-radius: 4px; font-size: 13px; font-weight: 600; cursor: pointer; margin-right: 4%;">
503                            Export
504                        </button>
505                        <button id="import-btn" style="width: 48%; padding: 8px; background: #8764b8; color: white; border: none; border-radius: 4px; font-size: 13px; font-weight: 600; cursor: pointer;">
506                            Import
507                        </button>
508                        <input type="file" id="import-file" accept=".json" style="display: none;">
509                    </div>
510                    <div style="margin-bottom: 10px;">
511                        <button id="clear-history-btn" style="width: 100%; padding: 8px; background: #d13438; color: white; border: none; border-radius: 4px; font-size: 13px; font-weight: 600; cursor: pointer;">
512                            Clear All History
513                        </button>
514                    </div>
515                    <div id="history-list" style="margin-top: 15px; max-height: 400px; overflow-y: auto;">
516                        <p style="text-align: center; color: #666; font-size: 13px;">Loading history...</p>
517                    </div>
518                </div>
519            </div>
520        `;
521
522        document.body.appendChild(panel);
523
524        // Person data
525        const personData = {
526            adrian: {
527                name: 'Adrian Chen',
528                email: 'adrian.ch3n@gmail.com'
529            },
530            charlene: {
531                name: 'Charlene Eng',
532                email: 'charlene.zita@gmail.com'
533            }
534        };
535
536        // Tab switching functionality
537        const tabForm = document.getElementById('tab-form');
538        const tabHistory = document.getElementById('tab-history');
539        const formContent = document.getElementById('form-content');
540        const historyContent = document.getElementById('history-content');
541
542        tabForm.addEventListener('click', () => {
543            tabForm.style.borderBottom = '3px solid #0078d4';
544            tabForm.style.color = '#0078d4';
545            tabHistory.style.borderBottom = '3px solid transparent';
546            tabHistory.style.color = '#666';
547            formContent.style.display = 'block';
548            historyContent.style.display = 'none';
549        });
550
551        tabHistory.addEventListener('click', async () => {
552            tabHistory.style.borderBottom = '3px solid #0078d4';
553            tabHistory.style.color = '#0078d4';
554            tabForm.style.borderBottom = '3px solid transparent';
555            tabForm.style.color = '#666';
556            historyContent.style.display = 'block';
557            formContent.style.display = 'none';
558            await loadHistoryView();
559        });
560
561        // Handle person selection
562        const personSelect = document.getElementById('autofill-person');
563        const nameInput = document.getElementById('autofill-name');
564        const emailInput = document.getElementById('autofill-email');
565
566        personSelect.addEventListener('change', () => {
567            const selectedPerson = personSelect.value;
568            if (selectedPerson && personData[selectedPerson]) {
569                nameInput.value = personData[selectedPerson].name;
570                emailInput.value = personData[selectedPerson].email;
571            } else {
572                nameInput.value = '';
573                emailInput.value = '';
574            }
575        });
576
577        // Add button hover effects
578        const btn = document.getElementById('autofill-btn');
579        btn.addEventListener('mouseenter', () => btn.style.background = '#005a9e');
580        btn.addEventListener('mouseleave', () => btn.style.background = '#0078d4');
581
582        const clearBtn = document.getElementById('clear-btn');
583        clearBtn.addEventListener('mouseenter', () => clearBtn.style.background = '#a4262c');
584        clearBtn.addEventListener('mouseleave', () => clearBtn.style.background = '#d13438');
585
586        // Add click handler for Fill Form button
587        btn.addEventListener('click', async () => {
588            const name = document.getElementById('autofill-name').value.trim();
589            const email = document.getElementById('autofill-email').value.trim();
590            const duration = document.getElementById('autofill-duration').value.trim();
591            const date = document.getElementById('autofill-date').value.trim();
592
593            if (!name || !email || !duration) {
594                alert('Please fill in all fields');
595                return;
596            }
597
598            const statusDiv = document.getElementById('autofill-status');
599            statusDiv.textContent = 'Filling form...';
600            statusDiv.style.color = '#0078d4';
601
602            btn.disabled = true;
603            btn.style.opacity = '0.6';
604
605            const success = await fillForm(name, email, duration, date);
606
607            if (success) {
608                statusDiv.textContent = '✓ Form filled successfully!';
609                statusDiv.style.color = '#107c10';
610            } else {
611                statusDiv.textContent = '✗ Error filling form';
612                statusDiv.style.color = '#d13438';
613            }
614
615            btn.disabled = false;
616            btn.style.opacity = '1';
617        });
618
619        // Add click handler for Clear Form button
620        clearBtn.addEventListener('click', async () => {
621            if (confirm('Are you sure you want to clear the form? This will reload the page.')) {
622                await clearForm();
623            }
624        });
625
626        // History management handlers
627        document.getElementById('export-btn').addEventListener('click', async () => {
628            const success = await exportHistory();
629            if (success) {
630                alert('History exported successfully!');
631            } else {
632                alert('Failed to export history');
633            }
634        });
635
636        document.getElementById('import-btn').addEventListener('click', () => {
637            document.getElementById('import-file').click();
638        });
639
640        document.getElementById('import-file').addEventListener('change', async (e) => {
641            const file = e.target.files[0];
642            if (!file) return;
643
644            try {
645                const fileContent = await file.text();
646                await importHistory(fileContent);
647                alert('History imported successfully!');
648                await loadHistoryView();
649            } catch (error) {
650                alert('Failed to import history: ' + error.message);
651            }
652            e.target.value = ''; // Reset file input
653        });
654
655        document.getElementById('clear-history-btn').addEventListener('click', async () => {
656            if (confirm('Are you sure you want to clear all history? This cannot be undone.')) {
657                const success = await clearHistory();
658                if (success) {
659                    alert('History cleared successfully!');
660                    await loadHistoryView();
661                } else {
662                    alert('Failed to clear history');
663                }
664            }
665        });
666
667        console.log('Auto-fill panel created');
668    }
669
670    // Load and display history
671    async function loadHistoryView() {
672        const historyList = document.getElementById('history-list');
673        const history = await getHistory();
674
675        if (history.length === 0) {
676            historyList.innerHTML = '<p style="text-align: center; color: #666; font-size: 13px;">No submissions yet</p>';
677            return;
678        }
679
680        // Group by name and date
681        const grouped = groupHistoryByNameAndDate(history);
682
683        let html = '';
684        for (const name in grouped) {
685            html += `<div style="margin-bottom: 20px;">
686                <h4 style="margin: 0 0 10px 0; color: #0078d4; font-size: 15px; border-bottom: 2px solid #0078d4; padding-bottom: 5px;">${name}</h4>`;
687            
688            for (const date in grouped[name]) {
689                const entries = grouped[name][date];
690                const formattedDate = formatDateToDDMMYYYY(date);
691                html += `<div style="margin-bottom: 10px; padding: 10px; background: #f5f5f5; border-radius: 4px;">
692                    <div style="font-weight: 600; color: #333; font-size: 13px; margin-bottom: 5px;">📅 ${formattedDate}</div>`;
693                
694                entries.forEach(entry => {
695                    const formattedSubmittedDate = formatSubmittedDate(entry.submittedAt);
696                    html += `<div style="margin-left: 15px; padding: 5px 0; border-bottom: 1px solid #ddd; font-size: 12px; display: flex; justify-content: space-between; align-items: center;">
697                        <div style="flex: 1;">
698                            <div style="color: #555;">⏰ ${entry.duration}</div>
699                            <div style="color: #888; font-size: 11px;">Submitted: ${formattedSubmittedDate}</div>
700                        </div>
701                        <button class="delete-entry-btn" data-timestamp="${entry.timestamp}" style="background: #d13438; color: white; border: none; border-radius: 3px; padding: 4px 8px; font-size: 11px; cursor: pointer; margin-left: 10px;">
702                            Delete
703                        </button>
704                    </div>`;
705                });
706                
707                html += '</div>';
708            }
709            
710            html += '</div>';
711        }
712
713        historyList.innerHTML = html;
714
715        // Add event listeners to delete buttons
716        const deleteButtons = historyList.querySelectorAll('.delete-entry-btn');
717        deleteButtons.forEach(button => {
718            button.addEventListener('click', async (e) => {
719                const timestamp = e.target.getAttribute('data-timestamp');
720                if (confirm('Are you sure you want to delete this entry?')) {
721                    const success = await deleteHistoryEntry(timestamp);
722                    if (success) {
723                        await loadHistoryView();
724                    } else {
725                        alert('Failed to delete entry');
726                    }
727                }
728            });
729            
730            // Add hover effect
731            button.addEventListener('mouseenter', () => button.style.background = '#a4262c');
732            button.addEventListener('mouseleave', () => button.style.background = '#d13438');
733        });
734    }
735
736    // Wait for page to load
737    function init() {
738        if (document.readyState === 'loading') {
739            document.addEventListener('DOMContentLoaded', () => {
740                setTimeout(createPanel, 1000);
741            });
742        } else {
743            setTimeout(createPanel, 1000);
744        }
745    }
746
747    init();
748})();