Online Secure Digital Diary with AI Sentiment Analysis

Secure Digital Diary

Your private space to write, reflect, and understand your emotions with AI.

Past Entries

Loading history...

${entry.content.substring(0, 80)}...

${entry.sentiment ? `${entry.sentiment.sentiment}` : ''}
`; }).join(''); }; const loadTodaysEntry = async () => { const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const entryDocRef = doc(db, `/artifacts/${appId}/users/${userId}/diary`, todayKey); const docSnap = await getDoc(entryDocRef); if (docSnap.exists()) { const data = docSnap.data(); DOM.diaryEntry.value = data.content; if (data.sentiment) { renderSentiment(data.sentiment); } } }; // --- MODAL & FIRESTORE --- const openModal = (entry) => { const entryDate = new Date(entry.id + 'T00:00:00'); DOM.modalDate.textContent = entryDate.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); DOM.modalEntryText.value = entry.content; DOM.modalSaveBtn.dataset.id = entry.id; DOM.modalDeleteBtn.dataset.id = entry.id; if (entry.sentiment) { DOM.modalSentiment.innerHTML = `Sentiment: ${entry.sentiment.sentiment} | Emotions: ${entry.sentiment.emotions.join(', ')}`; } else { DOM.modalSentiment.innerHTML = ''; } DOM.entryModal.classList.remove('hidden'); }; const closeModal = () => DOM.entryModal.classList.add('hidden'); const saveEntry = async () => { const content = DOM.diaryEntry.value.trim(); if (!content) return; const sentiment = await analyzeSentiment(content); renderSentiment(sentiment); const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const entryDocRef = doc(db, `/artifacts/${appId}/users/${userId}/diary`, todayKey); await setDoc(entryDocRef, { content, sentiment, updatedAt: serverTimestamp() }, { merge: true }); }; const updateEntry = async (id, content) => { const sentiment = await analyzeSentiment(content); const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const entryDocRef = doc(db, `/artifacts/${appId}/users/${userId}/diary`, id); await updateDoc(entryDocRef, { content, sentiment, updatedAt: serverTimestamp() }); closeModal(); }; const deleteEntry = async (id) => { if (!confirm("Are you sure you want to delete this entry?")) return; const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const entryDocRef = doc(db, `/artifacts/${appId}/users/${userId}/diary`, id); await deleteDoc(entryDocRef); closeModal(); if (id === todayKey) { DOM.diaryForm.reset(); DOM.sentimentAnalysis.classList.add('hidden'); } }; // --- PDF EXPORT --- const downloadPDF = () => { const { jsPDF } = window.jspdf; const doc = new jsPDF(); doc.setFontSize(18); doc.text("My Digital Diary Entries", 14, 22); const sortedEntries = allEntries.sort((a, b) => a.id.localeCompare(b.id)); let yPos = 30; sortedEntries.forEach(entry => { const entryDate = new Date(entry.id + 'T00:00:00'); doc.setFontSize(12); doc.setFont(undefined, 'bold'); doc.text(entryDate.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }), 14, yPos); yPos += 7; if (entry.sentiment) { doc.setFontSize(9); doc.setFont(undefined, 'normal'); doc.setTextColor(100); doc.text(`Sentiment: ${entry.sentiment.sentiment} | Emotions: ${entry.sentiment.emotions.join(', ')}`, 14, yPos); yPos += 7; } doc.setFontSize(11); doc.setTextColor(0); const splitContent = doc.splitTextToSize(entry.content, 180); doc.text(splitContent, 14, yPos); yPos += (splitContent.length * 5) + 10; if (yPos > 270) { doc.addPage(); yPos = 20; } }); doc.save("digital_diary.pdf"); }; // --- INITIALIZATION --- document.addEventListener('DOMContentLoaded', async () => { // Assign DOM elements Object.assign(DOM, { todayDate: document.getElementById('today-date'), diaryForm: document.getElementById('diary-form'), diaryEntry: document.getElementById('diary-entry'), saveBtn: document.getElementById('save-btn'), sentimentAnalysis: document.getElementById('sentiment-analysis'), sentimentResult: document.getElementById('sentiment-result'), emotionsResult: document.getElementById('emotions-result'), analysisLoader: document.getElementById('analysis-loader'), historyList: document.getElementById('history-list'), loadingHistory: document.getElementById('loading-history'), noHistoryMessage: document.getElementById('no-history-message'), downloadPdfBtn: document.getElementById('download-pdf-btn'), entryModal: document.getElementById('entry-modal'), modalDate: document.getElementById('modal-date'), modalEntryText: document.getElementById('modal-entry-text'), modalSentiment: document.getElementById('modal-sentiment'), modalSaveBtn: document.getElementById('modal-save-btn'), modalCancelBtn: document.getElementById('modal-cancel-btn'), modalDeleteBtn: document.getElementById('modal-delete-btn') }); DOM.todayDate.textContent = new Date().toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); // Event Listeners DOM.diaryForm.addEventListener('submit', (e) => { e.preventDefault(); saveEntry(); }); DOM.historyList.addEventListener('click', (e) => { const item = e.target.closest('.history-item'); if (item) { const entry = allEntries.find(en => en.id === item.dataset.id); if (entry) openModal(entry); } }); DOM.modalCancelBtn.addEventListener('click', closeModal); DOM.modalSaveBtn.addEventListener('click', () => updateEntry(DOM.modalSaveBtn.dataset.id, DOM.modalEntryText.value)); DOM.modalDeleteBtn.addEventListener('click', () => deleteEntry(DOM.modalDeleteBtn.dataset.id)); DOM.downloadPdfBtn.addEventListener('click', downloadPDF); // Firebase Initialization try { const firebaseConfig = JSON.parse(typeof __firebase_config !== 'undefined' ? __firebase_config : '{}'); const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; if (!firebaseConfig.apiKey) throw new Error("Firebase config missing."); const app = initializeApp(firebaseConfig); db = getFirestore(app); auth = getAuth(app); onAuthStateChanged(auth, (user) => { if (user) { userId = user.uid; if (entriesUnsubscribe) entriesUnsubscribe(); loadTodaysEntry(); const entriesCollection = collection(db, `/artifacts/${appId}/users/${userId}/diary`); entriesUnsubscribe = onSnapshot(entriesCollection, (snapshot) => { allEntries = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); renderHistory(); }); } }); if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) await signInWithCustomToken(auth, __initial_auth_token); else await signInAnonymously(auth); } catch (error) { console.error("Init Error:", error); document.getElementById('tab-content-today').innerHTML = `

Could not connect. ${error.message}

`; } lucide.createIcons(); });
Scroll to Top