Online Smart Self-Improvement Feedback System

Smart Self-Improvement Feedback System

All data is stored securely in your browser. Nothing is ever uploaded.

${goal.text}

`; goalsContainer.innerHTML += goalHTML; }); }; const renderDashboard = () => { const countByCategory = {}; categories.forEach(c => countByCategory[c] = 0); feedback.forEach(item => { if (countByCategory[item.category] !== undefined) countByCategory[item.category]++; }); const chartCanvas = document.getElementById('category-chart'); if (categoryChart) categoryChart.destroy(); categoryChart = new Chart(chartCanvas, { type: 'bar', data: { labels: Object.keys(countByCategory), datasets: [{ label: 'Feedback Count', data: Object.values(countByCategory), backgroundColor: '#4f46e5' }] }, options: { responsive: true, maintainAspectRatio: false, indexAxis: 'y' } }); renderGoals(); }; // --- MODAL & DATA HANDLING --- const openModal = (id = null) => { if (id) { const item = feedback.find(f => f.id === id); modalTitle.textContent = 'Edit Feedback'; modalFeedbackId.value = id; modalFeedbackInput.value = item.text; modalCategorySelect.value = item.category; modalDateInput.value = item.date; modalDeleteBtn.classList.remove('hidden'); } else { modalTitle.textContent = 'Log New Feedback'; modalFeedbackId.value = ''; modalFeedbackInput.value = ''; modalCategorySelect.selectedIndex = 0; modalDateInput.valueAsDate = new Date(); modalDeleteBtn.classList.add('hidden'); } modal.style.display = 'block'; }; const closeModal = () => modal.style.display = 'none'; const saveFeedback = () => { const id = modalFeedbackId.value; const data = { text: modalFeedbackInput.value.trim(), category: modalCategorySelect.value, date: modalDateInput.value }; if (!data.text || !data.date) { alert("Feedback and date are required."); return; } if (id) { const index = feedback.findIndex(f => f.id == id); feedback[index] = { ...feedback[index], ...data }; } else { feedback.push({ id: Date.now(), ...data }); } saveData(); renderFeedbackLog(); closeModal(); }; const deleteFeedback = () => { if (confirm("Delete this feedback entry?")) { feedback = feedback.filter(f => f.id != modalFeedbackId.value); saveData(); renderFeedbackLog(); closeModal(); } }; const addCategory = () => { const name = newCategoryNameInput.value.trim(); if (name && !categories.includes(name)) { categories.push(name); saveData(); renderCategories(); newCategoryNameInput.value = ''; } }; const deleteCategory = (name) => { if (confirm(`Delete category "${name}"?`)) { categories = categories.filter(c => c !== name); saveData(); renderCategories(); } }; // --- AI ANALYSIS --- const analyzeThemes = async () => { if (feedback.length < 3) { alert("Please log at least 3 pieces of feedback for a meaningful analysis."); return; } const btnText = document.getElementById('ai-btn-text'); const btnLoader = document.getElementById('ai-btn-loader'); btnText.classList.add('hidden'); btnLoader.classList.remove('hidden'); aiAnalysisBtn.disabled = true; const feedbackText = feedback.map(f => `- ${f.text} (Category: ${f.category})`).join('\n'); const prompt = `Based on the following feedback items, identify 3-5 key themes or areas for improvement. For each theme, suggest one specific, actionable SMART goal. Present the output as a list of themes, each with a suggested goal.\n\nFeedback:\n${feedbackText}`; try { let chatHistory = [{ role: "user", parts: [{ text: prompt }] }]; const payload = { contents: chatHistory }; const apiKey = ""; const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent?key=${apiKey}`; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) throw new Error(`API Error: ${response.statusText}`); const result = await response.json(); const themesText = result.candidates[0].content.parts[0].text; const themesContainer = document.getElementById('ai-themes'); themesContainer.innerHTML = themesText.split('\n').map(line => { if (line.match(/^\d+\./) || line.toLowerCase().includes('theme:')) { return `

${line}

`; } if (line.toLowerCase().includes('goal:')) { const goalText = line.replace(/goal:/i, '').trim(); return `

${line}

`; } return `

${line}

`; }).join(''); } catch (error) { console.error("AI Analysis Error:", error); document.getElementById('ai-themes').textContent = "Sorry, an error occurred during analysis."; } finally { btnText.classList.remove('hidden'); btnLoader.classList.add('hidden'); aiAnalysisBtn.disabled = false; } }; // --- GOAL MANAGEMENT --- const addGoal = (text) => { goals.push({ id: Date.now(), text, completed: false }); saveData(); renderGoals(); }; const toggleGoal = (id) => { const goal = goals.find(g => g.id == id); if (goal) goal.completed = !goal.completed; saveData(); renderGoals(); }; const removeGoal = (id) => { goals = goals.filter(g => g.id != id); saveData(); renderGoals(); }; // --- TAB MANAGEMENT & PDF --- window.changeTab = (tabId) => { currentTab = tabId; ['tab1', 'tab2', 'tab3'].forEach(id => { document.getElementById(id).classList.toggle('hidden', id !== tabId); document.getElementById(`${id}-button`).classList.toggle('active', id === tabId); }); if (tabId === 'tab2') renderDashboard(); updateButtonVisibility(); }; const updateButtonVisibility = () => { const prevBtn = document.getElementById('prev-button'); const nextBtn = document.getElementById('next-button'); const downloadBtn = document.getElementById('download-pdf-button'); prevBtn.classList.toggle('hidden', currentTab === 'tab1'); nextBtn.classList.toggle('hidden', currentTab === 'tab3'); downloadBtn.classList.toggle('hidden', currentTab !== 'tab2'); }; window.handleNext = () => changeTab(['tab1', 'tab2', 'tab3'][['tab1', 'tab2', 'tab3'].indexOf(currentTab) + 1]); window.handlePrev = () => changeTab(['tab1', 'tab2', 'tab3'][['tab1', 'tab2', 'tab3'].indexOf(currentTab) - 1]); window.downloadPDF = async () => { try { const canvas = await html2canvas(document.getElementById('insights-content'), { scale: 2 }); const pdf = new jspdf.jsPDF({ orientation: 'portrait', unit: 'px', format: 'a4' }); const newWidth = pdf.internal.pageSize.getWidth() - 80; const newHeight = (canvas.height * newWidth) / canvas.width; pdf.addImage(canvas.toDataURL('image/png'), 'PNG', 40, 40, newWidth, newHeight); pdf.save('self-improvement-insights.pdf'); } catch (e) { alert("Error generating PDF."); } }; // --- EVENT LISTENERS --- document.getElementById('add-feedback-btn').addEventListener('click', () => openModal()); feedbackLogContainer.addEventListener('click', (e) => { if (e.target.tagName === 'BUTTON' && e.target.dataset.id) openModal(parseInt(e.target.dataset.id)); }); modalSaveBtn.addEventListener('click', saveFeedback); modalCancelBtn.addEventListener('click', closeModal); modalDeleteBtn.addEventListener('click', deleteFeedback); addCategoryBtn.addEventListener('click', addCategory); categoryList.addEventListener('click', (e) => { if (e.target.tagName === 'BUTTON' && e.target.dataset.name) deleteCategory(e.target.dataset.name); }); aiAnalysisBtn.addEventListener('click', analyzeThemes); document.getElementById('insights-content').addEventListener('click', (e) => { if (e.target.classList.contains('add-goal-btn')) addGoal(e.target.dataset.goal); if (e.target.tagName === 'INPUT' && e.target.type === 'checkbox') toggleGoal(e.target.dataset.id); if (e.target.tagName === 'BUTTON' && !e.target.classList.contains('add-goal-btn')) removeGoal(e.target.dataset.id); }); // --- INITIALIZATION --- loadData(); renderFeedbackLog(); renderCategories(); updateButtonVisibility(); });
Scroll to Top