IBS Symptom Diary

IBS Symptom Diary

Track your symptoms, identify triggers, and gain insights.

No Data Yet

Start by adding an entry in the "Log Entry" tab to see your trends here.

Entry Details

Symptoms (0=None, 10=Severe)

Bowel Movements

Select your most common stool type for the day based on the Bristol Stool Chart.

Potential Triggers

Date Symptoms (B/P/G) Stool Type Stress Actions

Download Your Symptom Report

Generate a professional PDF of your diary entries to share with your healthcare provider. Select a date range to include in the report.

Type ${item.type}

${item.desc}

`).join(''); bristolSelector.querySelectorAll('.bristol-type').forEach(el => { el.addEventListener('click', () => { bristolSelector.querySelectorAll('.bristol-type').forEach(i => i.classList.remove('selected')); el.classList.add('selected'); document.getElementById('bristolType').value = el.dataset.type; }); }); }; const renderHistory = () => { historyTableBody.innerHTML = ''; if (diaryEntries.length === 0) { historyTableBody.innerHTML = `No entries found.`; return; } diaryEntries.forEach(entry => { const row = document.createElement('tr'); row.innerHTML = ` ${new Date(entry.date).toLocaleDateString()} ${entry.bloating}/${entry.pain}/${entry.gas} Type ${entry.bristolType || 'N/A'} ${entry.stress} `; row.querySelector('button[data-id][class*="text-blue-600"]').addEventListener('click', () => editEntry(entry.id)); row.querySelector('button[data-id][class*="text-red-600"]').addEventListener('click', () => deleteEntry(entry.id)); historyTableBody.appendChild(row); }); }; const renderDashboard = () => { const hasData = diaryEntries.length > 0; noDataMessage.style.display = hasData ? 'none' : 'block'; document.getElementById('dashboard-content').querySelectorAll('.chart-container').forEach(c => c.style.display = hasData ? 'block' : 'none'); if (!hasData) { Object.values(charts).forEach(chart => chart.destroy()); charts = {}; return; } const sortedEntries = [...diaryEntries].sort((a, b) => new Date(a.date) - new Date(b.date)); const labels = sortedEntries.map(e => new Date(e.date)); // Symptom Trend Chart const symptomData = { labels, datasets: [ { label: 'Bloating', data: sortedEntries.map(e => e.bloating), borderColor: '#3b82f6', tension: 0.1 }, { label: 'Pain', data: sortedEntries.map(e => e.pain), borderColor: '#ef4444', tension: 0.1 }, { label: 'Gas', data: sortedEntries.map(e => e.gas), borderColor: '#f97316', tension: 0.1 }, ] }; renderChart('symptomTrendChart', 'line', symptomData, 'Symptom Severity Over Time'); // Stress vs Avg Symptom Chart const stressData = { labels, datasets: [ { label: 'Stress Level', data: sortedEntries.map(e => e.stress), borderColor: '#8b5cf6', tension: 0.1, yAxisID: 'y' }, { label: 'Avg Symptom', data: sortedEntries.map(e => (e.bloating + e.pain + e.gas) / 3), borderColor: '#22c55e', tension: 0.1, yAxisID: 'y' }, ] }; renderChart('stressSymptomChart', 'line', stressData, 'Stress vs. Average Symptoms'); // Stool Type Chart const stoolCounts = bristolData.map(b => ({...b, count: 0})); diaryEntries.forEach(e => { const type = parseInt(e.bristolType); if(type >= 1 && type <= 7) stoolCounts[type - 1].count++; }); const stoolChartData = { labels: stoolCounts.map(s => `Type ${s.type}`), datasets: [{ label: 'Frequency', data: stoolCounts.map(s => s.count), backgroundColor: ['#A52A2A', '#8B4513', '#D2691E', '#CD853F', '#F4A460', '#DEB887', '#FFE4B5'], }] }; renderChart('stoolTypeChart', 'bar', stoolChartData, 'Bristol Stool Type Frequency'); }; const renderChart = (canvasId, type, data, title) => { if (charts[canvasId]) charts[canvasId].destroy(); const ctx = document.getElementById(canvasId).getContext('2d'); charts[canvasId] = new Chart(ctx, { type: type, data: data, options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: title, font: { size: 16 } } }, scales: { x: type === 'line' ? { type: 'time', time: { unit: 'day' } } : {}, y: { beginAtZero: true, max: 10 } } } }); }; const updateAllViews = () => { renderHistory(); renderDashboard(); }; // --- Form & Entry Logic --- const handleFormSubmit = (e) => { e.preventDefault(); const id = document.getElementById('entryId').value; const entry = { id: id || Date.now().toString(), date: document.getElementById('entryDate').value, bloating: parseInt(document.getElementById('bloating').value), pain: parseInt(document.getElementById('pain').value), gas: parseInt(document.getElementById('gas').value), bristolType: document.getElementById('bristolType').value, bmFrequency: parseInt(document.getElementById('bmFrequency').value), stress: parseInt(document.getElementById('stress').value), sleep: parseInt(document.getElementById('sleep').value), meals: { breakfast: document.getElementById('mealBreakfast').value, lunch: document.getElementById('mealLunch').value, dinner: document.getElementById('mealDinner').value, snacks: document.getElementById('mealSnacks').value, }, medications: document.getElementById('medications').value, notes: document.getElementById('notes').value, }; if (!entry.date) { alert('Please select a date.'); return; } if (id) { // Update existing const index = diaryEntries.findIndex(e => e.id === id); diaryEntries[index] = entry; } else { // Add new diaryEntries.push(entry); } saveEntries(); clearForm(); updateAllViews(); updateTabs(3); // Switch to history view }; const clearForm = () => { form.reset(); document.getElementById('entryId').value = ''; document.getElementById('entryDate').valueAsDate = new Date(); bristolSelector.querySelectorAll('.bristol-type').forEach(i => i.classList.remove('selected')); ['bloating', 'pain', 'gas', 'stress', 'sleep'].forEach(id => { document.getElementById(`${id}Value`).textContent = document.getElementById(id).value; }); }; const editEntry = (id) => { const entry = diaryEntries.find(e => e.id === id); if (!entry) return; document.getElementById('entryId').value = entry.id; document.getElementById('entryDate').value = entry.date; ['bloating', 'pain', 'gas', 'stress', 'sleep', 'bristolType', 'bmFrequency', 'medications', 'notes'].forEach(key => { const el = document.getElementById(key); if (el) el.value = entry[key] || ''; }); ['breakfast', 'lunch', 'dinner', 'snacks'].forEach(meal => { document.getElementById(`meal${meal.charAt(0).toUpperCase() + meal.slice(1)}`).value = entry.meals[meal] || ''; }); // Update sliders and their displays ['bloating', 'pain', 'gas', 'stress', 'sleep'].forEach(id => { const slider = document.getElementById(id); const display = document.getElementById(`${id}Value`); if(slider && display) { slider.value = entry[id] || 5; display.textContent = slider.value; } }); // Select bristol type bristolSelector.querySelectorAll('.bristol-type').forEach(i => i.classList.remove('selected')); const bristolEl = bristolSelector.querySelector(`[data-type='${entry.bristolType}']`); if (bristolEl) bristolEl.classList.add('selected'); updateTabs(2); // Switch to form }; const deleteEntry = (id) => { if (confirm('Are you sure you want to delete this entry?')) { diaryEntries = diaryEntries.filter(e => e.id !== id); saveEntries(); updateAllViews(); } }; // --- PDF Generation --- const generatePDF = () => { const { jsPDF } = window.jspdf; const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' }); const startDate = document.getElementById('startDate').value; const endDate = document.getElementById('endDate').value; let filteredEntries = diaryEntries; if (startDate && endDate) { filteredEntries = diaryEntries.filter(e => e.date >= startDate && e.date <= endDate); } if (filteredEntries.length === 0) { alert('No entries found for the selected date range.'); return; } const margin = 15; const pdfWidth = pdf.internal.pageSize.getWidth(); const pageHeight = pdf.internal.pageSize.getHeight(); let currentY = margin; const addHeader = () => { pdf.setFont('helvetica', 'bold'); pdf.setFontSize(22); pdf.text('IBS Symptom Diary Report', pdfWidth / 2, currentY, { align: 'center' }); currentY += 8; pdf.setFont('helvetica', 'normal'); pdf.setFontSize(11); const dateRange = startDate && endDate ? `${startDate} to ${endDate}` : 'All Entries'; pdf.text(`Date Range: ${dateRange}`, pdfWidth / 2, currentY, { align: 'center' }); currentY += 10; pdf.setDrawColor(200, 200, 200); pdf.line(margin, currentY, pdfWidth - margin, currentY); currentY += 10; }; const addFooter = (page) => { pdf.setPage(page); pdf.setFontSize(9); pdf.setFont('helvetica', 'italic'); pdf.text(`Page ${page}`, pdfWidth / 2, pageHeight - 10, { align: 'center' }); pdf.text('This is not medical advice. Consult a professional.', pdfWidth - margin, pageHeight - 10, { align: 'right' }); }; const checkNewPage = (spaceNeeded) => { if (currentY + spaceNeeded > pageHeight - 20) { addFooter(pdf.internal.getNumberOfPages()); pdf.addPage(); currentY = margin; return true; } return false; }; addHeader(); filteredEntries.forEach((entry, index) => { checkNewPage(60); // Estimate space for an entry pdf.setFontSize(14); pdf.setFont('helvetica', 'bold'); pdf.setFillColor(240, 240, 240); pdf.rect(margin, currentY, pdfWidth - (margin*2), 8, 'F'); pdf.text(new Date(entry.date).toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }), margin + 2, currentY + 6); currentY += 12; pdf.setFontSize(11); pdf.setFont('helvetica', 'normal'); let textBlock = `Symptoms: Bloating (${entry.bloating}/10), Pain (${entry.pain}/10), Gas (${entry.gas}/10)\n`; textBlock += `Bowel: Type ${entry.bristolType}, Frequency: ${entry.bmFrequency}\n`; textBlock += `Triggers: Stress (${entry.stress}/10), Sleep (${entry.sleep}/10)\n`; textBlock += `Meals:\n B: ${entry.meals.breakfast || 'N/A'}\n L: ${entry.meals.lunch || 'N/A'}\n D: ${entry.meals.dinner || 'N/A'}\n S: ${entry.meals.snacks || 'N/A'}\n`; textBlock += `Meds: ${entry.medications || 'N/A'}\n`; textBlock += `Notes: ${entry.notes || 'N/A'}`; const lines = pdf.splitTextToSize(textBlock, pdfWidth - (margin * 2) - 5); checkNewPage(lines.length * 5); pdf.text(lines, margin + 2, currentY); currentY += lines.length * 5 + 5; pdf.setDrawColor(220, 220, 220); pdf.line(margin, currentY, pdfWidth - margin, currentY); currentY += 5; }); addFooter(pdf.internal.getNumberOfPages()); pdf.save('IBS-Symptom-Report.pdf'); }; init(); });
Scroll to Top