`).join('');
};
const closeModal = (modalElement) => {
modalElement.querySelector('.modal-content').classList.add('scale-95');
setTimeout(() => modalElement.classList.add('hidden'), 300);
};
const addTask = (title, description) => {
const lowerCaseText = (title + ' ' + description).toLowerCase();
const tags = [];
for (const tag in TAG_KEYWORDS) {
if (TAG_KEYWORDS[tag].some(keyword => lowerCaseText.includes(keyword))) {
tags.push(tag);
state.allTags.add(tag);
}
}
state.tasks.push({
id: Date.now(),
title,
description,
status: 'Open',
tags,
comments: []
});
renderBoard();
renderTagsFilter();
};
const addComment = () => {
const input = getElement('comment-input');
if (!input.value.trim()) return;
const task = state.tasks.find(t => t.id === state.activeTaskId);
if (task) {
task.comments.push({
text: input.value.trim(),
timestamp: Date.now()
});
input.value = '';
renderComments();
renderBoard(); // To update comment count
}
};
const generatePDF = () => {
const { jsPDF } = jspdf;
const doc = new jsPDF();
doc.setFontSize(18);
doc.text('Task Board Summary', 14, 22);
let lastY = 30;
['Open', 'In Progress', 'Completed'].forEach(status => {
const tasksInStatus = state.tasks.filter(t => t.status === status);
if (tasksInStatus.length > 0) {
doc.setFontSize(14);
doc.text(status, 14, lastY + 10);
const tableBody = tasksInStatus.map(t => [t.title, t.tags.join(', ') || 'N/A']);
doc.autoTable({
startY: lastY + 12,
head: [['Title', 'Tags']],
body: tableBody,
theme: 'grid'
});
lastY = doc.autoTable.previous.finalY;
}
});
doc.save('Task-Board-Summary.pdf');
};
// --- Event Listeners ---
getElement('open-add-task-btn').addEventListener('click', () => {
addTaskModal.classList.remove('hidden');
setTimeout(() => addTaskModal.querySelector('.modal-content').classList.remove('scale-95'), 10);
});
getElement('close-add-modal-btn').addEventListener('click', () => closeModal(addTaskModal));
getElement('save-task-btn').addEventListener('click', () => {
const title = getElement('new-task-title').value;
const desc = getElement('new-task-description').value;
if (title.trim()) {
addTask(title, desc);
getElement('new-task-title').value = '';
getElement('new-task-description').value = '';
closeModal(addTaskModal);
} else {
alert('Task title is required.');
}
});
taskBoard.addEventListener('click', (e) => {
const card = e.target.closest('.task-card');
if (card) {
openTaskModal(parseInt(card.dataset.id));
}
});
getElement('close-modal-btn').addEventListener('click', () => closeModal(taskModal));
getElement('modal-task-status').addEventListener('change', (e) => {
const task = state.tasks.find(t => t.id === state.activeTaskId);
if (task) {
task.status = e.target.value;
renderBoard();
}
});
getElement('add-comment-btn').addEventListener('click', addComment);
getElement('comment-input').addEventListener('keypress', (e) => {
if (e.key === 'Enter') addComment();
});
getElement('filter-status').addEventListener('change', renderBoard);
getElement('filter-tag').addEventListener('change', renderBoard);
getElement('downloadPdfBtn').addEventListener('click', generatePDF);
// --- Initial Setup ---
const setupInitialData = () => {
addTask('Fix login button bug', 'The login button is not working on the main page. This is a critical issue.');
addTask('Develop new user profile feature', 'Request from marketing to add a new user profile section with avatars.');
addTask('Clarify API documentation', 'Question about the endpoint for user data. Need help from the backend team.');
state.tasks[2].status = 'In Progress';
state.tasks[2].comments.push({text: 'Contacted backend team, waiting for a response.', timestamp: Date.now() - 86400000});
const completedTask = { id: Date.now()+1, title: 'Update homepage banner', description: 'The seasonal banner was updated.', status: 'Completed', tags: [], comments: [] };
state.tasks.push(completedTask);
renderBoard();
renderTagsFilter();
};
setupInitialData();
});
