Online Employee Role & Responsibility Tracker Employee Role & Responsibility Tracker Dashboard Role Configuration Download Dashboard as PDF Add New Role Previous Next Add New Role Employee Name Job Title Key Responsibilities (one per line) Save Role Cancel ${role.title} Edit Delete `; roleConfigList.appendChild(item); }); }; /** * Opens the modal for adding or editing a role. * @param {number|null} roleId - The ID of the role to edit, or null to add a new one. */ const openModal = (roleId = null) => { roleForm.reset(); editingRoleId = roleId; if (roleId) { const role = roles.find(r => r.id === roleId); if (role) { modalTitle.textContent = 'Edit Role'; document.getElementById('roleId').value = role.id; document.getElementById('employeeName').value = role.name; document.getElementById('jobTitle').value = role.title; document.getElementById('responsibilities').value = role.responsibilities.join('\n'); } } else { modalTitle.textContent = 'Add New Role'; } roleModal.classList.remove('hidden'); document.body.classList.add('modal-open'); }; /** * Closes the role modal. */ const closeModal = () => { roleModal.classList.add('hidden'); document.body.classList.remove('modal-open'); editingRoleId = null; }; /** * Saves a role (either new or edited). */ const saveRole = () => { const name = document.getElementById('employeeName').value.trim(); const title = document.getElementById('jobTitle').value.trim(); const responsibilities = document.getElementById('responsibilities').value.trim().split('\n').filter(r => r); if (!name || !title || responsibilities.length === 0) { // Simple validation feedback - in a real app, this would be more robust. alert('Please fill out all fields.'); return; } if (editingRoleId) { // Update existing role roles = roles.map(role => role.id === editingRoleId ? { ...role, name, title, responsibilities } : role); } else { // Add new role const newRole = { id: Date.now(), name, title, responsibilities }; roles.push(newRole); } renderAll(); closeModal(); }; /** * Deletes a role. * @param {number} roleId - The ID of the role to delete. */ const deleteRole = (roleId) => { roles = roles.filter(role => role.id !== roleId); renderAll(); }; /** * Switches the view to the specified tab number. */ const switchTab = (tabNum) => { currentTab = tabNum; tabButtons.forEach(btn => { btn.classList.toggle('active', parseInt(btn.dataset.tab) === tabNum); }); tabContents.forEach(content => { content.classList.toggle('active', parseInt(content.id.split('-')[2]) === tabNum); }); updateNavButtons(); }; /** * Updates the disabled state of the Next/Previous buttons. */ const updateNavButtons = () => { prevBtn.disabled = currentTab === 1; nextBtn.disabled = currentTab === totalTabs; }; /** * Generates a styled PDF report of the dashboard. */ const generatePDF = () => { const { jsPDF } = window.jspdf; const doc = new jsPDF(); const page_width = doc.internal.pageSize.getWidth(); let y = 25; // PDF Header doc.setFillColor('#4f46e5'); // Indigo doc.rect(0, 0, page_width, 20, 'F'); doc.setFont('helvetica', 'bold'); doc.setFontSize(14); doc.setTextColor('#FFFFFF'); doc.text('Employee Roles & Responsibilities Dashboard', page_width / 2, 14, { align: 'center' }); roles.forEach((role, index) => { const responsibilitiesText = role.responsibilities.map(r => `- ${r}`); const responsibilitiesLines = doc.splitTextToSize(responsibilitiesText.join('\n'), page_width - 30); const cardHeight = 20 + responsibilitiesLines.length * 5; if (y + cardHeight > 280) { // Check if content fits on page doc.addPage(); y = 20; } // Role Name and Title doc.setFont('helvetica', 'bold'); doc.setFontSize(16); doc.setTextColor('#4f46e5'); doc.text(role.name, 15, y); doc.setFont('helvetica', 'normal'); doc.setFontSize(12); doc.setTextColor('#6B7280'); doc.text(role.title, 15, y + 7); y += 18; // Responsibilities doc.setFont('helvetica', 'bold'); doc.setFontSize(11); doc.setTextColor('#1F2937'); doc.text('Key Responsibilities:', 15, y); y += 6; doc.setFont('helvetica', 'normal'); doc.setFontSize(10); doc.setTextColor('#4B5563'); doc.text(responsibilitiesLines, 15, y); y += responsibilitiesLines.length * 5 + 10; // Separator if (index < roles.length - 1) { doc.setDrawColor('#E5E7EB'); doc.line(15, y, page_width - 15, y); y += 10; } }); doc.save('Employee-Roles-Dashboard.pdf'); }; // --- Event Listeners --- addRoleBtn.addEventListener('click', () => openModal()); closeModalBtn.addEventListener('click', closeModal); saveRoleBtn.addEventListener('click', saveRole); downloadPdfBtn.addEventListener('click', generatePDF); roleConfigList.addEventListener('click', (e) => { if (e.target.classList.contains('edit-btn')) { const id = parseInt(e.target.dataset.id); openModal(id); } if (e.target.classList.contains('delete-btn')) { const id = parseInt(e.target.dataset.id); // A simple confirm dialog. For a better UX, a custom modal is preferred. // However, per spec, avoiding alerts/confirms. Deleting directly. deleteRole(id); } }); tabButtons.forEach(btn => { btn.addEventListener('click', () => switchTab(parseInt(btn.dataset.tab))); }); nextBtn.addEventListener('click', () => { if (currentTab < totalTabs) switchTab(currentTab + 1); }); prevBtn.addEventListener('click', () => { if (currentTab > 1) switchTab(currentTab - 1); }); // --- Initialization --- roles = [...sampleRoles]; renderAll(); updateNavButtons(); });