Mindfulness & Productivity Balance Tool

Daily Wellness & Productivity Log

3
Very LowLowNeutralHighVery High

Weekly Overview & Insights

Overview for Week:


Select a week and click "Analyze Week" to view your overview.

Log for ${new Date(dateKey+'T00:00:00Z').toLocaleDateString()} loaded. You can edit and re-save.

`; } else { mpbTodayLogDisplayEl.innerHTML = `

No log for ${new Date(dateKey+'T00:00:00Z').toLocaleDateString()} yet. Fill the form to save.

`; } if(mpbDailyLogSavedMessageEl) mpbDailyLogSavedMessageEl.style.display = 'none'; } function mpbHandleDailyLogSubmit(e) { e.preventDefault(); const dateKey = mpbLogDateEl.value; if (!dateKey) { alert("Please select a date."); return; } const wellnessScores = {}; mpbWellnessFactorDefs.forEach(factor => { wellnessScores[factor.id] = parseInt(document.getElementById(`factor-${factor.id}`).value); }); mpbDailyLogs[dateKey] = { date: dateKey, wellnessScores: wellnessScores, productivityLevel: parseInt(mpbProductivityLevelEl.value), notes: mpbContextualNotesEl.value.trim() }; mpbSaveDailyLogs(); if(mpbDailyLogSavedMessageEl){ mpbDailyLogSavedMessageEl.textContent = `Log for ${new Date(dateKey+'T00:00:00Z').toLocaleDateString()} saved!`; mpbDailyLogSavedMessageEl.style.display = 'block'; setTimeout(() => { if(mpbDailyLogSavedMessageEl) mpbDailyLogSavedMessageEl.style.display = 'none'; }, 3000); } mpbLoadLogForDate(); } function mpbGetWeekDates(selectedDateStr) { const d = new Date(selectedDateStr + 'T00:00:00'); d.setHours(0,0,0,0); const day = d.getDay(); const diffToMonday = day === 0 ? -6 : 1 - day; const monday = new Date(d); monday.setDate(d.getDate() + diffToMonday); const sunday = new Date(monday); sunday.setDate(monday.getDate() + 6); return { start: monday, end: sunday }; } function mpbGenerateWeeklyOverview() { if (!mpbReviewWeekDateEl || !mpbSelectedReviewWeekDisplayEl || !mpbWeeklyOverviewAreaEl || !mpbLogHistoryTableBodyEl || !mpbNoLogsForWeekMessageEl || !mpbNoOverviewDataMessageEl || !mpbWeeklyAveragesDisplayEl || !mpbAvgProdValueEl || !mpbCorrelationInsightsEl || !mpbDownloadReportBtnEl || !mpbFactorAverageScoresChartEl) return; const selectedDateStr = mpbReviewWeekDateEl.value; if (!selectedDateStr) { mpbNoOverviewDataMessageEl.textContent = "Please select a date for the week to review."; mpbNoOverviewDataMessageEl.style.display = 'block'; mpbWeeklyOverviewAreaEl.style.display = 'none'; return; } const weekDates = mpbGetWeekDates(selectedDateStr); mpbSelectedReviewWeekDisplayEl.textContent = `${weekDates.start.toLocaleDateString()} - ${weekDates.end.toLocaleDateString()}`; const logsForWeek = []; let currentDateIter = new Date(weekDates.start); while (currentDateIter <= weekDates.end) { const dateKey = currentDateIter.toISOString().slice(0,10); if (mpbDailyLogs[dateKey]) { logsForWeek.push(mpbDailyLogs[dateKey]); } currentDateIter.setDate(currentDateIter.getDate() + 1); } while(mpbLogHistoryTableBodyEl.firstChild) mpbLogHistoryTableBodyEl.removeChild(mpbLogHistoryTableBodyEl.firstChild); if(mpbLogHistoryTableHeaderRowEl) { mpbLogHistoryTableHeaderRowEl.innerHTML = ''; let th = mpbLogHistoryTableHeaderRowEl.insertCell(); th.textContent = "Date"; mpbWellnessFactorDefs.forEach(f => { th = mpbLogHistoryTableHeaderRowEl.insertCell(); th.textContent = f.label.split(' ')[0]; }); th = mpbLogHistoryTableHeaderRowEl.insertCell(); th.textContent = "Productivity"; th = mpbLogHistoryTableHeaderRowEl.insertCell(); th.textContent = "Notes"; } if (logsForWeek.length === 0) { mpbNoLogsForWeekMessageEl.style.display = 'block'; mpbWeeklyAveragesDisplayEl.innerHTML = '

N/A

'; mpbAvgProdValueEl.textContent = 'N/A'; mpbFactorAverageScoresChartEl.innerHTML = '

No data for chart.

'; mpbCorrelationInsightsEl.innerHTML = '

No daily logs found for this week to generate insights.

'; mpbWeeklyOverviewAreaEl.style.display = 'block'; mpbDownloadReportBtnEl.style.display = 'none'; return; } mpbNoLogsForWeekMessageEl.style.display = 'none'; const weeklyAverages = {}; mpbWellnessFactorDefs.forEach(f => weeklyAverages[f.id] = { sum: 0, count: 0 }); let totalProductivitySum = 0, productivityCount = 0; logsForWeek.sort((a,b) => new Date(a.date) - new Date(b.date)).forEach(log => { const row = mpbLogHistoryTableBodyEl.insertRow(); row.insertCell().textContent = new Date(log.date+'T00:00:00Z').toLocaleDateString(); mpbWellnessFactorDefs.forEach(factor => { const score = log.wellnessScores[factor.id] !== undefined ? log.wellnessScores[factor.id] : 0; row.insertCell().textContent = score; weeklyAverages[factor.id].sum += score; weeklyAverages[factor.id].count++; }); row.insertCell().textContent = log.productivityLevel; const notesCell = row.insertCell(); notesCell.textContent = log.notes.substring(0,25)+(log.notes.length>25?'...':''); notesCell.title = log.notes; notesCell.classList.add('notes-cell'); totalProductivitySum += log.productivityLevel; productivityCount++; }); let avgWellnessHTML = ''; const factorAveragesForChart = []; mpbWellnessFactorDefs.forEach(f => { const avg = weeklyAverages[f.id].count > 0 ? (weeklyAverages[f.id].sum / weeklyAverages[f.id].count) : 0; avgWellnessHTML += `

${f.label}: ${avg.toFixed(1)}

`; factorAveragesForChart.push({label: f.label, value: avg, type: 'wellness'}); }); mpbWeeklyAveragesDisplayEl.innerHTML = avgWellnessHTML; const avgProd = productivityCount > 0 ? (totalProductivitySum / productivityCount) : 0; mpbAvgProdValueEl.textContent = avgProd.toFixed(1); factorAveragesForChart.push({label: "Productivity", value: avgProd, type: 'productivity'}); mpbRenderSimpleBarChart(factorAveragesForChart); let insightsHTML = '
    '; const avgProdNum = parseFloat(avgProd); mpbWellnessFactorDefs.forEach(f => { const avgFactorScore = weeklyAverages[f.id].count > 0 ? (weeklyAverages[f.id].sum / weeklyAverages[f.id].count) : null; if(avgFactorScore !== null && !isNaN(avgProdNum) && logsForWeek.length > 2) { // Need a few days for meaningful observation let highWellnessHighProdDays = 0; let lowWellnessLowProdDays = 0; logsForWeek.forEach(log => { if(log.wellnessScores[f.id] >= 4 && log.productivityLevel >=4) highWellnessHighProdDays++; if(log.wellnessScores[f.id] <= 2 && log.productivityLevel <=2) lowWellnessLowProdDays++; }); if (highWellnessHighProdDays >= logsForWeek.length * 0.4) { // If 40%+ days had this strong positive correlation insightsHTML += `
  • A number of days this week showed high '${f.label}' coinciding with high 'Productivity'. What elements contributed to these positive days?
  • `; } if (lowWellnessLowProdDays >= logsForWeek.length * 0.4) { insightsHTML += `
  • On several days, lower '${f.label}' appeared alongside lower 'Productivity'. Exploring the notes for these days might offer insights.
  • `; } } }); if(logsForWeek.filter(log => log.notes && (log.notes.toLowerCase().includes("stress") || log.notes.toLowerCase().includes("pressure") || log.notes.toLowerCase().includes("overwhelm"))).length >= Math.max(1, logsForWeek.length * 0.2) ){ // If stress mentioned on at least 20% of days (min 1) insightsHTML += `
  • Your notes mentioned terms like 'stress', 'pressure', or 'overwhelm' this week. How did these instances align with your wellness and productivity ratings on those specific days?
  • `; } if (avgProdNum >= 4 && avgWellnessHTML.includes("Sleep: ") && parseFloat(avgWellnessHTML.split("Sleep: ")[1].split("")[0]) >= 4) { insightsHTML += `
  • High average productivity this week seems to align with good average sleep quality. This is often a positive pattern.
  • `; } if (avgProdNum <= 2 && avgWellnessHTML.includes("Energy Level: ") && parseFloat(avgWellnessHTML.split("Energy Level: ")[1].split("")[0]) <= 2) { insightsHTML += `
  • Lower average productivity this week appears alongside lower average energy levels. What might have influenced your energy?
  • `; } if(insightsHTML === '
      ') insightsHTML += '
    • Reflect on your daily entries. What connections do you see between your wellness scores, productivity levels, and the day\'s events or notes?
    • '; insightsHTML += '
    '; mpbCorrelationInsightsEl.innerHTML = insightsHTML; mpbWeeklyOverviewAreaEl.style.display = 'block'; if(mpbDownloadReportBtnEl) mpbDownloadReportBtnEl.style.display = 'block'; } function mpbRenderSimpleBarChart(factorScoresData) { if (!mpbFactorAverageScoresChartEl) return; mpbFactorAverageScoresChartEl.innerHTML = ''; const maxValue = 5; factorScoresData.forEach(item => { const barDiv = document.createElement('div'); barDiv.classList.add('mpb-factor-bar'); const labelSpan = document.createElement('span'); labelSpan.classList.add('mpb-factor-bar-label'); labelSpan.textContent = item.label; const valueWrapper = document.createElement('div'); valueWrapper.classList.add('mpb-factor-bar-value-wrapper'); const valueBar = document.createElement('div'); valueBar.classList.add('mpb-factor-bar-value'); const percentageWidth = (item.value / maxValue) * 100; valueBar.style.width = `${Math.max(5, percentageWidth)}%`; // Min width 5% for visibility valueBar.textContent = item.value.toFixed(1); if(item.type === 'productivity'){ if(item.value < 2.5) valueBar.classList.add('low'); else if (item.value < 3.5) valueBar.classList.add('medium'); else valueBar.classList.add('high-prod'); } else { // wellness factor if(item.value < 2.5) valueBar.classList.add('low'); else if (item.value < 3.5) valueBar.classList.add('medium'); else valueBar.classList.add('high-well'); } valueWrapper.appendChild(valueBar); barDiv.appendChild(labelSpan); barDiv.appendChild(valueWrapper); mpbFactorAverageScoresChartEl.appendChild(barDiv); }); } function mpbDownloadPDF() { const selectedDateStr = mpbReviewWeekDateEl.value; if (!selectedDateStr || !mpbWeeklyOverviewAreaEl || mpbWeeklyOverviewAreaEl.style.display === 'none') { alert("Please analyze a week first."); return; } const weekDates = mpbGetWeekDates(selectedDateStr); const weekDisplay = `${weekDates.start.toLocaleDateString()} - ${weekDates.end.toLocaleDateString()}`; const logsForWeek = []; let currentDateIter = new Date(weekDates.start); while (currentDateIter <= weekDates.end) { const dateKey = currentDateIter.toISOString().slice(0,10); if (mpbDailyLogs[dateKey]) logsForWeek.push(mpbDailyLogs[dateKey]); currentDateIter.setDate(currentDateIter.getDate() + 1); } if (logsForWeek.length === 0 && (!mpbAvgProdValueEl || mpbAvgProdValueEl.textContent === 'N/A')) { alert("No data for this week to export."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF('p', 'pt', 'a4'); const primaryColorPDF = getComputedStyle(document.documentElement).getPropertyValue('--mpb-primary-color').trim(); const accentColorPDF = getComputedStyle(document.documentElement).getPropertyValue('--mpb-accent-color').trim(); const textColorPDF = getComputedStyle(document.documentElement).getPropertyValue('--mpb-text-color-dark').trim(); const whiteColorPDF = getComputedStyle(document.documentElement).getPropertyValue('--mpb-text-color-light').trim(); let yPos = 40; const leftMargin = 40; const contentWidth = doc.internal.pageSize.getWidth() - (2 * leftMargin); const lineSpacing = 14; doc.setFontSize(16); doc.setTextColor(primaryColorPDF); doc.text("Mental Wellness & Productivity - Weekly Report", doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' }); yPos += 20; doc.setFontSize(11); doc.setTextColor(textColorPDF); doc.text(`Week: ${weekDisplay}`, doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' }); yPos += 25; doc.setFontSize(12); doc.setFont(undefined, 'bold'); doc.setTextColor(primaryColorPDF); doc.text("Weekly Averages (1-5 Scale):", leftMargin, yPos); yPos += 18; doc.setFontSize(10); doc.setFont(undefined, 'normal'); doc.setTextColor(textColorPDF); const avgContainer = mpbWeeklyAveragesDisplayEl.querySelectorAll('p'); avgContainer.forEach(p => { yPos = checkPdfPageBreak(doc, yPos, lineSpacing); doc.text(p.textContent, leftMargin + 10, yPos); yPos += lineSpacing; }); yPos = checkPdfPageBreak(doc, yPos, lineSpacing); doc.text(`Average Productivity Level: ${mpbAvgProdValueEl.textContent}`, leftMargin + 10, yPos); yPos += lineSpacing + 5; const insightsContainer = mpbCorrelationInsightsEl.querySelector('ul'); if(insightsContainer && insightsContainer.children.length > 0 && insightsContainer.textContent.trim() !== "Reflect on your daily entries. Do you notice any connections between your wellness scores, productivity levels, and the day's events or notes?"){ yPos = checkPdfPageBreak(doc, yPos, 25); doc.setFontSize(12); doc.setFont(undefined, 'bold'); doc.setTextColor(primaryColorPDF); doc.text("Reflection Prompts from Your Data:", leftMargin, yPos); yPos += 18; doc.setFontSize(9); doc.setFont(undefined, 'normal'); doc.setTextColor(textColorPDF); Array.from(insightsContainer.children).forEach(li => { const lines = doc.splitTextToSize(li.textContent, contentWidth - 10); // Indent list items lines.forEach(line => { yPos = checkPdfPageBreak(doc, yPos, lineSpacing * 0.9); doc.text("- " + line, leftMargin + 10, yPos); yPos += lineSpacing * 0.9; }); }); yPos += 10; } if (logsForWeek.length > 0) { yPos = checkPdfPageBreak(doc, yPos, 40); doc.setFontSize(12); doc.setFont(undefined, 'bold'); doc.setTextColor(primaryColorPDF); doc.text("Daily Log Details for the Week:", leftMargin, yPos); yPos += 20; const tableColumns = ["Date"]; mpbWellnessFactorDefs.forEach(f => tableColumns.push(f.label.split('/')[0].trim())); tableColumns.push("Productivity"); tableColumns.push("Contextual Notes"); const tableRows = logsForWeek.sort((a,b)=>new Date(a.date) - new Date(b.date)).map(log => { const rowData = [new Date(log.date+'T00:00:00Z').toLocaleDateString()]; mpbWellnessFactorDefs.forEach(f => rowData.push(log.wellnessScores[f.id] || 'N/A')); rowData.push(log.productivityLevel); rowData.push(log.notes || ''); return rowData; }); doc.autoTable({ head: [tableColumns], body: tableRows, startY: yPos, theme: 'grid', headStyles: { fillColor: primaryColorPDF, textColor: whiteColorPDF, fontSize: 7, fontStyle: 'bold', cellPadding:2 }, styles: { fontSize: 7, cellPadding: 2, textColor: textColorPDF, overflow: 'linebreak' }, columnStyles: { 0:{cellWidth:50}, 6:{cellWidth:60}, 7:{cellWidth:'auto'} } }); } doc.save(`WellnessProductivityBalance_${weekDisplay.replace(/\s+/g, '').replace(/\//g,'-')}.pdf`); } function checkPdfPageBreak(doc, currentY, spaceNeeded) { if (currentY + spaceNeeded > doc.internal.pageSize.getHeight() - 40) { doc.addPage(); return 40; } return currentY; }
Scroll to Top