${w.tasks.map(t => `- ${t.name} (${t.duration} days)
`).join('')}
`;
});
};
const renderWorkflowDropdown = () => {
const select = getEl('workflowTemplate');
select.innerHTML = '
';
workflows.forEach(w => {
select.innerHTML += `
`;
});
};
const renderTaskAssignments = () => {
const workflowId = getEl('workflowTemplate').value;
const container = getEl('task-list-for-assignment');
container.innerHTML = '';
if (!workflowId) return;
const workflow = workflows.find(w => w.id == workflowId);
workflow.tasks.forEach(task => {
container.innerHTML += `
`;
});
};
// --- CORE LOGIC & EVENT HANDLERS ---
window.showTab = (tabName) => {
currentTab = tabName;
Object.values(tabs).forEach(tab => tab.style.display = 'none');
Object.values(tabButtons).forEach(btn => btn.classList.replace('active', 'inactive'));
if (tabs[tabName]) tabs[tabName].style.display = 'block';
if (tabButtons[tabName]) tabButtons[tabName].classList.replace('inactive', 'active');
updateNavButtons();
};
const updateNavButtons = () => {
const currentIndex = tabOrder.indexOf(currentTab);
navButtons.prev.style.visibility = currentIndex === 0 ? 'hidden' : 'visible';
navButtons.next.style.visibility = currentIndex === tabOrder.length - 1 ? 'hidden' : 'visible';
};
const handleNavClick = (direction) => {
const currentIndex = tabOrder.indexOf(currentTab);
const newIndex = currentIndex + direction;
if (newIndex >= 0 && newIndex < tabOrder.length) showTab(tabOrder[newIndex]);
};
getEl('workflowTemplate').addEventListener('change', renderTaskAssignments);
getEl('add-task-btn').addEventListener('click', () => {
const container = getEl('workflow-tasks-container');
const taskCount = container.querySelectorAll('.task-item').length;
const taskHtml = `
`;
container.insertAdjacentHTML('beforeend', taskHtml);
});
getEl('add-workflow-form').addEventListener('submit', e => {
e.preventDefault();
const newWorkflow = {
id: Date.now(),
name: getEl('workflowName').value,
tasks: []
};
const taskItems = document.querySelectorAll('#workflow-tasks-container .task-item');
taskItems.forEach(item => {
const name = item.querySelector('.task-name-input').value;
const duration = parseInt(item.querySelector('.task-duration-input').value);
if(name && duration > 0) newWorkflow.tasks.push({ name, duration });
});
workflows.push(newWorkflow);
e.target.reset();
getEl('workflow-tasks-container').innerHTML = '
';
renderAll();
});
getEl('new-request-form').addEventListener('submit', e => {
e.preventDefault();
const workflowId = parseInt(getEl('workflowTemplate').value);
const workflow = workflows.find(w => w.id === workflowId);
let currentDate = new Date();
const newRequest = {
id: Date.now(),
matterName: getEl('matterName').value,
workflowId: workflowId,
startDate: currentDate.toISOString().split('T')[0],
tasks: []
};
const assigneeSelects = document.querySelectorAll('.assignee-select');
workflow.tasks.forEach((taskTpl, index) => {
currentDate.setDate(currentDate.getDate() + taskTpl.duration);
newRequest.tasks.push({
name: taskTpl.name,
status: 'Pending',
assignee: assigneeSelects[index].value,
dueDate: currentDate.toISOString().split('T')[0]
});
});
newRequest.tasks[0].status = 'In Progress';
requests.push(newRequest);
e.target.reset();
showTab('dashboard');
renderAll();
});
window.deleteWorkflow = (id) => {
if (confirm('Are you sure you want to delete this template? This cannot be undone.')) {
workflows = workflows.filter(w => w.id !== id);
renderAll();
}
};
window.updateTaskStatus = (requestId, taskName, newStatus) => {
const request = requests.find(r => r.id === requestId);
if (!request) return;
const task = request.tasks.find(t => t.name === taskName);
if (task) {
task.status = newStatus;
// if completed, set next task to 'In Progress'
if(newStatus === 'Completed') {
const taskIndex = request.tasks.findIndex(t => t.name === taskName);
if(taskIndex < request.tasks.length - 1) {
request.tasks[taskIndex + 1].status = 'In Progress';
}
}
}
renderAll();
};
const downloadPDF = () => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
const today = new Date().toLocaleDateString();
doc.setFontSize(18);
doc.text("Legal Workflow Dashboard Report", 105, 22, { align: 'center' });
doc.setFontSize(11);
doc.setTextColor(100);
doc.text(`Report Generated: ${today}`, 14, 30);
const tableData = requests.map(req => {
const workflow = workflows.find(w => w.id === req.workflowId);
const completedCount = req.tasks.filter(t => t.status === 'Completed').length;
const progress = `${Math.round((completedCount / req.tasks.length) * 100)}%`;
const currentTask = req.tasks.find(t => t.status === 'In Progress') || req.tasks.find(t => t.status === 'Pending') || {name: 'Completed', dueDate: 'N/A', assignee: 'N/A'};
return [
req.matterName,
workflow.name,
progress,
currentTask.name,
currentTask.assignee,
currentTask.dueDate
];
});
doc.autoTable({
startY: 40,
head: [['Matter', 'Workflow', 'Progress', 'Current Task', 'Assignee', 'Due Date']],
body: tableData,
theme: 'striped',
headStyles: { fillColor: [41, 128, 185] },
});
doc.save(`Workflow_Report_${today.replace(/\//g, '-')}.pdf`);
};
// --- INITIALIZATION & BINDINGS ---
navButtons.prev.addEventListener('click', () => handleNavClick(-1));
navButtons.next.addEventListener('click', () => handleNavClick(1));
getEl('download-pdf-btn').addEventListener('click', downloadPDF);
Object.keys(tabButtons).forEach(name => tabButtons[name].addEventListener('click', () => showTab(name)));
renderAll();
updateNavButtons();
});