Personal Growth Progress Tracker

Personal Growth Progress Tracker

Define or Update Growth Goal

Your Growth Goals

Log Activity / Milestone

Recent Activity Logs (for selected goal)
DateActivityProgressTime SpentSelf-AssessmentActions

View Progress & Insights

'; return; } pgpt_growthGoals.sort((a,b)=>a.name.localeCompare(b.name)).forEach(goal => { const card = document.createElement('div'); card.className = 'pgpt-goal-card'; const unitDisplay = goal.targetUnit === 'Custom' ? goal.customUnitName : goal.targetUnit; const progressPercent = goal.targetMetricValue > 0 ? (goal.currentProgressValue / goal.targetMetricValue * 100) : 0; card.innerHTML = `
${goal.name}

Target: ${goal.targetMetricValue} ${unitDisplay} ${goal.targetDate ? `by ${goal.targetDate}` : ''}

Current Progress: ${goal.currentProgressValue.toFixed(1)} ${unitDisplay} (${progressPercent.toFixed(1)}%)

${progressPercent.toFixed(1)}%

${goal.description || 'No description.'}

`; container.appendChild(card); }); } function pgpt_populateGoalSelects() { const selects = [ document.getElementById('pgpt_selectGoalForLog'), document.getElementById('pgpt_selectGoalForProgressView') ]; selects.forEach((select, index) => { if (!select) return; const currentVal = select.value; select.innerHTML = (index === 1) ? '' : ''; pgpt_growthGoals.sort((a,b)=>a.name.localeCompare(b.name)).forEach(goal => { const option = document.createElement('option'); option.value = goal.id; option.textContent = goal.name; select.appendChild(option); }); if (pgpt_growthGoals.find(g => g.id == currentVal) || (index === 1 && currentVal === "overall")) { select.value = currentVal; } else if (index === 1) { // For progress view, default to overall if previous invalid select.value = "overall"; } else { // For log activity, if prev invalid, it will be blank select.value = ""; } }); } // --- Tab 2: Log Activity --- function pgpt_updateLogFormUnits() { const goalId = document.getElementById('pgpt_selectGoalForLog').value; const unitDisplayEl = document.getElementById('pgpt_logUnitDisplay'); if (!unitDisplayEl) return; if (goalId) { const goal = pgpt_growthGoals.find(g => g.id == goalId); if (goal) { unitDisplayEl.textContent = goal.targetUnit === 'Custom' ? goal.customUnitName : goal.targetUnit; pgpt_renderRecentLogsTable(); // Refresh table when goal changes return; } } unitDisplayEl.textContent = 'Unit'; // Default if no goal selected pgpt_renderRecentLogsTable(); // Clear/show placeholder if no goal } function pgpt_clearLogEntryForm() { document.getElementById('pgpt_logEntryId').value = ''; // Don't clear goal selection or date, user might be logging multiple entries for same goal/date // document.getElementById('pgpt_selectGoalForLog').value = ''; // document.getElementById('pgpt_logDate').value = PGPT_CONTEXT_DATE_STR; document.getElementById('pgpt_activityDescription').value = ''; document.getElementById('pgpt_logTimeSpentHours').value = ''; document.getElementById('pgpt_logTimeSpentMinutes').value = ''; document.getElementById('pgpt_logQuantitativeProgress').value = ''; document.getElementById('pgpt_logNotes').value = ''; document.getElementById('pgpt_logSelfAssessment').value = ''; document.getElementById('pgpt_saveLogEntryButton').textContent = 'Add Log Entry'; const cancelBtn = document.getElementById('pgpt_cancelLogEntryEditButton'); if(cancelBtn) cancelBtn.style.display = 'none'; } function pgpt_saveLogEntry() { const id = document.getElementById('pgpt_logEntryId').value; const goalId = document.getElementById('pgpt_selectGoalForLog').value; const date = document.getElementById('pgpt_logDate').value; const activity = document.getElementById('pgpt_activityDescription').value.trim(); const timeHours = parseInt(document.getElementById('pgpt_logTimeSpentHours').value) || 0; const timeMinutes = parseInt(document.getElementById('pgpt_logTimeSpentMinutes').value) || 0; const timeSpentMinutes = (timeHours * 60) + timeMinutes; const quantitativeProgress = parseFloat(document.getElementById('pgpt_logQuantitativeProgress').value) || 0; const notes = document.getElementById('pgpt_logNotes').value.trim(); const selfAssessment = document.getElementById('pgpt_logSelfAssessment').value ? parseInt(document.getElementById('pgpt_logSelfAssessment').value) : null; if (!goalId) { alert("Please select a goal to log against."); return; } if (!date) { alert("Please select the date of activity."); return; } if (!activity) { alert("Activity description is required."); return; } // quantitativeProgress can be 0 if it's just time spent or reflection const logEntry = { goalId: parseInt(goalId), date, activity, timeSpentMinutes, quantitativeProgress, notes, selfAssessment }; if (id) { const index = pgpt_progressLogs.findIndex(l => l.id == id); if(index > -1) pgpt_progressLogs[index] = { ...pgpt_progressLogs[index], ...logEntry }; } else { pgpt_progressLogs.push({ id: Date.now(), ...logEntry }); } pgpt_updateGoalCurrentProgress(parseInt(goalId)); pgpt_clearLogEntryForm(); pgpt_renderRecentLogsTable(); pgpt_renderGoalsList(); // To update progress bars on goal cards } function pgpt_updateGoalCurrentProgress(goalId) { const goal = pgpt_growthGoals.find(g => g.id == goalId); if (!goal) return; const relevantLogs = pgpt_progressLogs.filter(log => log.goalId == goalId); goal.currentProgressValue = relevantLogs.reduce((sum, log) => sum + (log.quantitativeProgress || 0), 0); if (relevantLogs.length > 0) { // Update last log date goal.lastLogDate = relevantLogs.sort((a,b) => new Date(b.date) - new Date(a.date))[0].date; } else { goal.lastLogDate = ''; } } function pgpt_editLogEntry(logId){ const log = pgpt_progressLogs.find(l => l.id == logId); if(log){ document.getElementById('pgpt_logEntryId').value = log.id; document.getElementById('pgpt_selectGoalForLog').value = log.goalId; pgpt_updateLogFormUnits(); // Update units based on selected goal document.getElementById('pgpt_logDate').value = log.date; document.getElementById('pgpt_activityDescription').value = log.activity; document.getElementById('pgpt_logTimeSpentHours').value = Math.floor(log.timeSpentMinutes / 60); document.getElementById('pgpt_logTimeSpentMinutes').value = log.timeSpentMinutes % 60; document.getElementById('pgpt_logQuantitativeProgress').value = log.quantitativeProgress; document.getElementById('pgpt_logNotes').value = log.notes; document.getElementById('pgpt_logSelfAssessment').value = log.selfAssessment || ''; document.getElementById('pgpt_saveLogEntryButton').textContent = 'Update Log Entry'; const cancelBtn = document.getElementById('pgpt_cancelLogEntryEditButton'); if(cancelBtn) cancelBtn.style.display = 'inline-block'; } } function pgpt_deleteLogEntry(logId){ const logToDelete = pgpt_progressLogs.find(l => l.id == logId); if (logToDelete && confirm("Delete this log entry?")) { pgpt_progressLogs = pgpt_progressLogs.filter(l => l.id != logId); pgpt_updateGoalCurrentProgress(logToDelete.goalId); // Recalculate goal progress pgpt_renderRecentLogsTable(); pgpt_renderGoalsList(); } } function pgpt_renderRecentLogsTable() { const goalId = document.getElementById('pgpt_selectGoalForLog').value; const tbody = document.getElementById('pgpt_recentLogsTable')?.getElementsByTagName('tbody')[0]; if (!tbody) return; tbody.innerHTML = ''; if (!goalId) { tbody.innerHTML = `Select a goal to see recent logs.`; return; } const logsForGoal = pgpt_progressLogs.filter(log => log.goalId == goalId) .sort((a,b) => new Date(b.date) - new Date(a.date) || b.id - a.id) // Sort by date desc, then by id desc .slice(0, 5); // Show last 5 if (logsForGoal.length === 0) { tbody.innerHTML = `No logs for this goal yet.`; return; } logsForGoal.forEach(log => { const row = tbody.insertRow(); row.insertCell().textContent = log.date; row.insertCell().textContent = log.activity; const goal = pgpt_growthGoals.find(g => g.id == log.goalId); const unit = goal ? (goal.targetUnit === 'Custom' ? goal.customUnitName : goal.targetUnit) : ''; row.insertCell().textContent = `${log.quantitativeProgress} ${unit}`; row.insertCell().textContent = pgpt_formatMinutesToHHMM(log.timeSpentMinutes); row.insertCell().textContent = log.selfAssessment ? `${log.selfAssessment}/5` : 'N/A'; const actionsCell = row.insertCell(); actionsCell.innerHTML = ``; }); } // --- Tab 3: View Progress --- function pgpt_displayProgressView() { const viewGoalId = document.getElementById('pgpt_selectGoalForProgressView').value; const container = document.getElementById('pgpt_progressViewContainer'); if(!container) return; container.innerHTML = ''; // Clear previous view if (viewGoalId === "overall") { container.innerHTML = '

Overall Progress Summary

'; if (pgpt_growthGoals.length === 0) { container.innerHTML += '

No goals defined yet.

'; return; } pgpt_growthGoals.forEach(goal => { const unitDisplay = goal.targetUnit === 'Custom' ? goal.customUnitName : goal.targetUnit; const progressPercent = goal.targetMetricValue > 0 ? (goal.currentProgressValue / goal.targetMetricValue * 100) : 0; const card = document.createElement('div'); card.className = 'pgpt-goal-card'; // Reuse card style card.innerHTML = `
${goal.name}

Target: ${goal.targetMetricValue} ${unitDisplay} ${goal.targetDate ? `by ${goal.targetDate}` : ''}

Current: ${goal.currentProgressValue.toFixed(1)} ${unitDisplay} (${progressPercent.toFixed(1)}%)

${progressPercent.toFixed(1)}%
${goal.lastLogDate ? `

Last Log: ${goal.lastLogDate}

` : ''}`; container.appendChild(card); }); } else { const goal = pgpt_growthGoals.find(g => g.id == viewGoalId); if (!goal) { container.innerHTML = '

Select a goal to view its progress.

'; return; } const unitDisplay = goal.targetUnit === 'Custom' ? goal.customUnitName : goal.targetUnit; const progressPercent = goal.targetMetricValue > 0 ? (goal.currentProgressValue / goal.targetMetricValue * 100) : 0; container.innerHTML = `

Progress for: ${goal.name}

Description: ${goal.description || 'N/A'}

Target: ${goal.targetMetricValue} ${unitDisplay} ${goal.targetDate ? `by ${goal.targetDate}` : ''}

Current Progress: ${goal.currentProgressValue.toFixed(1)} ${unitDisplay} (${progressPercent.toFixed(1)}%)

${progressPercent.toFixed(1)}%
Activity Log:
`; const logTable = document.createElement('table'); logTable.className = 'pgpt-data-table'; logTable.innerHTML = `DateActivity/MilestoneProgress (${unitDisplay})Time SpentNotesSelf-Assessment`; const logTbody = logTable.getElementsByTagName('tbody')[0]; const logsForThisGoal = pgpt_progressLogs.filter(log => log.goalId == viewGoalId).sort((a,b) => new Date(b.date) - new Date(a.date)); if (logsForThisGoal.length === 0) { logTbody.innerHTML = `No activities logged for this goal yet.`; } else { logsForThisGoal.forEach(log => { const row = logTbody.insertRow(); row.insertCell().textContent = log.date; row.insertCell().textContent = log.activity; row.insertCell().textContent = log.quantitativeProgress; row.insertCell().textContent = pgpt_formatMinutesToHHMM(log.timeSpentMinutes); row.insertCell().textContent = log.notes || '-'; row.insertCell().textContent = log.selfAssessment ? `${log.selfAssessment}/5` : 'N/A'; }); } container.appendChild(logTable); } } // --- PDF Download --- function pgpt_downloadPDF() { const viewGoalId = document.getElementById('pgpt_selectGoalForProgressView').value; if (!viewGoalId) { alert("Select a goal or 'Overall Summary' to generate PDF."); return; } const doc = new jsPDF(); const primaryColorPDF = getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim(); const textColorPDF = getComputedStyle(document.documentElement).getPropertyValue('--text-color').trim(); const whiteColorPDF = '#FFFFFF'; doc.setFontSize(18); doc.setTextColor(primaryColorPDF); doc.text("Personal Growth Progress Report", 14, 20); doc.setFontSize(10); doc.setTextColor(textColorPDF); doc.text(`Report Date: ${PGPT_CONTEXT_DATE_STR}`, 14, 28); doc.text(`Generated On: ${PGPT_GENERATED_ON_STRING}`, 14, 33); let currentY = 45; if (viewGoalId === "overall") { doc.setFontSize(14); doc.setFont(undefined, 'bold'); doc.setTextColor(primaryColorPDF); doc.text("Overall Goals Summary", 14, currentY); currentY += 10; const overallCols = ["Goal Name", "Target", "Current Progress", "% Complete", "Target Date"]; const overallRows = pgpt_growthGoals.map(goal => { const unit = goal.targetUnit === 'Custom' ? goal.customUnitName : goal.targetUnit; const perc = goal.targetMetricValue > 0 ? (goal.currentProgressValue / goal.targetMetricValue * 100) : 0; return [ goal.name, `${goal.targetMetricValue} ${unit}`, `${goal.currentProgressValue.toFixed(1)} ${unit}`, `${perc.toFixed(1)}%`, goal.targetDate || 'N/A' ]; }); if (overallRows.length > 0) { doc.autoTable({ head: [overallCols], body: overallRows, startY: currentY, theme: 'grid', headStyles: {fillColor: primaryColorPDF, textColor: whiteColorPDF, fontSize:9}, styles:{fontSize:8}}); } else { doc.setFontSize(10); doc.setFont(undefined, 'normal'); doc.setTextColor(textColorPDF); doc.text("No goals defined to summarize.", 16, currentY); } } else { const goal = pgpt_growthGoals.find(g => g.id == viewGoalId); if (!goal) { alert("Selected goal not found for PDF."); return; } const unit = goal.targetUnit === 'Custom' ? goal.customUnitName : goal.targetUnit; const progressPercent = goal.targetMetricValue > 0 ? (goal.currentProgressValue / goal.targetMetricValue * 100) : 0; doc.setFontSize(14); doc.setFont(undefined, 'bold'); doc.setTextColor(primaryColorPDF); doc.text(`Progress for: ${goal.name}`, 14, currentY); currentY += 10; doc.setFontSize(10); doc.setFont(undefined, 'normal'); doc.setTextColor(textColorPDF); if(goal.description) { doc.text(`Description: ${goal.description}`, 16, currentY); currentY +=5; } doc.text(`Target: ${goal.targetMetricValue} ${unit} ${goal.targetDate ? `by ${goal.targetDate}` : ''}`, 16, currentY); currentY += 5; doc.text(`Current Progress: ${goal.currentProgressValue.toFixed(1)} ${unit} (${progressPercent.toFixed(1)}%)`, 16, currentY); currentY += 10; doc.setFontSize(12); doc.setFont(undefined, 'bold'); doc.setTextColor(primaryColorPDF); doc.text("Activity Log:", 14, currentY); currentY +=7; const logs = pgpt_progressLogs.filter(l => l.goalId == viewGoalId).sort((a,b) => new Date(a.date) - new Date(b.date)); const logCols = ["Date", "Activity/Milestone", `Progress (${unit})`, "Time Spent", "Notes", "Self-Assessment"]; const logRows = logs.map(l => [ l.date, l.activity, l.quantitativeProgress, pgpt_formatMinutesToHHMM(l.timeSpentMinutes), l.notes || '-', l.selfAssessment ? `${l.selfAssessment}/5` : 'N/A' ]); if (logRows.length > 0) { doc.autoTable({ head: [logCols], body: logRows, startY: currentY, theme: 'grid', headStyles: {fillColor: primaryColorPDF, textColor: whiteColorPDF, fontSize:9}, styles:{fontSize:8, cellPadding:1.5}, columnStyles: { 2: {halign:'right'}, 3:{halign:'center'}, 5:{halign:'center'}} }); } else { doc.setFontSize(10); doc.setFont(undefined, 'normal'); doc.setTextColor(textColorPDF); doc.text("No activities logged for this goal.", 16, currentY); } } doc.save(`Personal_Growth_Progress_${viewGoalId === 'overall' ? 'Overall' : pgpt_growthGoals.find(g=>g.id==viewGoalId)?.name.replace(/ /g,'_') || 'Goal'}_${PGPT_CONTEXT_DATE_STR}.pdf`); }
Scroll to Top