Productivity Technique Selector

Productivity Technique Selector

Productivity Technique Selector

Filter Techniques Based On Your Needs:











Recommended Techniques:

Add New Productivity Technique

Tags (select all that apply):
Time Focus:
Work Style:
Primary Goal:

Technique Library

No techniques in the library yet.

'; return; } techniques.forEach(tech => { const item = document.createElement('div'); item.className = 'pts-list-item'; item.innerHTML = ` ${escapeHtml(tech.name)}
`; configListContainer.appendChild(item); }); } /** Handles filter changes and updates results */ window.ptsApplyFilters = () => { // Use try-catch for safety, though querySelector shouldn't fail if HTML is correct try { // Get selected radio values const timeChecked = document.querySelector('input[name="time"]:checked'); const styleChecked = document.querySelector('input[name="style"]:checked'); const goalChecked = document.querySelector('input[name="goal"]:checked'); currentFilters.time = timeChecked ? timeChecked.value : 'any'; currentFilters.style = styleChecked ? styleChecked.value : 'any'; currentFilters.goal = goalChecked ? goalChecked.value : 'any'; renderResults(); } catch (error) { console.error("Error applying filters:", error); showMessage("Error updating results based on filters.", true); } } /** Adds a new technique */ window.ptsAddTechnique = () => { // Null checks already handled by initial check if (!newNameInput || !newDescInput || !addForm) return; const name = newNameInput.value.trim(); const description = newDescInput.value.trim(); const selectedTags = Array.from(addForm.querySelectorAll('input[name="tags"]:checked')).map(cb => cb.value); if (!name || !description) { showMessage("Please enter both a name and description.", true); return; } if (techniques.some(t => t.name.toLowerCase() === name.toLowerCase())) { showMessage("A technique with this name already exists.", true); return; } techniques.push({ id: 't' + Date.now(), name, description, tags: selectedTags }); addForm.reset(); // Clear form showMessage(null); // Clear errors renderConfigList(); // Update config view ptsApplyFilters(); // Update dashboard view in case it matches current filters }; /** Deletes a technique */ window.ptsDeleteTechnique = (id) => { if (!confirm('Are you sure you want to delete this technique?')) return; techniques = techniques.filter(t => t.id !== id); renderConfigList(); ptsApplyFilters(); // Update dashboard view }; /** Switches tabs */ window.ptsShowTab = (tabId, element) => { // Null checks already handled by initial check if (!container || !tabLinks) return; container.querySelectorAll('.pts-tab-content').forEach(tab => tab.classList.remove('pts-active')); container.querySelectorAll('.pts-tab-link').forEach(link => link.classList.remove('pts-active')); const tabToShow = container.querySelector('#' + tabId); if (tabToShow) tabToShow.classList.add('pts-active'); if (element) element.classList.add('pts-active'); currentTabId = tabId; updateNavButtons(); }; /** Handles nav buttons */ window.ptsNavigateTabs = (isNext) => { // Null checks already handled by initial check if (!container || !tabLinks) return; const targetTabId = isNext ? 'pts-tab-config' : 'pts-tab-dashboard'; const targetTabLink = container.querySelector(`.pts-tab-link[onclick*="'${targetTabId}'"]`); if(targetTabLink) targetTabLink.click(); }; /** Updates nav button states */ function updateNavButtons() { // Null checks already handled by initial check if (!prevBtn || !nextBtn) return; prevBtn.disabled = currentTabId === 'pts-tab-dashboard'; nextBtn.disabled = currentTabId === 'pts-tab-config'; } /** Downloads the filtered results as PDF */ function downloadPDF() { if (typeof jsPDF === 'undefined' || !jsPDF.autoTable) { showMessage("PDF library not loaded.", true); return; } if (filteredResults.length === 0) { showMessage("No recommendations to download based on current filters.", true); return; } showLoader(true); showMessage(null); try { const doc = new jsPDF(); const pageMargin = 40; const pageWidth = doc.internal.pageSize.getWidth(); let y = pageMargin; // 1. Title doc.setFontSize(18); doc.setFont(undefined, 'bold'); doc.text("Productivity Technique Recommendations", pageWidth / 2, y, { align: 'center' }); y += 30; doc.setFont(undefined, 'normal'); // 2. Filters Used (Optional but helpful context) doc.setFontSize(10); doc.text(`Filters Applied: Time(${currentFilters.time}), Style(${currentFilters.style}), Goal(${currentFilters.goal})`, pageMargin, y); y += 20; // 3. Results Table const tableHead = [["Technique", "Description", "Tags"]]; const tableBody = filteredResults.map(tech => [ tech.name, tech.description, tech.tags.map(tag => tag.replace(':', ': ').replace(/^(time|style|goal)/, match => match.charAt(0).toUpperCase() + match.slice(1))).join(', ') ]); doc.autoTable({ startY: y, head: tableHead, body: tableBody, theme: 'striped', headStyles: { fillColor: [0, 95, 204] }, // Primary color styles: { fontSize: 9, cellPadding: 4, valign: 'top' }, columnStyles: { 0: { cellWidth: 'auto' }, // Name 1: { cellWidth: '*' }, // Description (wrap) 2: { cellWidth: 'auto' } // Tags }, didParseCell: function (data) { // Make description wrap if (data.column.index === 1) { data.cell.styles.cellWidth = 'wrap'; } if (data.column.index === 2) { data.cell.styles.fontSize = 8; } // Smaller font for tags } }); doc.save("Productivity_Techniques.pdf"); } catch (e) { console.error("Error generating PDF:", e); showMessage("An error occurred while generating the PDF.", true); } finally { showLoader(false); } } /** Basic HTML escaping */ function escapeHtml(unsafe) { if (typeof unsafe !== 'string') return unsafe ?? ''; // Handle null/undefined return unsafe .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } /** Shows or hides loader */ function showLoader(show) { // Null checks already handled by initial check if (!loaderOverlay) return; loaderOverlay.style.display = show ? 'flex' : 'none'; } /** Displays messages */ function showMessage(message, isError = false) { // Null checks already handled by initial check if (!messageArea) return; if (!message) { messageArea.style.display = 'none'; return; } messageArea.textContent = message; messageArea.className = `mt-4 text-center font-medium ${isError ? 'text-red-600' : 'text-blue-600'}`; messageArea.style.display = 'block'; // Auto-hide message after a few seconds setTimeout(() => { if(messageArea.textContent === message) { messageArea.style.display = 'none'; } }, 4000); } // === Event Listeners === // Null check button before adding listener if (downloadBtn) { downloadBtn.addEventListener('click', downloadPDF); } // === Initial Render === renderConfigList(); ptsApplyFilters(); // Initial render of dashboard results updateNavButtons(); });
Scroll to Top