`;
entriesList.appendChild(entryEl);
});
}
};
// Function to update reminder status display
const updateReminderStatus = () => {
if (reminderTime) {
reminderTimeInput.value = reminderTime;
reminderStatus.textContent = `Daily reminder is set for ${reminderTime}.`;
reminderStatus.className = 'mt-4 font-medium text-green-600';
} else {
reminderTimeInput.value = '';
reminderStatus.textContent = 'No reminder is set.';
reminderStatus.className = 'mt-4 font-medium text-gray-500';
}
};
// Function to handle tab switching
const switchTab = (tabIndex) => {
tabs.forEach(tab => tab.classList.replace('tab-active', 'tab-inactive'));
tabPanes.forEach(pane => pane.classList.add('hidden'));
const selectedTab = tabs[tabIndex];
const selectedPaneId = selectedTab.getAttribute('data-tab');
const selectedPane = document.getElementById(selectedPaneId);
selectedTab.classList.replace('tab-inactive', 'tab-active');
if (selectedPane) {
selectedPane.classList.remove('hidden');
}
currentTabIndex = tabIndex;
updateNavButtons();
};
// Function to update Previous/Next button states
const updateNavButtons = () => {
prevBtn.disabled = currentTabIndex === 0;
nextBtn.disabled = currentTabIndex === tabs.length - 1;
prevBtn.classList.toggle('opacity-50', prevBtn.disabled);
nextBtn.classList.toggle('opacity-50', nextBtn.disabled);
};
// Initial setup calls
renderEntries();
updateReminderStatus();
updateNavButtons();
if (reminderTime) {
startReminderCheck();
}
// --- EVENT LISTENERS ---
// Tab navigation
tabs.forEach((tab, index) => {
tab.addEventListener('click', () => switchTab(index));
});
// Previous/Next button navigation
prevBtn.addEventListener('click', () => {
if (currentTabIndex > 0) {
switchTab(currentTabIndex - 1);
}
});
nextBtn.addEventListener('click', () => {
if (currentTabIndex < tabs.length - 1) {
switchTab(currentTabIndex + 1);
}
});
// Save new entry
if (saveEntryBtn) {
saveEntryBtn.addEventListener('click', () => {
const text = journalInput.value.trim();
if (text) {
const newEntry = {
id: Date.now(),
date: new Date().toISOString(),
text: text
};
entries.push(newEntry);
localStorage.setItem('gratitudeEntries', JSON.stringify(entries));
journalInput.value = '';
renderEntries();
// Show confirmation message
saveConfirmation.style.display = 'block';
setTimeout(() => {
saveConfirmation.style.display = 'none';
}, 3000);
}
});
}
// Edit and Delete entry buttons (event delegation)
if (entriesList) {
entriesList.addEventListener('click', (e) => {
const target = e.target.closest('button');
if (!target) return;
const entryId = parseInt(target.getAttribute('data-id'));
if (target.classList.contains('delete-btn')) {
// Use a custom confirmation modal in a real app, window.confirm is a placeholder
if (confirm('Are you sure you want to delete this entry?')) {
entries = entries.filter(entry => entry.id !== entryId);
localStorage.setItem('gratitudeEntries', JSON.stringify(entries));
renderEntries();
}
}
if (target.classList.contains('edit-btn')) {
const entryToEdit = entries.find(entry => entry.id === entryId);
if (entryToEdit) {
const newText = prompt('Edit your entry:', entryToEdit.text);
if (newText !== null && newText.trim() !== '') {
entryToEdit.text = newText.trim();
localStorage.setItem('gratitudeEntries', JSON.stringify(entries));
renderEntries();
}
}
}
});
}
// Set Reminder
if (setReminderBtn) {
setReminderBtn.addEventListener('click', () => {
const time = reminderTimeInput.value;
if (time) {
// Request notification permission
if (Notification.permission === 'granted') {
saveAndStartReminder(time);
} else if (Notification.permission !== 'denied') {
Notification.requestPermission().then(permission => {
if (permission === 'granted') {
saveAndStartReminder(time);
} else {
alert('Notification permission was denied. You will not receive reminders.');
}
});
} else {
alert('Notification permission is denied. Please enable it in your browser settings to receive reminders.');
}
}
});
}
// Clear Reminder
if (clearReminderBtn) {
clearReminderBtn.addEventListener('click', () => {
reminderTime = null;
localStorage.removeItem('gratitudeReminderTime');
if (reminderInterval) {
clearInterval(reminderInterval);
}
updateReminderStatus();
});
}
// PDF Download
if (downloadPdfBtn) {
downloadPdfBtn.addEventListener('click', async () => {
// Temporarily create a clone for PDF generation
const contentToPrint = entriesList.cloneNode(true);
contentToPrint.style.maxHeight = 'none'; // Remove scroll limit for PDF
contentToPrint.id = 'pdf-content';
// Hide buttons in the clone
contentToPrint.querySelectorAll('.pdf-hide').forEach(el => el.classList.add('pdf-hide'));
// Append to body to render, but make it invisible
document.body.appendChild(contentToPrint);
contentToPrint.style.position = 'absolute';
contentToPrint.style.left = '-9999px';
contentToPrint.style.width = '800px'; // Set a fixed width for consistent PDF layout
// Add a title to the PDF content
const pdfTitle = document.createElement('h1');
pdfTitle.innerText = 'My Gratitude Journal';
pdfTitle.className = 'text-2xl font-bold text-center mb-6';
contentToPrint.insertBefore(pdfTitle, contentToPrint.firstChild);
const { jsPDF } = window.jspdf;
const canvas = await html2canvas(contentToPrint, { scale: 2 });
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'px',
format: 'a4'
});
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (canvas.height * pdfWidth) / canvas.width;
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
pdf.save('gratitude-journal.pdf');
// Clean up the cloned element
document.body.removeChild(contentToPrint);
});
}
// --- HELPER FUNCTIONS ---
function saveAndStartReminder(time) {
reminderTime = time;
localStorage.setItem('gratitudeReminderTime', time);
updateReminderStatus();
startReminderCheck();
}
function startReminderCheck() {
if (reminderInterval) {
clearInterval(reminderInterval);
}
reminderInterval = setInterval(checkTime, 30000); // Check every 30 seconds
}
function checkTime() {
if (!reminderTime) return;
const now = new Date();
const [hours, minutes] = reminderTime.split(':');
if (now.getHours() == hours && now.getMinutes() == minutes) {
// Check if a notification for today has already been sent
const lastNotification = localStorage.getItem('lastGratitudeNotification');
const today = new Date().toDateString();
if (lastNotification !== today) {
showNotification();
localStorage.setItem('lastGratitudeNotification', today);
}
}
}
function showNotification() {
const notification = new Notification('Time for Gratitude!', {
body: 'Take a moment to write down what you are grateful for today.',
icon: 'https://img.icons8.com/plasticine/100/000000/leaf.png' // A generic, friendly icon
});
notification.onclick = () => {
window.focus();
switchTab(0); // Switch to the journal tab on click
};
}
});