Attorney Workload & Case Allocation Manager

Attorney Workload & Case Allocation Manager

A dashboard to visualize workloads and manage case assignments.

Attorney Roster & Workload

Unassigned Cases

${c.name}

${c.type} - Value: ${formatCurrency(c.value)}

Complexity: ${c.complexity} `).join(''); if (assignedCases.length === 0) { casesHtml = '

No cases assigned.

'; } const attorneyCard = `

${attorney.name}

${attorney.specialty}

Workload: ${currentLoad} / ${attorney.capacity}

Assigned Cases:

    ${casesHtml}
`; container.innerHTML += attorneyCard; }); }; /** * Renders the list of unassigned cases on the dashboard. */ const renderDashboardUnassignedCases = () => { const container = document.getElementById('unassigned-cases-container'); if (!container) return; // Null check const unassignedCases = cases.filter(c => c.attorneyId === null); container.innerHTML = ''; if (unassignedCases.length === 0) { container.innerHTML = '
No unassigned cases.
'; return; } unassignedCases.forEach(c => { const attorneyOptions = attorneys.map(a => ``).join(''); const caseCard = `

${c.name}

${c.type}

Complexity: ${c.complexity} Value: ${formatCurrency(c.value)}
`; container.innerHTML += caseCard; }); }; /** * Renders the editable table of attorneys in the configuration tab. */ const renderConfigAttorneys = () => { const container = document.getElementById('attorney-list-container'); if (!container) return; // Null check let tableHtml = `
`; if (attorneys.length === 0) { tableHtml += ``; } else { attorneys.forEach(a => { tableHtml += ` `; }); } tableHtml += `
Name Specialty Capacity Actions
No attorneys added.
${a.name} ${a.specialty} ${a.capacity}
`; container.innerHTML = tableHtml; }; /** * Renders the editable table of unassigned cases in the configuration tab. */ const renderConfigCases = () => { const container = document.getElementById('case-list-container'); if (!container) return; // Null check const unassignedCases = cases.filter(c => c.attorneyId === null); let tableHtml = `
`; if (unassignedCases.length === 0) { tableHtml += ``; } else { unassignedCases.forEach(c => { tableHtml += ` `; }); } tableHtml += `
Case Name Type Complexity Actions
No unassigned cases.
${c.name} ${c.type} ${c.complexity}
`; container.innerHTML = tableHtml; }; /** * Master render function to update the entire UI. */ const renderAll = () => { renderDashboardAttorneys(); renderDashboardUnassignedCases(); renderConfigAttorneys(); renderConfigCases(); }; // --- EVENT HANDLERS & FORM LOGIC --- function handleAttorneySave(e) { e.preventDefault(); const id = document.getElementById('attorney-id').value; const name = document.getElementById('attorney-name').value; const specialty = document.getElementById('attorney-specialty').value; const capacity = parseInt(document.getElementById('attorney-capacity').value); if (id) { // Update existing const index = attorneys.findIndex(a => a.id == id); if (index !== -1) { attorneys[index] = { ...attorneys[index], name, specialty, capacity }; } } else { // Add new attorneys.push({ id: getNextId(attorneys), name, specialty, capacity }); } clearAttorneyForm(); renderAll(); } window.clearAttorneyForm = () => { attorneyForm.reset(); document.getElementById('attorney-id').value = ''; }; window.editAttorney = (id) => { const attorney = attorneys.find(a => a.id === id); if (attorney) { document.getElementById('attorney-id').value = attorney.id; document.getElementById('attorney-name').value = attorney.name; document.getElementById('attorney-specialty').value = attorney.specialty; document.getElementById('attorney-capacity').value = attorney.capacity; document.getElementById('attorney-name').focus(); } }; window.deleteAttorney = (id) => { if (cases.some(c => c.attorneyId === id)) { // Simple validation; a more robust app would use a custom modal console.warn("Cannot delete attorney with assigned cases. Please reassign cases first."); // In a real app, you would show a user-friendly message here instead of an alert. // For now, we will prevent deletion and log to console. return; } attorneys = attorneys.filter(a => a.id !== id); renderAll(); }; function handleCaseSave(e) { e.preventDefault(); const id = document.getElementById('case-id').value; const name = document.getElementById('case-name').value; const type = document.getElementById('case-type').value; const complexity = parseInt(document.getElementById('case-complexity').value); const value = parseFloat(document.getElementById('case-value').value); if (id) { // Update const index = cases.findIndex(c => c.id == id); if (index !== -1) { cases[index] = { ...cases[index], name, type, complexity, value }; } } else { // Add new cases.push({ id: getNextId(cases), name, type, complexity, value, attorneyId: null }); } clearCaseForm(); renderAll(); } window.clearCaseForm = () => { caseForm.reset(); document.getElementById('case-id').value = ''; }; window.editCase = (id) => { const caseItem = cases.find(c => c.id === id); if (caseItem) { document.getElementById('case-id').value = caseItem.id; document.getElementById('case-name').value = caseItem.name; document.getElementById('case-type').value = caseItem.type; document.getElementById('case-complexity').value = caseItem.complexity; document.getElementById('case-value').value = caseItem.value; document.getElementById('case-name').focus(); } }; window.deleteCase = (id) => { cases = cases.filter(c => c.id !== id); renderAll(); }; window.assignCase = (caseId) => { const selectElement = document.getElementById(`assign-attorney-${caseId}`); if (!selectElement) return; const attorneyId = parseInt(selectElement.value); if (isNaN(attorneyId) || attorneyId === "") return; const caseIndex = cases.findIndex(c => c.id === caseId); if (caseIndex !== -1) { cases[caseIndex].attorneyId = attorneyId; renderAll(); } }; // --- TAB NAVIGATION --- window.changeTab = (tabIndex) => { currentTab = tabIndex; const tabs = document.querySelectorAll('.tab'); const tabContents = document.querySelectorAll('.tab-content'); tabs.forEach((tab, index) => { if (index === tabIndex) { tab.classList.remove('tab-inactive'); tab.classList.add('tab-active'); } else { tab.classList.remove('tab-active'); tab.classList.add('tab-inactive'); } }); tabContents.forEach((content, index) => { content.style.display = index === tabIndex ? 'block' : 'none'; }); }; window.navigateTab = (direction) => { const numTabs = document.querySelectorAll('.tab').length; let newTab = currentTab + direction; if (newTab < 0) newTab = numTabs - 1; if (newTab >= numTabs) newTab = 0; changeTab(newTab); }; // --- PDF DOWNLOAD FUNCTIONALITY --- window.downloadPDF = () => { const { jsPDF } = window.jspdf; const doc = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); doc.setFontSize(18); doc.text('Attorney Workload & Case Allocation Summary', 14, 22); doc.setFontSize(11); doc.setTextColor(100); doc.text(`Generated on: ${new Date().toLocaleDateString('en-US')}`, 14, 30); const head = [['Attorney', 'Specialty', 'Assigned Cases', 'Workload (Points)', 'Capacity']]; const body = attorneys.map(attorney => { const assignedCases = cases.filter(c => c.attorneyId === attorney.id); const currentLoad = assignedCases.reduce((sum, c) => sum + c.complexity, 0); const caseList = assignedCases.map(c => `- ${c.name} (C: ${c.complexity})`).join('\n') || 'None'; return [ attorney.name, attorney.specialty, caseList, `${currentLoad}`, `${attorney.capacity}` ]; }); doc.autoTable({ startY: 40, head: head, body: body, theme: 'striped', headStyles: { fillColor: [22, 160, 133] }, styles: { cellPadding: 2, fontSize: 9 }, didDrawCell: (data) => { // For multiline text in 'Assigned Cases' column if (data.column.index === 2 && data.cell.section === 'body') { doc.autoTableText(data.cell.text, data.cell.x + 2, data.cell.y + 2, { halign: 'left', valign: 'top' }); } } }); const unassignedCases = cases.filter(c => c.attorneyId === null); if (unassignedCases.length > 0) { const unassignedHead = [['Case Name / Client', 'Type', 'Complexity', 'Value']]; const unassignedBody = unassignedCases.map(c => [c.name, c.type, c.complexity, formatCurrency(c.value)]); doc.autoTable({ startY: doc.autoTable.previous.finalY + 15, head: [['Unassigned Cases']], theme: 'plain', styles: { fontSize: 14, fontStyle: 'bold' } }); doc.autoTable({ startY: doc.autoTable.previous.finalY + 2, head: unassignedHead, body: unassignedBody, theme: 'grid', headStyles: { fillColor: [44, 62, 80] }, }); } doc.save('Attorney_Workload_Summary.pdf'); }; // --- INITIAL RENDER --- renderAll(); });
Scroll to Top