`;
container.appendChild(msgEl);
});
container.scrollTop = container.scrollHeight;
}
function renderFiles(docs) {
const container = document.getElementById('fileList');
container.innerHTML = '';
docs.forEach(doc => {
const file = doc.data();
const fileEl = document.createElement('div');
fileEl.className = 'flex items-center justify-between p-2 bg-gray-100 rounded-md';
fileEl.innerHTML = `
${file.name}
`;
fileEl.querySelector('button').addEventListener('click', () => deleteFile(doc.id, file.path));
container.appendChild(fileEl);
});
}
// --- DATABASE OPERATIONS ---
async function updateTaskStatus(taskId, completed) {
await updateDoc(dashboardDocRef, { [`tasks.${taskId}.completed`]: completed });
}
async function deleteTask(taskId) {
await updateDoc(dashboardDocRef, { [`tasks.${taskId}`]: deleteField() });
}
document.getElementById('addTaskBtn').addEventListener('click', async () => {
const input = document.getElementById('taskInput');
if (input.value.trim() === '') return;
const taskId = 'task_' + Date.now();
await updateDoc(dashboardDocRef, { [`tasks.${taskId}`]: { text: input.value, completed: false } });
input.value = '';
});
document.getElementById('sendMessageBtn').addEventListener('click', async () => {
const input = document.getElementById('chatInput');
if (input.value.trim() === '') return;
await addDoc(chatCollectionRef, {
text: input.value,
name: userName,
uid: userId,
timestamp: serverTimestamp()
});
input.value = '';
});
async function deleteFile(docId, filePath) {
const fileRef = ref(storage, filePath);
try {
await deleteObject(fileRef);
await deleteDoc(doc(filesCollectionRef, docId));
showMessage("File deleted.");
} catch (error) {
console.error("Error deleting file:", error);
showMessage("Could not delete file.", true);
}
}
// --- FILE UPLOAD ---
const fileInput = document.getElementById('fileInput');
const uploadBtn = document.getElementById('uploadFileBtn');
const progressContainer = document.getElementById('uploadProgress');
const progressBar = document.getElementById('progressBar');
uploadBtn.addEventListener('click', () => {
const file = fileInput.files[0];
if (!file) return;
const filePath = `artifacts/${appId}/public/files/${currentSessionId}/${Date.now()}_${file.name}`;
const storageRef = ref(storage, filePath);
const uploadTask = uploadBytesResumable(storageRef, file);
uploadTask.on('state_changed',
(snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
progressContainer.style.display = 'block';
progressBar.style.width = progress + '%';
},
(error) => {
console.error("Upload failed:", error);
showMessage("File upload failed.", true);
progressContainer.style.display = 'none';
},
() => {
getDownloadURL(uploadTask.snapshot.ref).then(async (downloadURL) => {
await addDoc(filesCollectionRef, {
name: file.name,
url: downloadURL,
path: filePath,
uploaderId: userId,
uploaderName: userName,
uploadedAt: serverTimestamp()
});
showMessage("File uploaded successfully!");
progressContainer.style.display = 'none';
fileInput.value = '';
});
}
);
});
// --- UI & PDF ---
const tabs = document.querySelectorAll('.tab-content');
const tabLinks = document.querySelectorAll('.tab-link');
window.showTab = (tabIndex) => {
tabs.forEach((t, i) => { t.style.display = i === tabIndex ? 'block' : 'none'; });
tabLinks.forEach((l, i) => { l.classList.toggle('active', i === tabIndex); l.classList.toggle('inactive', i !== tabIndex); });
};
document.getElementById('downloadPdfBtn').addEventListener('click', async () => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
const pageHeight = doc.internal.pageSize.height;
const margin = 15;
let y = margin;
// Helper function to add text and manage page breaks
const addWrappedText = (text, options) => {
const lines = doc.splitTextToSize(text, doc.internal.pageSize.width - margin * 2);
for (const line of lines) {
if (y + 10 > pageHeight - margin) {
doc.addPage();
y = margin;
}
doc.text(line, margin, y, options);
y += 7; // Line height
}
};
// Title
doc.setFontSize(22);
doc.setFont("helvetica", "bold");
doc.text("Team Collaboration Dashboard", doc.internal.pageSize.width / 2, y, { align: 'center' });
y += 10;
doc.setFontSize(12);
doc.setFont("helvetica", "normal");
doc.text(`Session ID: ${currentSessionId}`, doc.internal.pageSize.width / 2, y, { align: 'center' });
y += 15;
// --- To-Do List ---
doc.setFontSize(16);
doc.setFont("helvetica", "bold");
doc.text("Shared To-Do List", margin, y);
y += 10;
doc.setFontSize(12);
doc.setFont("helvetica", "normal");
Object.values(dashboardData.tasks || {}).forEach(task => {
const prefix = task.completed ? '[x] ' : '[ ] ';
addWrappedText(prefix + task.text);
});
y += 10;
// --- Team Chat ---
doc.setFontSize(16);
doc.setFont("helvetica", "bold");
doc.text("Team Chat", margin, y);
y += 10;
doc.setFontSize(12);
doc.setFont("helvetica", "normal");
const chatSnapshot = await getDocs(query(chatCollectionRef, orderBy("timestamp")));
chatSnapshot.docs.forEach(docSnap => {
const msg = docSnap.data();
addWrappedText(`${msg.name}: ${msg.text}`);
});
y += 10;
// --- Shared Files ---
doc.setFontSize(16);
doc.setFont("helvetica", "bold");
doc.text("Shared Files", margin, y);
y += 10;
doc.setFontSize(12);
doc.setFont("helvetica", "normal");
const filesSnapshot = await getDocs(query(filesCollectionRef, orderBy("uploadedAt")));
filesSnapshot.docs.forEach(docSnap => {
const file = docSnap.data();
addWrappedText(`- ${file.name} (Uploaded by: ${file.uploaderName})`);
});
doc.save(`dashboard-${currentSessionId}.pdf`);
});
function showMessage(message, isError = false) {
const box = document.getElementById('messageBox');
box.textContent = message;
box.className = `fixed top-5 right-5 text-white py-2 px-4 rounded-lg shadow-lg ${isError ? 'bg-red-500' : 'bg-green-500'}`;
setTimeout(() => { box.className += ' hidden'; }, 3000);
}
Uploaded by ${file.uploaderName}
