${dueDateText}
Priority: ${priorityMap[task.priority]}
`;
elements.taskList.appendChild(card);
});
}
async function handleFormSubmit(e) {
e.preventDefault();
const id = elements.taskIdInput.value;
const taskData = {
text: elements.taskTextInput.value,
subject: elements.taskSubjectInput.value,
dueDate: elements.taskDueDateInput.value,
priority: elements.taskPriorityInput.value,
completed: false,
};
try {
const tasksCol = collection(db, 'artifacts', appId, 'users', userId, 'tasks');
if (id) {
// Update existing task
const taskRef = doc(tasksCol, id);
await setDoc(taskRef, taskData, { merge: true });
} else {
// Add new task
taskData.createdAt = serverTimestamp();
await addDoc(tasksCol, taskData);
}
closeModal();
} catch (error) {
console.error("Error saving task: ", error);
showError("Failed to save task.");
}
}
async function handleTaskAction(e) {
const target = e.target.closest('button');
if (!target) return;
const id = target.dataset.id;
const tasksCol = collection(db, 'artifacts', appId, 'users', userId, 'tasks');
const taskRef = doc(tasksCol, id);
if (target.classList.contains('toggle-complete-btn')) {
const isCompleted = target.dataset.completed === 'true';
await setDoc(taskRef, { completed: !isCompleted }, { merge: true });
} else if (target.classList.contains('edit-task-btn')) {
const taskToEdit = allTasks.find(t => t.id === id);
if (taskToEdit) openModal(taskToEdit);
}
}
async function handleDelete() {
const id = elements.taskIdInput.value;
if (id && confirm("Are you sure you want to delete this task?")) {
try {
const tasksCol = collection(db, 'artifacts', appId, 'users', userId, 'tasks');
await deleteDoc(doc(tasksCol, id));
closeModal();
} catch (error) {
console.error("Error deleting task: ", error);
showError("Failed to delete task.");
}
}
}
function downloadPdf() {
if (allTasks.length === 0) {
showError("Your to-do list is empty.");
return;
}
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
doc.setFont('helvetica', 'bold');
doc.setFontSize(18);
doc.text('My Smart To-Do List', doc.internal.pageSize.getWidth() / 2, 20, { align: 'center' });
const priorityMap = { '1': 'Low', '2': 'Medium', '3': 'High' };
const sortedTasks = [...allTasks].sort((a, b) => calculatePriorityScore(b) - calculatePriorityScore(a));
const tableBody = sortedTasks.map(task => [
task.completed ? 'Yes' : 'No',
task.text,
task.subject || '',
new Date(task.dueDate).toLocaleString(),
priorityMap[task.priority]
]);
doc.autoTable({
startY: 30,
head: [['Done', 'Task', 'Subject', 'Due Date', 'Priority']],
body: tableBody,
theme: 'grid',
headStyles: { fillColor: [79, 70, 229] }
});
doc.save('smart-todo-list.pdf');
}
// --- Firebase Initialization and Auth ---
async function initializeFirebase() {
try {
const app = initializeApp(firebaseConfig);
db = getFirestore(app);
auth = getAuth(app);
onAuthStateChanged(auth, (user) => {
if (user) {
userId = user.uid;
if (tasksUnsubscribe) tasksUnsubscribe(); // Unsubscribe from old listener if exists
const tasksCol = collection(db, 'artifacts', appId, 'users', userId, 'tasks');
const q = query(tasksCol);
tasksUnsubscribe = onSnapshot(q, (snapshot) => {
const tasks = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
renderTasks(tasks);
}, (error) => {
console.error("Error fetching tasks:", error);
showError("Could not load tasks.");
});
} else {
userId = null;
if (tasksUnsubscribe) tasksUnsubscribe();
renderTasks([]); // Clear tasks if user logs out
}
});
if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) {
await signInWithCustomToken(auth, __initial_auth_token);
} else {
await signInAnonymously(auth);
}
} catch (error) {
console.error("Firebase initialization failed:", error);
showError("Could not connect to the service.");
}
}
// --- Event Listeners ---
elements.btnAddOpen.addEventListener('click', () => openModal());
elements.btnCloseModal.addEventListener('click', closeModal);
elements.modalOverlay.addEventListener('click', (e) => {
if (e.target === elements.modalOverlay) closeModal();
});
elements.taskForm.addEventListener('submit', handleFormSubmit);
elements.taskList.addEventListener('click', handleTaskAction);
elements.btnDeleteTask.addEventListener('click', handleDelete);
elements.btnDownloadPdf.addEventListener('click', downloadPdf);
// --- Start the app ---
initializeFirebase();