Legal Timeline Management System
Case Timeline Dashboard
Configure Case Events
Add New Event
Existing Events
| Date | Title | Actions |
|---|
No timeline data to display. Add events in the Data Configuration tab.
'; return; } const timelineContainer = document.createElement('div'); timelineContainer.className = 'relative border-l-2 border-blue-500 ml-4 py-4'; events.forEach((event, index) => { const eventElement = document.createElement('div'); eventElement.className = 'mb-8 ml-8 relative'; const dot = document.createElement('div'); dot.className = 'absolute -left-[38px] mt-1.5 h-4 w-4 rounded-full bg-blue-500 border-4 border-white'; const date = document.createElement('time'); date.className = 'mb-1 text-sm font-normal leading-none text-gray-500'; date.textContent = new Date(event.date).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }); const title = document.createElement('h3'); title.className = 'text-lg font-semibold text-gray-900'; title.textContent = event.title; const category = document.createElement('span'); category.className = 'bg-blue-100 text-blue-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded'; category.textContent = event.category; const description = document.createElement('p'); description.className = 'my-2 text-base font-normal text-gray-600'; description.textContent = event.description; eventElement.appendChild(dot); eventElement.appendChild(date); eventElement.appendChild(title); eventElement.appendChild(category); eventElement.appendChild(description); timelineContainer.appendChild(eventElement); }); timelineVisualization.appendChild(timelineContainer); } // --- TAB NAVIGATION --- window.changeTab = (tabIndex) => { if (tabIndex === currentTab) return; tabButtons[currentTab].classList.remove('active'); tabContents[currentTab].classList.remove('active'); currentTab = tabIndex; tabButtons[currentTab].classList.add('active'); tabContents[currentTab].classList.add('active'); updateNavButtons(); }; window.navigateTabs = (direction) => { const newTab = direction === 'next' ? currentTab + 1 : currentTab - 1; if (newTab >= 0 && newTab < tabButtons.length) { changeTab(newTab); } }; function updateNavButtons() { prevBtn.style.visibility = currentTab === 0 ? 'hidden' : 'visible'; nextBtn.style.visibility = currentTab === tabButtons.length - 1 ? 'hidden' : 'visible'; pdfDownloadSection.style.display = currentTab === 0 ? 'block' : 'none'; } // --- EVENT HANDLING --- if (eventForm) { eventForm.addEventListener('submit', function(e) { e.preventDefault(); const id = eventIdInput.value ? parseInt(eventIdInput.value) : null; const eventData = { date: document.getElementById('event-date').value, title: document.getElementById('event-title').value, description: document.getElementById('event-description').value, category: document.getElementById('event-category').value, }; if (id) { // Update existing event const index = events.findIndex(event => event.id === id); if (index !== -1) { events[index] = { ...events[index], ...eventData }; } } else { // Add new event events.push({ id: Date.now(), ...eventData }); } sortEvents(); renderAll(); resetForm(); // Optionally, switch back to dashboard after adding/editing // changeTab(0); }); } if (cancelEditBtn) { cancelEditBtn.addEventListener('click', resetForm); } window.app = { editEvent: (id) => { const event = events.find(e => e.id === id); if (!event) return; eventIdInput.value = event.id; document.getElementById('event-date').value = event.date; document.getElementById('event-title').value = event.title; document.getElementById('event-description').value = event.description; document.getElementById('event-category').value = event.category; formTitle.textContent = 'Edit Event'; cancelEditBtn.style.display = 'inline-block'; eventForm.querySelector('button[type="submit"]').textContent = 'Update Event'; }, deleteEvent: (id) => { // Using a custom modal would be better, but for simplicity: if (confirm('Are you sure you want to delete this event?')) { events = events.filter(event => event.id !== id); renderAll(); } } }; function resetForm() { eventForm.reset(); eventIdInput.value = ''; formTitle.textContent = 'Add New Event'; cancelEditBtn.style.display = 'none'; eventForm.querySelector('button[type="submit"]').textContent = 'Save Event'; } // --- PDF GENERATION --- if (downloadPdfBtn) { downloadPdfBtn.addEventListener('click', function() { const { jsPDF } = window.jspdf; const timelineContent = document.getElementById('timeline-visualization'); const toolTitle = "Legal Timeline Report"; html2canvas(timelineContent, { scale: 2 }).then(canvas => { const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'portrait', unit: 'px', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const canvasWidth = canvas.width; const canvasHeight = canvas.height; const ratio = canvasWidth / canvasHeight; const imgWidth = pdfWidth - 40; // with margin const imgHeight = imgWidth / ratio; let position = 20; // Add a professional header pdf.setFontSize(22); pdf.setFont('helvetica', 'bold'); pdf.text(toolTitle, pdfWidth / 2, position + 10, { align: 'center' }); position += 40; pdf.setDrawColor(100, 100, 100); pdf.line(20, position, pdfWidth - 20, position); position += 20; // Add the timeline image pdf.addImage(imgData, 'PNG', 20, position, imgWidth, imgHeight); let heightLeft = imgHeight; // Add footer const pageCount = pdf.internal.getNumberOfPages(); for(let i = 1; i <= pageCount; i++) { pdf.setPage(i); pdf.setFontSize(10); pdf.setTextColor(150); pdf.text('Page ' + i + ' of ' + pageCount, pdfWidth - 40, pdfHeight - 10); pdf.text('Generated by Legal Timeline Management System', 20, pdfHeight - 10); } pdf.save('Legal-Timeline.pdf'); }); }); } // --- START THE APP --- initializeApp(); });