Patent Filing Timeline Planner

Patent Filing Timeline Planner

Projected Patent Timeline

Months after: ${stagesToRender.find(s => s.key === stage.dependsOn)?.name || 'Start'}

`; durationInputsContainer.insertAdjacentHTML('beforeend', inputHtml); }); }; const calculateTimeline = () => { const startDate = filingDateInput.value; if (!startDate) { calculatedTimeline = []; return; } const filingType = filingTypeSelect.value; let currentStages = JSON.parse(JSON.stringify(timelineStages[filingType])); // Deep copy // Update durations from inputs document.querySelectorAll('.duration-input').forEach(input => { const key = input.dataset.key; const stage = currentStages.find(s => s.key === key); if(stage) stage.duration = parseInt(input.value, 10); }); if (includePctCheckbox.checked && filingType === 'provisional') { const pctStages = JSON.parse(JSON.stringify(timelineStages.pct)); document.querySelectorAll('.duration-input').forEach(input => { const key = input.dataset.key; const stage = pctStages.find(s => s.key === key); if(stage) stage.duration = parseInt(input.value, 10); }); currentStages.push(...pctStages); } const dates = {}; const result = []; currentStages.sort((a, b) => { // Simple sort to process dependencies if (a.dependsOn === null) return -1; if (b.dependsOn === null) return 1; return 0; }); currentStages.forEach(stage => { let baseDate; if(stage.dependsOn === null) { baseDate = new Date(startDate + 'T00:00:00'); // Fix timezone issue } else { baseDate = dates[stage.dependsOn]; } if(baseDate){ dates[stage.key] = addMonths(baseDate, stage.duration); result.push({ ...stage, date: dates[stage.key] }); } }); result.sort((a,b) => a.date - b.date); calculatedTimeline = result; }; const renderTimeline = () => { timelineContainer.innerHTML = ''; if (calculatedTimeline.length === 0) { timelineContainer.innerHTML = `

Please set an initial filing date in the Configuration tab to generate a timeline.

`; return; } const today = new Date(); calculatedTimeline.forEach(item => { const isCompleted = item.date < today; const itemHtml = `

${item.name}

${item.description || ''}

`; timelineContainer.insertAdjacentHTML('beforeend', itemHtml); }); }; // --- TAB NAVIGATION LOGIC --- window.switchTab = (tabName) => { currentTab = tabName; Object.keys(tabs).forEach(key => { tabs[key].classList.toggle('active', key === tabName); tabs[key].classList.toggle('inactive', key !== tabName); }); Object.keys(contents).forEach(key => { contents[key].classList.toggle('hidden', key !== tabName); }); updateNavButtons(); }; window.navigateTabs = (direction) => { const tabKeys = Object.keys(tabs); const currentIndex = tabKeys.indexOf(currentTab); let newIndex = (direction === 'next') ? currentIndex + 1 : currentIndex - 1; if (newIndex >= 0 && newIndex < tabKeys.length) { if (tabKeys[newIndex] === 'dashboard') { calculateTimeline(); renderTimeline(); } switchTab(tabKeys[newIndex]); } }; const updateNavButtons = () => { const tabKeys = Object.keys(tabs); const currentIndex = tabKeys.indexOf(currentTab); navButtons.prev.disabled = currentIndex === 0; navButtons.next.disabled = currentIndex === tabKeys.length - 1; }; // --- PDF GENERATION --- const generatePdf = () => { if(calculatedTimeline.length === 0) return; const { jsPDF } = window.jspdf; const doc = new jsPDF(); doc.setFontSize(18); doc.text('Patent Filing Timeline Report', 14, 22); doc.setFontSize(11); doc.text(`Based on initial filing date: ${formatDate(new Date(filingDateInput.value + 'T00:00:00'))}`, 14, 30); const tableColumn = ["Stage", "Description", "Projected Date"]; const tableRows = calculatedTimeline.map(item => [ item.name, item.description || '-', formatDate(item.date) ]); doc.autoTable({ head: [tableColumn], body: tableRows, startY: 40, theme: 'grid', headStyles: { fillColor: [79, 70, 229] }, }); doc.save('Patent_Filing_Timeline.pdf'); }; // --- INITIALIZATION & EVENT LISTENERS --- const initialize = () => { // Set default filing date to today for USA context const today = new Date(); const offset = today.getTimezoneOffset(); const todayLocal = new Date(today.getTime() - (offset*60*1000)); filingDateInput.value = todayLocal.toISOString().split('T')[0]; renderDurationInputs(); calculateTimeline(); renderTimeline(); updateNavButtons(); }; filingTypeSelect.addEventListener('change', renderDurationInputs); includePctCheckbox.addEventListener('change', renderDurationInputs); updateTimelineBtn.addEventListener('click', () => { calculateTimeline(); renderTimeline(); switchTab('dashboard'); }); downloadPdfBtn.addEventListener('click', generatePdf); initialize(); });
Scroll to Top