Smart Project Task Splitter

Smart Project Task Splitter

Project Details

Project Phases

Task Summary

Total Tasks0
To Do0
In Progress0
Completed0

All Tasks

Detailed task lists are available in the 'Project Breakdown' tab and the PDF export.

Tips for Effective Task Splitting

Use the Work Breakdown Structure (WBS) Approach
Start with major project deliverables or phases and progressively break them down into smaller, more manageable components (tasks and sub-tasks).
The 100% Rule
The WBS should include 100% of the work defined by the project scope and capture all deliverables – internal, external, interim – in terms of the work to be completed, including project management.
Make Tasks Actionable and Specific
Each task should have a clear outcome and a defined start and end. Use action verbs. For example, instead of "User Documentation," use "Write User Manual Draft."
Ensure Tasks are Measurable
Define how you will know when a task is successfully completed. This helps in tracking progress accurately.
Assign Responsibility
Each task should have a clear owner responsible for its completion.
Set Realistic Timeframes/Effort
Estimate the effort or duration for each task. Be realistic. Tasks that are too long (e.g., more than a week or two for one person) might need further breakdown.
Consider Dependencies (Mentally for this tool)
While this tool doesn't formally track dependencies, think about the order in which tasks need to be done. Which tasks rely on others being completed first?
Keep Tasks Manageable
A common rule of thumb is that a task should not be shorter than 4 hours or longer than 40-80 hours of work. Adjust based on your project's nature.
Review and Refine
Task breakdown is often an iterative process. Review your list with your team (if applicable) and make adjustments as needed.
×

Add New Phase

×

Add New Task

` : ''}
`; tasksListEl.appendChild(taskEl); }); } function sptsRenderTaskSummary() { let totalTasks = 0; let todoTasks = 0; let inProgressTasks = 0; let completedTasks = 0; sptsProject.phases.forEach(phase => { if (phase.tasks) { totalTasks += phase.tasks.length; phase.tasks.forEach(task => { if (task.status === 'To Do') todoTasks++; else if (task.status === 'In Progress') inProgressTasks++; else if (task.status === 'Completed') completedTasks++; }); } }); document.getElementById('sptsTotalTasksCount').textContent = totalTasks; document.getElementById('sptsTodoTasksCount').textContent = todoTasks; document.getElementById('sptsInProgressTasksCount').textContent = inProgressTasks; document.getElementById('sptsCompletedTasksCount').textContent = completedTasks; // Optionally, render a full list of tasks in the summary tab too // const allTasksListEl = document.getElementById('sptsAllTasksList'); // allTasksListEl.innerHTML = ''; // Clear previous list // ... logic to build and append task items similar to phase view ... } // --- MODAL HANDLING --- function sptsOpenModal(modalId) { document.getElementById(modalId).style.display = 'block'; } function sptsCloseModal(modalId) { document.getElementById(modalId).style.display = 'none'; } window.onclick = function(event) { // Close modals if clicked outside if (event.target == sptsPhaseModal) sptsCloseModal('sptsPhaseModal'); if (event.target == sptsTaskModal) sptsCloseModal('sptsTaskModal'); } // --- PHASE CRUD --- window.sptsOpenPhaseModal = function(phaseIdToEdit = null) { sptsPhaseForm.reset(); if (phaseIdToEdit) { const phase = sptsProject.phases.find(p => p.id === phaseIdToEdit); if (phase) { sptsPhaseModalTitle.textContent = 'Edit Phase'; sptsPhaseIdInput.value = phase.id; sptsPhaseNameInput.value = phase.name; } } else { sptsPhaseModalTitle.textContent = 'Add New Phase'; sptsPhaseIdInput.value = ''; } sptsOpenModal('sptsPhaseModal'); } sptsPhaseForm.addEventListener('submit', function(e) { e.preventDefault(); const phaseId = sptsPhaseIdInput.value; const phaseName = sptsPhaseNameInput.value.trim(); if (!phaseName) { alert('Phase name cannot be empty.'); return; } if (phaseId) { // Editing existing phase const phase = sptsProject.phases.find(p => p.id === phaseId); if (phase) phase.name = phaseName; } else { // Adding new phase const newPhase = { id: 'spts-phase-' + Date.now(), name: phaseName, tasks: [] }; sptsProject.phases.push(newPhase); } sptsSaveData(); sptsRenderPhases(); sptsCloseModal('sptsPhaseModal'); }); window.sptsDeletePhase = function(phaseId) { if (confirm('Are you sure you want to delete this phase and all its tasks?')) { sptsProject.phases = sptsProject.phases.filter(p => p.id !== phaseId); sptsSaveData(); sptsRenderPhases(); } } // --- TASK CRUD --- window.sptsOpenTaskModal = function(phaseId, taskIdToEdit = null) { sptsTaskForm.reset(); sptsTaskPhaseIdInput.value = phaseId; const phase = sptsProject.phases.find(p => p.id === phaseId); if (!phase) return; if (taskIdToEdit) { const task = phase.tasks.find(t => t.id === taskIdToEdit); if (task) { sptsTaskModalTitle.textContent = `Edit Task in ${phase.name}`; sptsTaskIdInput.value = task.id; sptsTaskNameInput.value = task.name; sptsTaskDescriptionInput.value = task.description || ''; sptsTaskEffortInput.value = task.effort || ''; sptsTaskAssigneeInput.value = task.assignee || ''; sptsTaskDueDateInput.value = task.dueDate || ''; sptsTaskStatusInput.value = task.status || 'To Do'; } } else { sptsTaskModalTitle.textContent = `Add New Task to ${phase.name}`; sptsTaskIdInput.value = ''; } sptsOpenModal('sptsTaskModal'); } sptsTaskForm.addEventListener('submit', function(e) { e.preventDefault(); const phaseId = sptsTaskPhaseIdInput.value; const taskId = sptsTaskIdInput.value; const taskName = sptsTaskNameInput.value.trim(); if (!taskName) { alert('Task name cannot be empty.'); return; } const phase = sptsProject.phases.find(p => p.id === phaseId); if (!phase) return; const taskData = { name: taskName, description: sptsTaskDescriptionInput.value.trim(), effort: sptsTaskEffortInput.value ? parseInt(sptsTaskEffortInput.value) : null, assignee: sptsTaskAssigneeInput.value.trim(), dueDate: sptsTaskDueDateInput.value, status: sptsTaskStatusInput.value }; if (taskId) { // Editing existing task const taskIndex = phase.tasks.findIndex(t => t.id === taskId); if (taskIndex > -1) { phase.tasks[taskIndex] = { ...phase.tasks[taskIndex], ...taskData }; } } else { // Adding new task const newTask = { id: 'spts-task-' + Date.now(), ...taskData }; phase.tasks.push(newTask); } sptsSaveData(); sptsRenderTasksForPhase(phaseId); sptsCloseModal('sptsTaskModal'); }); window.sptsDeleteTask = function(phaseId, taskId) { if (confirm('Are you sure you want to delete this task?')) { const phase = sptsProject.phases.find(p => p.id === phaseId); if (phase) { phase.tasks = phase.tasks.filter(t => t.id !== taskId); sptsSaveData(); sptsRenderTasksForPhase(phaseId); } } } // --- PDF GENERATION --- sptsDownloadPdfButton.addEventListener('click', function() { const doc = new jsPDF(); const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--spts-primary-color').trim(); const secondaryColor = getComputedStyle(document.documentElement).getPropertyValue('--spts-secondary-color').trim(); const textColor = getComputedStyle(document.documentElement).getPropertyValue('--spts-text-color').trim(); doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text(`Project Breakdown: ${sptsProject.name || 'Untitled Project'}`, 14, 22); doc.setFontSize(11); doc.setTextColor(100); doc.text(`Report generated on: ${new Date().toLocaleDateString()}`, 14, 30); let yPos = 40; // Project Details doc.setFontSize(12); doc.setTextColor(textColor); if(sptsProject.goal) { doc.text(`Goal: ${sptsProject.goal}`, 14, yPos); yPos += 7; } if(sptsProject.startDate) { doc.text(`Start Date: ${new Date(sptsProject.startDate + 'T00:00:00').toLocaleDateString()}`, 14, yPos); yPos += 7; } if(sptsProject.endDate) { doc.text(`End Date: ${new Date(sptsProject.endDate + 'T00:00:00').toLocaleDateString()}`, 14, yPos); yPos += 10; } sptsProject.phases.forEach((phase, index) => { if (yPos > 260 && index > 0) { // Add new page if content is too long doc.addPage(); yPos = 20; } doc.setFontSize(14); doc.setTextColor(secondaryColor); doc.text(`Phase: ${phase.name}`, 14, yPos); yPos += 8; if (phase.tasks && phase.tasks.length > 0) { const tableColumn = ["#", "Task Name", "Description", "Effort (h)", "Assignee", "Due Date", "Status"]; const tableRows = []; phase.tasks.forEach((task, taskIndex) => { const taskData = [ taskIndex + 1, task.name || "N/A", task.description || "N/A", task.effort !== null ? task.effort : "N/A", task.assignee || "N/A", task.dueDate ? new Date(task.dueDate + 'T00:00:00').toLocaleDateString() : "N/A", task.status || "N/A" ]; tableRows.push(taskData); }); doc.autoTable({ head: [tableColumn], body: tableRows, startY: yPos, theme: 'grid', headStyles: { fillColor: secondaryColor, textColor: '#ffffff' }, styles: { font: 'Arial', fontSize: 8, cellPadding: 1.5, overflow: 'linebreak' }, columnStyles: { 0: { cellWidth: 8 }, // # 1: { cellWidth: 35 }, // Task Name 2: { cellWidth: 50 }, // Description 3: { cellWidth: 15 }, // Effort 4: { cellWidth: 25 }, // Assignee 5: { cellWidth: 20 }, // Due Date 6: { cellWidth: 20 } // Status }, didDrawPage: function (data) { // Handle page breaks if table is very long yPos = data.cursor.y + 15; // Update yPos for next element } }); yPos = doc.lastAutoTable.finalY + 10; // Ensure yPos is updated after table } else { doc.setFontSize(10); doc.setTextColor(textColor); doc.text("No tasks in this phase.", 16, yPos); yPos += 10; } }); // Summary in PDF if (yPos > 250) { doc.addPage(); yPos = 20;} doc.setFontSize(14); doc.setTextColor(primaryColor); doc.text("Task Summary", 14, yPos); yPos += 8; doc.setFontSize(10); doc.setTextColor(textColor); let totalTasks = 0, todo = 0, inProgress = 0, completed = 0; sptsProject.phases.forEach(p => p.tasks.forEach(t => { totalTasks++; if(t.status === 'To Do') todo++; else if(t.status === 'In Progress') inProgress++; else if(t.status === 'Completed') completed++; })); doc.text(`Total Tasks: ${totalTasks}`, 14, yPos); yPos += 6; doc.text(`To Do: ${todo}`, 14, yPos); yPos += 6; doc.text(`In Progress: ${inProgress}`, 14, yPos); yPos += 6; doc.text(`Completed: ${completed}`, 14, yPos); doc.save(`Project_Task_Breakdown_${(sptsProject.name || 'Export').replace(/\s+/g, '_')}_${new Date().toISOString().slice(0,10)}.pdf`); }); // --- INITIALIZATION --- document.addEventListener('DOMContentLoaded', () => { sptsLoadProject(); // Activate the first tab if (document.querySelector('#smartProjectTaskSplitterTool .spts-tab-button')) { document.querySelector('#smartProjectTaskSplitterTool .spts-tab-button').click(); } });
Scroll to Top