Automated Office Workflow Optimization Tool

Automated Office Workflow Optimization Tool

Workflow Analytics

Total Tasks

0

In Progress

0

Completed

0

Avg. Completion Time

N/A

Task Status Distribution

Tasks per Assignee

${task.name}

${task.assignee}

${task.priority} Due: ${task.dueDate}
`; } function renderTaskList() { taskListContainer.innerHTML = tasks.map(task => `

${task.name} (${task.status})

Assigned to: ${task.assignee}

`).join(''); } function renderAnalytics() { // KPIs document.getElementById('total-tasks').textContent = tasks.length; document.getElementById('tasks-in-progress').textContent = tasks.filter(t => t.status === 'In Progress').length; const completedTasks = tasks.filter(t => t.status === 'Done'); document.getElementById('tasks-completed').textContent = completedTasks.length; // Avg Completion Time const completableTasks = completedTasks.filter(t => t.createdAt && t.completedAt); if (completableTasks.length > 0) { const totalTime = completableTasks.reduce((sum, task) => { const start = new Date(task.createdAt); const end = new Date(task.completedAt); return sum + (end - start); }, 0); const avgTime = totalTime / completableTasks.length / (1000 * 60 * 60 * 24); // in days document.getElementById('avg-completion-time').textContent = `${avgTime.toFixed(1)} days`; } else { document.getElementById('avg-completion-time').textContent = 'N/A'; } // Charts const statusCounts = statuses.map(s => tasks.filter(t => t.status === s).length); const assignees = [...new Set(tasks.map(t => t.assignee))]; const assigneeCounts = assignees.map(a => tasks.filter(t => t.assignee === a).length); if (statusChart) statusChart.destroy(); statusChart = new Chart(document.getElementById('status-chart'), { type: 'doughnut', data: { labels: statuses, datasets: [{ data: statusCounts, backgroundColor: ['#FBBF24', '#3B82F6', '#10B981'] }] }, options: { responsive: true } }); if (assigneeChart) assigneeChart.destroy(); assigneeChart = new Chart(document.getElementById('assignee-chart'), { type: 'bar', data: { labels: assignees, datasets: [{ label: 'Tasks Assigned', data: assigneeCounts, backgroundColor: '#6366F1' }] }, options: { responsive: true, scales: { y: { beginAtZero: true } } } }); } // --- DRAG & DROP --- function addDragAndDropListeners() { const taskCards = document.querySelectorAll('.task-card'); const columns = document.querySelectorAll('.kanban-column'); let draggedItem = null; taskCards.forEach(card => { card.addEventListener('dragstart', () => { draggedItem = card; setTimeout(() => card.classList.add('dragging'), 0); }); card.addEventListener('dragend', () => { draggedItem.classList.remove('dragging'); draggedItem = null; }); }); columns.forEach(column => { column.addEventListener('dragover', e => { e.preventDefault(); column.classList.add('drag-over'); }); column.addEventListener('dragleave', () => column.classList.remove('drag-over')); column.addEventListener('drop', () => { column.classList.remove('drag-over'); if (draggedItem) { const taskId = parseInt(draggedItem.dataset.taskId); const newStatus = column.dataset.status; const task = tasks.find(t => t.id === taskId); if (task) { task.status = newStatus; if (newStatus === 'Done' && !task.completedAt) { task.completedAt = new Date().toISOString(); } updateAll(); } } }); }); } // --- EVENT HANDLERS --- taskForm.addEventListener('submit', (e) => { e.preventDefault(); const id = parseInt(editTaskIdInput.value); const taskData = { name: taskNameInput.value, assignee: taskAssigneeInput.value, priority: taskPriorityInput.value, dueDate: taskDueDateInput.value, }; if (id) { // Update const index = tasks.findIndex(t => t.id === id); if (index !== -1) tasks[index] = { ...tasks[index], ...taskData }; } else { // Add taskData.id = Date.now(); taskData.status = 'To Do'; taskData.createdAt = new Date().toISOString(); tasks.push(taskData); } resetTaskForm(); updateAll(); showModal('Success', `Task has been ${id ? 'updated' : 'added'} successfully.`); }); downloadPdfBtn.addEventListener('click', () => { const { jsPDF } = window.jspdf; const doc = new jsPDF(); doc.setFontSize(18); doc.text('Workflow Analytics Report', 14, 22); doc.setFontSize(11); doc.text(`Generated on: ${new Date().toLocaleDateString()}`, 14, 30); const kpis = [ ['Total Tasks', document.getElementById('total-tasks').textContent], ['Tasks In Progress', document.getElementById('tasks-in-progress').textContent], ['Tasks Completed', document.getElementById('tasks-completed').textContent], ['Avg. Completion Time', document.getElementById('avg-completion-time').textContent] ]; doc.autoTable({ head: [['Metric', 'Value']], body: kpis, startY: 40 }); doc.addPage(); doc.text('Task Details', 14, 22); const head = [['ID', 'Task Name', 'Assignee', 'Priority', 'Due Date', 'Status']]; const body = tasks.map(t => [t.id, t.name, t.assignee, t.priority, t.dueDate, t.status]); doc.autoTable({ head, body, startY: 30 }); doc.save('workflow_report.pdf'); }); // --- HELPERS --- function resetTaskForm() { taskForm.reset(); editTaskIdInput.value = ''; taskFormTitle.textContent = 'Add New Task'; taskSubmitBtn.textContent = 'Add Task'; taskCancelEditBtn.classList.add('hidden'); } function showModal(title, message) { modalTitle.textContent = title; modalMessage.textContent = message; modal.classList.add('visible'); } modalCloseBtn.addEventListener('click', () => modal.classList.remove('visible')); // --- GLOBAL API --- window.app = { editTask: (id) => { const task = tasks.find(t => t.id === id); if (task) { setActiveTab('config'); editTaskIdInput.value = task.id; taskNameInput.value = task.name; taskAssigneeInput.value = task.assignee; taskPriorityInput.value = task.priority; taskDueDateInput.value = task.dueDate; taskFormTitle.textContent = 'Edit Task'; taskSubmitBtn.textContent = 'Update Task'; taskCancelEditBtn.classList.remove('hidden'); } }, deleteTask: (id) => { tasks = tasks.filter(t => t.id !== id); updateAll(); } }; // --- TAB NAVIGATION --- function setActiveTab(tabId) { currentTab = tabId; tabButtons.forEach(btn => btn.classList.toggle('active', btn.dataset.tab === tabId)); tabPanes.forEach(pane => pane.style.display = pane.id === tabId ? 'block' : 'none'); const currentIndex = tabs.indexOf(currentTab); prevTabBtn.disabled = currentIndex === 0; nextTabBtn.disabled = currentIndex === tabs.length - 1; } tabButtons.forEach(button => button.addEventListener('click', () => setActiveTab(button.dataset.tab))); prevTabBtn.addEventListener('click', () => { const newIndex = tabs.indexOf(currentTab) - 1; if (newIndex >= 0) setActiveTab(tabs[newIndex]); }); nextTabBtn.addEventListener('click', () => { const newIndex = tabs.indexOf(currentTab) + 1; if (newIndex < tabs.length) setActiveTab(tabs[newIndex]); }); taskCancelEditBtn.addEventListener('click', resetTaskForm); // --- START --- initialize(); });
Scroll to Top