Hacks na criação
Inclua no código abaixo deixando ele completo.....
(Editar chat`s até ele acertar)
História do sistema
Sempre fui um péssimo priorizador de atividades e um enrolador por não saber qual tarefa chave de um projeto atacar, sempre me perdi no meio do processo e muitas vezes, não terminei projetos que iniciei por falta de capacidade e organização diante a tantas outras prioridades que surgem diante da nossa jornada.
Sobre o sistema
O sistema "Ballaminut Networking - Sistema de produtividade"
tem diversas funcionalidades que permitem a gestão de tarefas e eventos de forma organizada e eficiente.
As listas de tarefas são interativas, permitindo reordenação dos itens via arrastar e soltar, graças à integração com a biblioteca Sortable.js.
Essas funcionalidades proporcionam um sistema robusto e flexível para o gerenciamento de produtividade, permitindo aos usuários organizarem suas tarefas e eventos de maneira eficiente e personalizada.
Vídeo de explicação
Qual linguagem?
Front End
HTML (HyperText Markup Language):
Utilizada para estruturar o conteúdo da página, incluindo elementos como <div>, <table>, <input>, <button>, e <label>. Define a estrutura básica do documento.
CSS (Cascading Style Sheets):
Usada para estilizar a página web. No código fornecido, há dois blocos <style> que definem o layout, cores, fontes, espaçamento e outros aspectos visuais dos elementos HTML.
JavaScript:
Utilizado para adicionar interatividade e funcionalidade dinâmica à página. O código JavaScript é incluído dentro das tags <script> e fornece funcionalidades como adicionar tarefas, manipular a DOM, armazenar e recuperar dados do localStorage, e implementar um calendário dinâmico.
Biblioteca JavaScript (Sortable.js):
Importada através de uma URL (https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js), esta biblioteca é utilizada para permitir a ordenação dos itens da lista de tarefas através de arrastar e soltar (drag and drop).
Qual código?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ballaminut Networking - Sistema de produtividade</title>
<style>
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
}
th {
background-color: #f2f2f2;
}
td {
vertical-align: top;
}
.checklist {
margin-right: 5px;
}
.project-title-button {
cursor: pointer;
margin-left: 5px;
padding: 2px 4px;
font-size: 14px;
background-color: transparent;
color: green;
border: none;
border-radius: 3px;
}
.project-title-button:hover {
color: darkgreen;
}
.project-title {
border: 2px solid green;
}
.nested-list {
margin-left: 20px;
display: none;
}
.checklist-container {
display: flex;
flex-direction: column;
margin: 10px 0;
}
.checklist-label {
font-size: 18px;
margin-left: 10px;
text-decoration: none;
cursor: pointer;
}
.checklist-label.completed {
text-decoration: line-through;
}
.checklist-input {
width: 20px;
height: 20px;
cursor: pointer;
accent-color: orange;
}
.add-task-container {
margin-bottom: 20px;
}
.add-task-input,
.add-tag-input,
.add-number-input,
.add-person-input,
.add-date-input,
.add-end-date-input,
.add-time-input,
.add-amount-input,
.add-reason-input,
.add-location-input,
.add-method-input {
padding: 5px;
font-size: 16px;
}
.add-task-button {
margin-left: 10px;
padding: 8px 16px;
font-size: 16px;
cursor: pointer;
background-color: orange;
color: white;
border: none;
border-radius: 5px;
}
.add-task-button:hover {
background-color: black;
}
.remove-task-button {
cursor: pointer;
margin-left: 5px;
padding: 2px 4px;
font-size: 10px;
background-color: white;
color: gray;
border: none;
border-radius: 3px;
opacity: 0.8;
}
.remove-task-button:hover {
background-color: lightgray;
}
.edit-number-input,
.edit-tag-input,
.edit-person-input,
.edit-date-input,
.edit-end-date-input,
.edit-time-input,
.edit-amount-input,
.edit-reason-input,
.edit-location-input,
.edit-method-input {
width: 100px;
font-size: 14px;
padding: 2px;
margin-left: 10px;
}
.filter-container {
margin-bottom: 20px;
}
.filter-dropdown {
padding: 5px;
font-size: 16px;
}
.sort-button {
padding: 5px 10px;
font-size: 16px;
cursor: pointer;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
margin-left: 10px;
}
.sort-button:hover {
background-color: #0056b3;
}
.blocker-button {
cursor: pointer;
margin-left: 5px;
padding: 2px 4px;
font-size: 14px;
background-color: transparent;
color: red;
border: none;
border-radius: 3px;
}
.blocker-button:hover {
color: darkred;
}
.blocker {
background-color: #ffcccc;
}
.toggle {
cursor: pointer;
font-weight: bold;
margin-right: 10px;
}
.calendar {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin-top: 20px;
}
.calendar-month {
width: 100%;
text-align: center;
font-weight: bold;
margin: 20px 0;
}
.calendar-day {
width: calc(100% / 7 - 10px);
text-align: center;
border: 1px solid #ccc;
padding: 5px;
cursor: pointer;
}
.calendar-day.occupied {
background-color: #ccc;
}
.calendar-hour {
font-size: 0.8em;
margin-top: 2px;
}
.calendar-week {
display: flex;
justify-content: space-between;
width: 100%;
}
.calendar-event {
background-color: orange;
color: white;
margin: 2px 0;
padding: 2px;
}
.calendar-event.end {
background-color: blue;
color: white;
}
.completed-tasks-container {
margin-top: 40px;
}
.completed-task {
text-decoration: line-through;
color: gray;
}
.report-container {
margin-top: 40px;
}
.report-item {
margin-bottom: 10px;
}
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}
</style>
</head>
<body>
<center><h1>Ballaminut Networking - Sistema de produtividade</h1>
<table>
<b>
<subtitle> >>> Adicione as suas tarefas aqui!!!</subtitle>
<br>
<br>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Caixinha de Checklist e Agenda</title>
</b></table>
</center>
<div class="add-task-container">
<input type="text" id="newTask" class="add-task-input" placeholder="Digite uma nova tarefa" onkeydown="handleKeyPress(event)">
<input type="text" id="newTag" class="add-tag-input" placeholder="Digite uma tag">
<input type="number" id="newNumber" class="add-number-input" placeholder="Número" min="1">
<input type="text" id="newPerson" class="add-person-input" placeholder="Atribuir a">
<input type="date" id="newDate" class="add-date-input" placeholder="Data de realização">
<input type="date" id="newEndDate" class="add-end-date-input" placeholder="Data de término">
<input type="time" id="newTime" class="add-time-input" placeholder="Horário">
<input type="number" id="newAmount" class="add-amount-input" placeholder="Quanto" step="0.01">
<input type="text" id="newReason" class="add-reason-input" placeholder="Por que da tarefa?">
<input type="text" id="newLocation" class="add-location-input" placeholder="Onde será a tarefa?">
<input type="text" id="newMethod" class="add-method-input" placeholder="Como será feita essa tarefa?">
<button onclick="addTask()" class="add-task-button">Adicionar Tarefa</button>
<button onclick="addCustomField()" class="add-task-button">Adicionar Campo Personalizado</button>
</div>
<div class="filter-container">
<label for="tagFilter">Filtrar por tag:</label>
<select id="tagFilter" class="filter-dropdown" onchange="filterTasks()">
<option value="">Todas</option>
</select>
<label for="personFilter">Filtrar por pessoa:</label>
<select id="personFilter" class="filter-dropdown" onchange="filterTasks()">
<option value="">Todas</option>
</select>
<label for="customFieldFilter">Filtrar por campo personalizado:</label>
<input type="text" id="customFieldFilter" class="filter-dropdown" placeholder="Digite o valor exato" oninput="filterTasks()">
<label for="keywordFilter">Filtrar por palavras-chave:</label>
<input type="text" id="keywordFilter" class="filter-dropdown" placeholder="Digite a palavra-chave" oninput="filterTasks()">
<button onclick="sortTasksByNumber()" class="sort-button">Ordenar por Número</button>
<button onclick="filterBlockers()" class="sort-button">Mostrar Bloqueantes</button>
<button onclick="generateBlockerReport()" class="sort-button">Gerar Relatório de Bloqueantes</button>
<button onclick="filterProjectTitles()" class="sort-button">Mostrar Títulos de Projeto</button>
<button onclick="generateProjectTitleReport()" class="sort-button">Gerar Relatório de Títulos de Projeto</button>
<button onclick="generateSortedNumberReport()" class="sort-button">Gerar Relatório Ordenado por Número</button>
<button onclick="downloadExcel()" class="sort-button">Baixar Checklist em Excel</button>
<input type="file" id="uploadExcel" class="sort-button" onchange="uploadExcel(event)" style="display:none;">
<button onclick="document.getElementById('uploadExcel').click()" class="sort-button">Subir Checklist Excel</button>
</div>
<div id="projectTitle" class="project-title"></div>
<div id="checklistItems">
<!-- Itens de checklist serão adicionados aqui dinamicamente -->
</div>
<div class="agenda">
<h1>Minha Agenda com Calendário Mensal e Horários</h1>
<div id="eventsList">
<!-- Lista de eventos será preenchida dinamicamente -->
</div>
<div class="calendar" id="calendar">
<!-- Calendário será preenchido dinamicamente -->
</div>
</div>
<div class="completed-tasks-container">
<h2>Histórico de Atividades Concluídas</h2>
<div id="completedTasks">
<!-- Atividades concluídas serão adicionadas aqui dinamicamente -->
</div>
</div>
<div class="report-container">
<h2>Relatório de Atividades Bloqueantes</h2>
<div id="blockerReport">
<!-- Relatório de bloqueantes será preenchido dinamicamente -->
</div>
</div>
<div class="report-container">
<h2>Relatório de Títulos de Projeto</h2>
<div id="projectTitleReport">
<!-- Relatório de títulos de projeto será preenchido dinamicamente -->
</div>
</div>
<div class="report-container">
<h2>Relatório Ordenado por Número</h2>
<div id="sortedNumberReport">
<!-- Relatório ordenado por número será preenchido dinamicamente -->
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.17.0/xlsx.full.min.js"></script>
<script>
function addTask() {
const taskInput = document.getElementById('newTask');
const taskName = taskInput.value.trim();
const tagInput = document.getElementById('newTag');
const tagName = tagInput.value.trim().toLowerCase();
const numberInput = document.getElementById('newNumber');
const taskNumber = numberInput.value.trim();
const personInput = document.getElementById('newPerson');
const personName = personInput.value.trim();
const dateInput = document.getElementById('newDate');
const taskDate = dateInput.value;
const endDateInput = document.getElementById('newEndDate');
const endDate = endDateInput.value;
const timeInput = document.getElementById('newTime');
const taskTime = timeInput.value;
const amountInput = document.getElementById('newAmount');
const amount = amountInput.value.trim();
const reasonInput = document.getElementById('newReason');
const taskReason = reasonInput.value.trim();
const locationInput = document.getElementById('newLocation');
const taskLocation = locationInput.value.trim();
const methodInput = document.getElementById('newMethod');
const taskMethod = methodInput.value.trim();
if (taskName !== '' && taskNumber !== '') {
const checklistItems = document.getElementById('checklistItems');
const newTaskId = `task-${Date.now()}`;
const taskContainer = document.createElement('div');
taskContainer.className = 'checklist-container';
taskContainer.setAttribute('data-tag', tagName);
taskContainer.setAttribute('data-number', taskNumber);
taskContainer.setAttribute('data-person', personName);
taskContainer.setAttribute('data-date', taskDate);
taskContainer.setAttribute('data-end-date', endDate);
taskContainer.setAttribute('data-time', taskTime);
taskContainer.setAttribute('data-amount', amount);
taskContainer.setAttribute('data-reason', taskReason);
taskContainer.setAttribute('data-location', taskLocation);
taskContainer.setAttribute('data-method', taskMethod);
const taskHeader = document.createElement('div');
taskHeader.style.display = 'flex';
taskHeader.style.alignItems = 'center';
const toggleButton = document.createElement('span');
toggleButton.className = 'toggle';
toggleButton.textContent = '+';
toggleButton.addEventListener('click', function() {
const nested = taskContainer.querySelector('.nested-list');
if (nested.style.display === 'block') {
nested.style.display = 'none';
toggleButton.textContent = '+';
} else {
nested.style.display = 'block';
toggleButton.textContent = '-';
}
});
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = newTaskId;
checkbox.className = 'checklist-input';
checkbox.addEventListener('change', function() {
if (checkbox.checked) {
if (confirm('Você tem certeza que deseja concluir essa tarefa?')) {
label.classList.toggle('completed', checkbox.checked);
moveToCompleted(taskContainer);
saveChecklistState();
} else {
checkbox.checked = false;
}
} else {
label.classList.toggle('completed', checkbox.checked);
checklistItems.appendChild(taskContainer);
saveChecklistState();
}
});
const label = document.createElement('input');
label.type = 'text';
label.className = 'checklist-label';
label.value = taskName;
label.addEventListener('change', function() {
saveChecklistState();
});
const numberInputField = document.createElement('input');
numberInputField.type = 'number';
numberInputField.value = taskNumber;
numberInputField.className = 'edit-number-input';
numberInputField.placeholder = "Número";
numberInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-number', numberInputField.value);
saveChecklistState();
});
const tagInputField = document.createElement('input');
tagInputField.type = 'text';
tagInputField.value = tagName;
tagInputField.className = 'edit-tag-input';
tagInputField.placeholder = "Tag";
tagInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-tag', tagInputField.value.toLowerCase());
saveChecklistState();
updateFilterDropdown();
});
const personInputField = document.createElement('input');
personInputField.type = 'text';
personInputField.value = personName;
personInputField.className = 'edit-person-input';
personInputField.placeholder = "Atribuir a";
personInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-person', personInputField.value);
saveChecklistState();
updatePersonFilterDropdown();
});
const dateInputField = document.createElement('input');
dateInputField.type = 'date';
dateInputField.value = taskDate;
dateInputField.className = 'edit-date-input';
dateInputField.placeholder = "Data de realização";
dateInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-date', dateInputField.value);
saveChecklistState();
updateCalendar();
});
const endDateInputField = document.createElement('input');
endDateInputField.type = 'date';
endDateInputField.value = endDate;
endDateInputField.className = 'edit-end-date-input';
endDateInputField.placeholder = "Data de término";
endDateInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-end-date', endDateInputField.value);
saveChecklistState();
updateCalendar();
});
const timeInputField = document.createElement('input');
timeInputField.type = 'time';
timeInputField.value = taskTime;
timeInputField.className = 'edit-time-input';
timeInputField.placeholder = "Horário";
timeInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-time', timeInputField.value);
saveChecklistState();
updateCalendar();
});
const amountInputField = document.createElement('input');
amountInputField.type = 'number';
amountInputField.value = amount;
amountInputField.className = 'edit-amount-input';
amountInputField.placeholder = "Quanto";
amountInputField.step = "0.01";
amountInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-amount', amountInputField.value);
saveChecklistState();
});
const reasonInputField = document.createElement('input');
reasonInputField.type = 'text';
reasonInputField.value = taskReason;
reasonInputField.className = 'edit-reason-input';
reasonInputField.placeholder = "Por que da tarefa?";
reasonInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-reason', reasonInputField.value);
saveChecklistState();
});
const locationInputField = document.createElement('input');
locationInputField.type = 'text';
locationInputField.value = taskLocation;
locationInputField.className = 'edit-location-input';
locationInputField.placeholder = "Onde será a tarefa?";
locationInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-location', locationInputField.value);
saveChecklistState();
});
const methodInputField = document.createElement('input');
methodInputField.type = 'text';
methodInputField.value = taskMethod;
methodInputField.className = 'edit-method-input';
methodInputField.placeholder = "Como será feita essa tarefa?";
methodInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-method', methodInputField.value);
saveChecklistState();
});
const removeButton = document.createElement('button');
removeButton.type = 'button';
removeButton.className = 'remove-task-button';
removeButton.textContent = 'x';
removeButton.addEventListener('click', function() {
if (confirm('Você tem certeza que deseja excluir essa tarefa?')) {
taskContainer.remove();
saveChecklistState();
updateCalendar();
}
});
const blockerButton = document.createElement('button');
blockerButton.type = 'button';
blockerButton.className = 'blocker-button';
blockerButton.innerHTML = '⚠';
blockerButton.addEventListener('click', function() {
taskContainer.classList.toggle('blocker');
saveChecklistState();
});
const projectTitleButton = document.createElement('button');
projectTitleButton.type = 'button';
projectTitleButton.className = 'project-title-button';
projectTitleButton.innerHTML = '★';
projectTitleButton.addEventListener('click', function() {
taskContainer.classList.toggle('project-title');
saveChecklistState();
});
const addSubTaskButton = document.createElement('button');
addSubTaskButton.type = 'button';
addSubTaskButton.className = 'add-task-button';
addSubTaskButton.textContent = 'Adicionar Subtarefa';
addSubTaskButton.style.marginLeft = '10px';
addSubTaskButton.addEventListener('click', function() {
const subTaskName = prompt('Digite a nova subtarefa:');
if (subTaskName) {
addSubTask(taskContainer, subTaskName);
}
});
const customFieldButton = document.createElement('button');
customFieldButton.type = 'button';
customFieldButton.className = 'add-task-button';
customFieldButton.textContent = 'Adicionar Campo Personalizado';
customFieldButton.style.marginLeft = '10px';
customFieldButton.addEventListener('click', function() {
addCustomField(taskContainer);
});
const nestedList = document.createElement('div');
nestedList.className = 'nested-list';
taskHeader.appendChild(toggleButton);
taskHeader.appendChild(checkbox);
taskHeader.appendChild(label);
taskHeader.appendChild(tagInputField);
taskHeader.appendChild(numberInputField);
taskHeader.appendChild(personInputField);
taskHeader.appendChild(dateInputField);
taskHeader.appendChild(endDateInputField);
taskHeader.appendChild(timeInputField);
taskHeader.appendChild(amountInputField);
taskHeader.appendChild(reasonInputField);
taskHeader.appendChild(locationInputField);
taskHeader.appendChild(methodInputField);
taskHeader.appendChild(blockerButton);
taskHeader.appendChild(projectTitleButton);
taskHeader.appendChild(removeButton);
taskHeader.appendChild(addSubTaskButton);
taskHeader.appendChild(customFieldButton);
taskContainer.appendChild(taskHeader);
taskContainer.appendChild(nestedList);
checklistItems.appendChild(taskContainer);
taskInput.value = '';
tagInput.value = '';
numberInput.value = '';
personInput.value = '';
dateInput.value = '';
endDateInput.value = '';
timeInput.value = '';
amountInput.value = '';
reasonInput.value = '';
locationInput.value = '';
methodInput.value = '';
saveChecklistState();
updateFilterDropdown();
updatePersonFilterDropdown();
updateCalendar();
initializeSortable(nestedList);
}
}
function addSubTask(parentTaskContainer, subTaskName) {
const nestedList = parentTaskContainer.querySelector('.nested-list');
const subTaskId = `subtask-${Date.now()}`;
const subTaskContainer = document.createElement('div');
subTaskContainer.className = 'checklist-container';
subTaskContainer.setAttribute('data-tag', '');
subTaskContainer.setAttribute('data-number', '');
subTaskContainer.setAttribute('data-person', '');
subTaskContainer.setAttribute('data-date', '');
subTaskContainer.setAttribute('data-end-date', '');
subTaskContainer.setAttribute('data-time', '');
subTaskContainer.setAttribute('data-amount', '');
subTaskContainer.setAttribute('data-reason', '');
subTaskContainer.setAttribute('data-location', '');
subTaskContainer.setAttribute('data-method', '');
const subTaskHeader = document.createElement('div');
subTaskHeader.style.display = 'flex';
subTaskHeader.style.alignItems = 'center';
const toggleButton = document.createElement('span');
toggleButton.className = 'toggle';
toggleButton.textContent = '+';
toggleButton.addEventListener('click', function() {
const nested = subTaskContainer.querySelector('.nested-list');
if (nested.style.display === 'block') {
nested.style.display = 'none';
toggleButton.textContent = '+';
} else {
nested.style.display = 'block';
toggleButton.textContent = '-';
}
});
const subCheckbox = document.createElement('input');
subCheckbox.type = 'checkbox';
subCheckbox.id = subTaskId;
subCheckbox.className = 'checklist-input';
subCheckbox.addEventListener('change', function() {
if (subCheckbox.checked) {
if (confirm('Você tem certeza que deseja concluir essa tarefa?')) {
subLabel.classList.toggle('completed', subCheckbox.checked);
moveToCompleted(subTaskContainer);
saveChecklistState();
} else {
subCheckbox.checked = false;
}
} else {
subLabel.classList.toggle('completed', subCheckbox.checked);
nestedList.appendChild(subTaskContainer);
saveChecklistState();
}
});
const subLabel = document.createElement('input');
subLabel.type = 'text';
subLabel.className = 'checklist-label';
subLabel.value = subTaskName;
subLabel.addEventListener('change', function() {
saveChecklistState();
});
const subNumberInputField = document.createElement('input');
subNumberInputField.type = 'number';
subNumberInputField.value = '';
subNumberInputField.className = 'edit-number-input';
subNumberInputField.placeholder = "Número";
subNumberInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-number', subNumberInputField.value);
saveChecklistState();
});
const subTagInputField = document.createElement('input');
subTagInputField.type = 'text';
subTagInputField.value = '';
subTagInputField.className = 'edit-tag-input';
subTagInputField.placeholder = "Tag";
subTagInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-tag', subTagInputField.value.toLowerCase());
saveChecklistState();
updateFilterDropdown();
});
const subPersonInputField = document.createElement('input');
subPersonInputField.type = 'text';
subPersonInputField.value = '';
subPersonInputField.className = 'edit-person-input';
subPersonInputField.placeholder = "Atribuir a";
subPersonInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-person', subPersonInputField.value);
saveChecklistState();
updatePersonFilterDropdown();
});
const subDateInputField = document.createElement('input');
subDateInputField.type = 'date';
subDateInputField.value = '';
subDateInputField.className = 'edit-date-input';
subDateInputField.placeholder = "Data de realização";
subDateInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-date', subDateInputField.value);
saveChecklistState();
updateCalendar();
});
const subEndDateInputField = document.createElement('input');
subEndDateInputField.type = 'date';
subEndDateInputField.value = '';
subEndDateInputField.className = 'edit-end-date-input';
subEndDateInputField.placeholder = "Data de término";
subEndDateInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-end-date', subEndDateInputField.value);
saveChecklistState();
updateCalendar();
});
const subTimeInputField = document.createElement('input');
subTimeInputField.type = 'time';
subTimeInputField.value = '';
subTimeInputField.className = 'edit-time-input';
subTimeInputField.placeholder = "Horário";
subTimeInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-time', subTimeInputField.value);
saveChecklistState();
updateCalendar();
});
const subAmountInputField = document.createElement('input');
subAmountInputField.type = 'number';
subAmountInputField.value = '';
subAmountInputField.className = 'edit-amount-input';
subAmountInputField.placeholder = "Quanto";
subAmountInputField.step = "0.01";
subAmountInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-amount', subAmountInputField.value);
saveChecklistState();
});
const subReasonInputField = document.createElement('input');
subReasonInputField.type = 'text';
subReasonInputField.value = '';
subReasonInputField.className = 'edit-reason-input';
subReasonInputField.placeholder = "Por que da tarefa?";
subReasonInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-reason', subReasonInputField.value);
saveChecklistState();
});
const subLocationInputField = document.createElement('input');
subLocationInputField.type = 'text';
subLocationInputField.value = '';
subLocationInputField.className = 'edit-location-input';
subLocationInputField.placeholder = "Onde será a tarefa?";
subLocationInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-location', subLocationInputField.value);
saveChecklistState();
});
const subMethodInputField = document.createElement('input');
subMethodInputField.type = 'text';
subMethodInputField.value = '';
subMethodInputField.className = 'edit-method-input';
subMethodInputField.placeholder = "Como será feita essa tarefa?";
subMethodInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-method', subMethodInputField.value);
saveChecklistState();
});
const subRemoveButton = document.createElement('button');
subRemoveButton.type = 'button';
subRemoveButton.className = 'remove-task-button';
subRemoveButton.textContent = 'x';
subRemoveButton.addEventListener('click', function() {
if (confirm('Você tem certeza que deseja excluir essa tarefa?')) {
subTaskContainer.remove();
saveChecklistState();
updateCalendar();
}
});
const subBlockerButton = document.createElement('button');
subBlockerButton.type = 'button';
subBlockerButton.className = 'blocker-button';
subBlockerButton.innerHTML = '⚠';
subBlockerButton.addEventListener('click', function() {
subTaskContainer.classList.toggle('blocker');
saveChecklistState();
});
const subProjectTitleButton = document.createElement('button');
subProjectTitleButton.type = 'button';
subProjectTitleButton.className = 'project-title-button';
subProjectTitleButton.innerHTML = '★';
subProjectTitleButton.addEventListener('click', function() {
subTaskContainer.classList.toggle('project-title');
saveChecklistState();
});
const addSubSubTaskButton = document.createElement('button');
addSubSubTaskButton.type = 'button';
addSubSubTaskButton.className = 'add-task-button';
addSubSubTaskButton.textContent = 'Adicionar Subtarefa';
addSubSubTaskButton.style.marginLeft = '10px';
addSubSubTaskButton.addEventListener('click', function() {
const subSubTaskName = prompt('Digite a nova subtarefa:');
if (subSubTaskName) {
addSubTask(subTaskContainer, subSubTaskName);
}
});
const customFieldButton = document.createElement('button');
customFieldButton.type = 'button';
customFieldButton.className = 'add-task-button';
customFieldButton.textContent = 'Adicionar Campo Personalizado';
customFieldButton.style.marginLeft = '10px';
customFieldButton.addEventListener('click', function() {
addCustomField(subTaskContainer);
});
subTaskHeader.appendChild(toggleButton);
subTaskHeader.appendChild(subCheckbox);
subTaskHeader.appendChild(subLabel);
subTaskHeader.appendChild(subTagInputField);
subTaskHeader.appendChild(subNumberInputField);
subTaskHeader.appendChild(subPersonInputField);
subTaskHeader.appendChild(subDateInputField);
subTaskHeader.appendChild(subEndDateInputField);
subTaskHeader.appendChild(subTimeInputField);
subTaskHeader.appendChild(subAmountInputField);
subTaskHeader.appendChild(subReasonInputField);
subTaskHeader.appendChild(subLocationInputField);
subTaskHeader.appendChild(subMethodInputField);
subTaskHeader.appendChild(subBlockerButton);
subTaskHeader.appendChild(subProjectTitleButton);
subTaskHeader.appendChild(subRemoveButton);
subTaskHeader.appendChild(addSubSubTaskButton);
subTaskHeader.appendChild(customFieldButton);
subTaskContainer.appendChild(subTaskHeader);
const subNestedList = document.createElement('div');
subNestedList.className = 'nested-list';
subTaskContainer.appendChild(subNestedList);
nestedList.appendChild(subTaskContainer);
initializeSortable(subNestedList);
updateCalendar();
}
function setProjectTitle(title) {
const projectTitle = document.getElementById('projectTitle');
projectTitle.textContent = title;
}
function saveChecklistState() {
const tasks = [];
const checklistItems = document.querySelectorAll('#checklistItems > .checklist-container');
checklistItems.forEach((taskContainer) => {
const taskHeader = taskContainer.querySelector('div');
const checkbox = taskContainer.querySelector('.checklist-input');
const label = taskContainer.querySelector('.checklist-label');
const tag = taskContainer.querySelector('.edit-tag-input').value.toLowerCase();
const number = taskContainer.querySelector('.edit-number-input').value;
const person = taskContainer.querySelector('.edit-person-input').value;
const date = taskContainer.querySelector('.edit-date-input').value;
const endDate = taskContainer.querySelector('.edit-end-date-input').value;
const time = taskContainer.querySelector('.edit-time-input').value;
const amount = taskContainer.querySelector('.edit-amount-input').value;
const reason = taskContainer.querySelector('.edit-reason-input').value;
const location = taskContainer.querySelector('.edit-location-input').value;
const method = taskContainer.querySelector('.edit-method-input').value;
const isBlocker = taskContainer.classList.contains('blocker');
const isProjectTitle = taskContainer.classList.contains('project-title');
const subTasks = Array.from(taskContainer.querySelector('.nested-list').children).map(subTask => getTaskData(subTask));
const customFields = getCustomFields(taskContainer);
tasks.push({
id: checkbox.id,
name: label.value,
checked: checkbox.checked,
tag: tag,
number: number,
person: person,
date: date,
endDate: endDate,
time: time,
amount: amount,
reason: reason,
location: location,
method: method,
blocker: isBlocker,
projectTitle: isProjectTitle,
subTasks: subTasks,
customFields: customFields
});
});
localStorage.setItem('checklistItems', JSON.stringify(tasks));
}
function getTaskData(taskContainer) {
const checkbox = taskContainer.querySelector('.checklist-input');
const label = taskContainer.querySelector('.checklist-label');
const tag = taskContainer.querySelector('.edit-tag-input').value.toLowerCase();
const number = taskContainer.querySelector('.edit-number-input').value;
const person = taskContainer.querySelector('.edit-person-input').value;
const date = taskContainer.querySelector('.edit-date-input').value;
const endDate = taskContainer.querySelector('.edit-end-date-input').value;
const time = taskContainer.querySelector('.edit-time-input').value;
const amount = taskContainer.querySelector('.edit-amount-input').value;
const reason = taskContainer.querySelector('.edit-reason-input').value;
const location = taskContainer.querySelector('.edit-location-input').value;
const method = taskContainer.querySelector('.edit-method-input').value;
const isBlocker = taskContainer.classList.contains('blocker');
const isProjectTitle = taskContainer.classList.contains('project-title');
const subTasks = Array.from(taskContainer.querySelector('.nested-list').children).map(subTask => getTaskData(subTask));
const customFields = getCustomFields(taskContainer);
return {
id: checkbox.id,
name: label.value,
checked: checkbox.checked,
tag: tag,
number: number,
person: person,
date: date,
endDate: endDate,
time: time,
amount: amount,
reason: reason,
location: location,
method: method,
blocker: isBlocker,
projectTitle: isProjectTitle,
subTasks: subTasks,
customFields: customFields
};
}
function getCustomFields(taskContainer) {
const customFields = {};
const customFieldInputs = taskContainer.querySelectorAll('.custom-field-input');
customFieldInputs.forEach(input => {
customFields[input.placeholder] = input.value;
});
return customFields;
}
function restoreChecklistState() {
const tasks = JSON.parse(localStorage.getItem('checklistItems')) || [];
tasks.forEach((task) => {
addTaskFromData(task);
});
updateFilterDropdown();
updatePersonFilterDropdown();
updateCalendar();
}
function addTaskFromData(task) {
const checklistItems = document.getElementById('checklistItems');
const taskContainer = document.createElement('div');
taskContainer.className = 'checklist-container';
taskContainer.setAttribute('data-tag', task.tag);
taskContainer.setAttribute('data-number', task.number);
taskContainer.setAttribute('data-person', task.person);
taskContainer.setAttribute('data-date', task.date);
taskContainer.setAttribute('data-end-date', task.endDate);
taskContainer.setAttribute('data-time', task.time);
taskContainer.setAttribute('data-amount', task.amount);
taskContainer.setAttribute('data-reason', task.reason);
taskContainer.setAttribute('data-location', task.location);
taskContainer.setAttribute('data-method', task.method);
const taskHeader = document.createElement('div');
taskHeader.style.display = 'flex';
taskHeader.style.alignItems = 'center';
const toggleButton = document.createElement('span');
toggleButton.className = 'toggle';
toggleButton.textContent = '+';
toggleButton.addEventListener('click', function() {
const nested = taskContainer.querySelector('.nested-list');
if (nested.style.display === 'block') {
nested.style.display = 'none';
toggleButton.textContent = '+';
} else {
nested.style.display = 'block';
toggleButton.textContent = '-';
}
});
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = task.id;
checkbox.className = 'checklist-input';
checkbox.checked = task.checked;
checkbox.addEventListener('change', function() {
if (checkbox.checked) {
if (confirm('Você tem certeza que deseja concluir essa tarefa?')) {
label.classList.toggle('completed', checkbox.checked);
moveToCompleted(taskContainer);
saveChecklistState();
} else {
checkbox.checked = false;
}
} else {
label.classList.toggle('completed', checkbox.checked);
checklistItems.appendChild(taskContainer);
saveChecklistState();
}
});
const label = document.createElement('input');
label.type = 'text';
label.className = 'checklist-label';
label.value = task.name;
if (task.checked) {
label.classList.add('completed');
}
label.addEventListener('change', function() {
saveChecklistState();
});
const numberInputField = document.createElement('input');
numberInputField.type = 'number';
numberInputField.value = task.number;
numberInputField.className = 'edit-number-input';
numberInputField.placeholder = "Número";
numberInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-number', numberInputField.value);
saveChecklistState();
});
const tagInputField = document.createElement('input');
tagInputField.type = 'text';
tagInputField.value = task.tag;
tagInputField.className = 'edit-tag-input';
tagInputField.placeholder = "Tag";
tagInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-tag', tagInputField.value.toLowerCase());
saveChecklistState();
updateFilterDropdown();
});
const personInputField = document.createElement('input');
personInputField.type = 'text';
personInputField.value = task.person;
personInputField.className = 'edit-person-input';
personInputField.placeholder = "Atribuir a";
personInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-person', personInputField.value);
saveChecklistState();
updatePersonFilterDropdown();
});
const dateInputField = document.createElement('input');
dateInputField.type = 'date';
dateInputField.value = task.date;
dateInputField.className = 'edit-date-input';
dateInputField.placeholder = "Data de realização";
dateInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-date', dateInputField.value);
saveChecklistState();
updateCalendar();
});
const endDateInputField = document.createElement('input');
endDateInputField.type = 'date';
endDateInputField.value = task.endDate;
endDateInputField.className = 'edit-end-date-input';
endDateInputField.placeholder = "Data de término";
endDateInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-end-date', endDateInputField.value);
saveChecklistState();
updateCalendar();
});
const timeInputField = document.createElement('input');
timeInputField.type = 'time';
timeInputField.value = task.time;
timeInputField.className = 'edit-time-input';
timeInputField.placeholder = "Horário";
timeInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-time', timeInputField.value);
saveChecklistState();
updateCalendar();
});
const amountInputField = document.createElement('input');
amountInputField.type = 'number';
amountInputField.value = task.amount;
amountInputField.className = 'edit-amount-input';
amountInputField.placeholder = "Quanto";
amountInputField.step = "0.01";
amountInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-amount', amountInputField.value);
saveChecklistState();
});
const reasonInputField = document.createElement('input');
reasonInputField.type = 'text';
reasonInputField.value = task.reason;
reasonInputField.className = 'edit-reason-input';
reasonInputField.placeholder = "Por que da tarefa?";
reasonInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-reason', reasonInputField.value);
saveChecklistState();
});
const locationInputField = document.createElement('input');
locationInputField.type = 'text';
locationInputField.value = task.location;
locationInputField.className = 'edit-location-input';
locationInputField.placeholder = "Onde será a tarefa?";
locationInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-location', locationInputField.value);
saveChecklistState();
});
const methodInputField = document.createElement('input');
methodInputField.type = 'text';
methodInputField.value = task.method;
methodInputField.className = 'edit-method-input';
methodInputField.placeholder = "Como será feita essa tarefa?";
methodInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-method', methodInputField.value);
saveChecklistState();
});
const removeButton = document.createElement('button');
removeButton.type = 'button';
removeButton.className = 'remove-task-button';
removeButton.textContent = 'x';
removeButton.addEventListener('click', function() {
if (confirm('Você tem certeza que deseja excluir essa tarefa?')) {
taskContainer.remove();
saveChecklistState();
updateCalendar();
}
});
const blockerButton = document.createElement('button');
blockerButton.type = 'button';
blockerButton.className = 'blocker-button';
blockerButton.innerHTML = '⚠';
blockerButton.addEventListener('click', function() {
taskContainer.classList.toggle('blocker');
saveChecklistState();
});
const projectTitleButton = document.createElement('button');
projectTitleButton.type = 'button';
projectTitleButton.className = 'project-title-button';
projectTitleButton.innerHTML = '★';
projectTitleButton.addEventListener('click', function() {
taskContainer.classList.toggle('project-title');
saveChecklistState();
});
const addSubTaskButton = document.createElement('button');
addSubTaskButton.type = 'button';
addSubTaskButton.className = 'add-task-button';
addSubTaskButton.textContent = 'Adicionar Subtarefa';
addSubTaskButton.style.marginLeft = '10px';
addSubTaskButton.addEventListener('click', function() {
const subTaskName = prompt('Digite a nova subtarefa:');
if (subTaskName) {
addSubTask(taskContainer, subTaskName);
}
});
const customFieldButton = document.createElement('button');
customFieldButton.type = 'button';
customFieldButton.className = 'add-task-button';
customFieldButton.textContent = 'Adicionar Campo Personalizado';
customFieldButton.style.marginLeft = '10px';
customFieldButton.addEventListener('click', function() {
addCustomField(taskContainer);
});
const nestedList = document.createElement('div');
nestedList.className = 'nested-list';
if (task.subTasks) {
task.subTasks.forEach(subTask => {
addSubTaskFromData(nestedList, subTask);
});
}
if (task.customFields) {
for (const fieldName in task.customFields) {
const customField = document.createElement('input');
customField.type = 'text';
customField.value = task.customFields[fieldName];
customField.placeholder = fieldName;
customField.className = 'custom-field-input';
taskHeader.appendChild(customField);
}
}
taskHeader.appendChild(toggleButton);
taskHeader.appendChild(checkbox);
taskHeader.appendChild(label);
taskHeader.appendChild(tagInputField);
taskHeader.appendChild(numberInputField);
taskHeader.appendChild(personInputField);
taskHeader.appendChild(dateInputField);
taskHeader.appendChild(endDateInputField);
taskHeader.appendChild(timeInputField);
taskHeader.appendChild(amountInputField);
taskHeader.appendChild(reasonInputField);
taskHeader.appendChild(locationInputField);
taskHeader.appendChild(methodInputField);
taskHeader.appendChild(blockerButton);
taskHeader.appendChild(projectTitleButton);
taskHeader.appendChild(removeButton);
taskHeader.appendChild(addSubTaskButton);
taskHeader.appendChild(customFieldButton);
taskContainer.appendChild(taskHeader);
taskContainer.appendChild(nestedList);
if (task.blocker) {
taskContainer.classList.add('blocker');
}
if (task.projectTitle) {
taskContainer.classList.add('project-title');
}
checklistItems.appendChild(taskContainer);
initializeSortable(nestedList);
updateCalendar();
}
function addSubTaskFromData(nestedList, subTask) {
const subTaskContainer = document.createElement('div');
subTaskContainer.className = 'checklist-container';
subTaskContainer.setAttribute('data-tag', subTask.tag);
subTaskContainer.setAttribute('data-number', subTask.number);
subTaskContainer.setAttribute('data-person', subTask.person);
subTaskContainer.setAttribute('data-date', subTask.date);
subTaskContainer.setAttribute('data-end-date', subTask.endDate);
subTaskContainer.setAttribute('data-time', subTask.time);
subTaskContainer.setAttribute('data-amount', subTask.amount);
subTaskContainer.setAttribute('data-reason', subTask.reason);
subTaskContainer.setAttribute('data-location', subTask.location);
subTaskContainer.setAttribute('data-method', subTask.method);
const subTaskHeader = document.createElement('div');
subTaskHeader.style.display = 'flex';
subTaskHeader.style.alignItems = 'center';
const toggleButton = document.createElement('span');
toggleButton.className = 'toggle';
toggleButton.textContent = '+';
toggleButton.addEventListener('click', function() {
const nested = subTaskContainer.querySelector('.nested-list');
if (nested.style.display === 'block') {
nested.style.display = 'none';
toggleButton.textContent = '+';
} else {
nested.style.display = 'block';
toggleButton.textContent = '-';
}
});
const subCheckbox = document.createElement('input');
subCheckbox.type = 'checkbox';
subCheckbox.id = subTask.id;
subCheckbox.className = 'checklist-input';
subCheckbox.checked = subTask.checked;
subCheckbox.addEventListener('change', function() {
if (subCheckbox.checked) {
if (confirm('Você tem certeza que deseja concluir essa tarefa?')) {
subLabel.classList.toggle('completed', subCheckbox.checked);
moveToCompleted(subTaskContainer);
saveChecklistState();
} else {
subCheckbox.checked = false;
}
} else {
subLabel.classList.toggle('completed', subCheckbox.checked);
nestedList.appendChild(subTaskContainer);
saveChecklistState();
}
});
const subLabel = document.createElement('input');
subLabel.type = 'text';
subLabel.className = 'checklist-label';
subLabel.value = subTask.name;
if (subTask.checked) {
subLabel.classList.add('completed');
}
subLabel.addEventListener('change', function() {
saveChecklistState();
});
const subNumberInputField = document.createElement('input');
subNumberInputField.type = 'number';
subNumberInputField.value = subTask.number;
subNumberInputField.className = 'edit-number-input';
subNumberInputField.placeholder = "Número";
subNumberInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-number', subNumberInputField.value);
saveChecklistState();
});
const subTagInputField = document.createElement('input');
subTagInputField.type = 'text';
subTagInputField.value = subTask.tag;
subTagInputField.className = 'edit-tag-input';
subTagInputField.placeholder = "Tag";
subTagInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-tag', subTagInputField.value.toLowerCase());
saveChecklistState();
updateFilterDropdown();
});
const subPersonInputField = document.createElement('input');
subPersonInputField.type = 'text';
subPersonInputField.value = subTask.person;
subPersonInputField.className = 'edit-person-input';
subPersonInputField.placeholder = "Atribuir a";
subPersonInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-person', subPersonInputField.value);
saveChecklistState();
updatePersonFilterDropdown();
});
const subDateInputField = document.createElement('input');
subDateInputField.type = 'date';
subDateInputField.value = subTask.date;
subDateInputField.className = 'edit-date-input';
subDateInputField.placeholder = "Data de realização";
subDateInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-date', subDateInputField.value);
saveChecklistState();
updateCalendar();
});
const subEndDateInputField = document.createElement('input');
subEndDateInputField.type = 'date';
subEndDateInputField.value = subTask.endDate;
subEndDateInputField.className = 'edit-end-date-input';
subEndDateInputField.placeholder = "Data de término";
subEndDateInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-end-date', subEndDateInputField.value);
saveChecklistState();
updateCalendar();
});
const subTimeInputField = document.createElement('input');
subTimeInputField.type = 'time';
subTimeInputField.value = subTask.time;
subTimeInputField.className = 'edit-time-input';
subTimeInputField.placeholder = "Horário";
subTimeInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-time', subTimeInputField.value);
saveChecklistState();
updateCalendar();
});
const subAmountInputField = document.createElement('input');
subAmountInputField.type = 'number';
subAmountInputField.value = subTask.amount;
subAmountInputField.className = 'edit-amount-input';
subAmountInputField.placeholder = "Quanto";
subAmountInputField.step = "0.01";
subAmountInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-amount', subAmountInputField.value);
saveChecklistState();
});
const subReasonInputField = document.createElement('input');
subReasonInputField.type = 'text';
subReasonInputField.value = subTask.reason;
subReasonInputField.className = 'edit-reason-input';
subReasonInputField.placeholder = "Por que da tarefa?";
subReasonInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-reason', subReasonInputField.value);
saveChecklistState();
});
const subLocationInputField = document.createElement('input');
subLocationInputField.type = 'text';
subLocationInputField.value = subTask.location;
subLocationInputField.className = 'edit-location-input';
subLocationInputField.placeholder = "Onde será a tarefa?";
subLocationInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-location', subLocationInputField.value);
saveChecklistState();
});
const subMethodInputField = document.createElement('input');
subMethodInputField.type = 'text';
subMethodInputField.value = subTask.method;
subMethodInputField.className = 'edit-method-input';
subMethodInputField.placeholder = "Como será feita essa tarefa?";
subMethodInputField.addEventListener('change', function() {
subTaskContainer.setAttribute('data-method', subMethodInputField.value);
saveChecklistState();
});
const subRemoveButton = document.createElement('button');
subRemoveButton.type = 'button';
subRemoveButton.className = 'remove-task-button';
subRemoveButton.textContent = 'x';
subRemoveButton.addEventListener('click', function() {
if (confirm('Você tem certeza que deseja excluir essa tarefa?')) {
subTaskContainer.remove();
saveChecklistState();
updateCalendar();
}
});
const subBlockerButton = document.createElement('button');
subBlockerButton.type = 'button';
subBlockerButton.className = 'blocker-button';
subBlockerButton.innerHTML = '⚠';
subBlockerButton.addEventListener('click', function() {
subTaskContainer.classList.toggle('blocker');
saveChecklistState();
});
const subProjectTitleButton = document.createElement('button');
subProjectTitleButton.type = 'button';
subProjectTitleButton.className = 'project-title-button';
subProjectTitleButton.innerHTML = '★';
subProjectTitleButton.addEventListener('click', function() {
subTaskContainer.classList.toggle('project-title');
saveChecklistState();
});
const addSubSubTaskButton = document.createElement('button');
addSubSubTaskButton.type = 'button';
addSubSubTaskButton.className = 'add-task-button';
addSubSubTaskButton.textContent = 'Adicionar Subtarefa';
addSubSubTaskButton.style.marginLeft = '10px';
addSubSubTaskButton.addEventListener('click', function() {
const subSubTaskName = prompt('Digite a nova subtarefa:');
if (subSubTaskName) {
addSubTask(subTaskContainer, subSubTaskName);
}
});
const customFieldButton = document.createElement('button');
customFieldButton.type = 'button';
customFieldButton.className = 'add-task-button';
customFieldButton.textContent = 'Adicionar Campo Personalizado';
customFieldButton.style.marginLeft = '10px';
customFieldButton.addEventListener('click', function() {
addCustomField(subTaskContainer);
});
subTaskHeader.appendChild(toggleButton);
subTaskHeader.appendChild(subCheckbox);
subTaskHeader.appendChild(subLabel);
subTaskHeader.appendChild(subTagInputField);
subTaskHeader.appendChild(subNumberInputField);
subTaskHeader.appendChild(subPersonInputField);
subTaskHeader.appendChild(subDateInputField);
subTaskHeader.appendChild(subEndDateInputField);
subTaskHeader.appendChild(subTimeInputField);
subTaskHeader.appendChild(subAmountInputField);
subTaskHeader.appendChild(subReasonInputField);
subTaskHeader.appendChild(subLocationInputField);
subTaskHeader.appendChild(subMethodInputField);
subTaskHeader.appendChild(subBlockerButton);
subTaskHeader.appendChild(subProjectTitleButton);
subTaskHeader.appendChild(subRemoveButton);
subTaskHeader.appendChild(addSubSubTaskButton);
subTaskHeader.appendChild(customFieldButton);
subTaskContainer.appendChild(subTaskHeader);
const subNestedList = document.createElement('div');
subNestedList.className = 'nested-list';
subTaskContainer.appendChild(subNestedList);
nestedList.appendChild(subTaskContainer);
initializeSortable(subNestedList);
updateCalendar();
}
function initializeSortable(container) {
new Sortable(container, {
group: 'nested',
animation: 150,
fallbackOnBody: true,
swapThreshold: 0.65,
onEnd: () => {
saveChecklistState();
}
});
const nestedLists = container.querySelectorAll('.nested-list');
nestedLists.forEach(nestedList => {
new Sortable(nestedList, {
group: 'nested',
animation: 150,
fallbackOnBody: true,
swapThreshold: 0.65,
onEnd: () => {
saveChecklistState();
}
});
});
}
function updateFilterDropdown() {
const tags = new Set();
const tasks = JSON.parse(localStorage.getItem('checklistItems')) || [];
function collectTags(task) {
if (task.tag) {
tags.add(task.tag);
}
if (task.subTasks) {
task.subTasks.forEach(subTask => collectTags(subTask));
}
}
tasks.forEach((task) => {
collectTags(task);
});
const tagFilter = document.getElementById('tagFilter');
tagFilter.innerHTML = '<option value="">Todas</option>';
tags.forEach((tag) => {
const option = document.createElement('option');
option.value = tag;
option.textContent = tag;
tagFilter.appendChild(option);
});
}
function updatePersonFilterDropdown() {
const people = new Set();
const tasks = JSON.parse(localStorage.getItem('checklistItems')) || [];
function collectPeople(task) {
if (task.person) {
people.add(task.person);
}
if (task.subTasks) {
task.subTasks.forEach(subTask => collectPeople(subTask));
}
}
tasks.forEach((task) => {
collectPeople(task);
});
const personFilter = document.getElementById('personFilter');
personFilter.innerHTML = '<option value="">Todas</option>';
people.forEach((person) => {
const option = document.createElement('option');
option.value = person;
option.textContent = person;
personFilter.appendChild(option);
});
}
function filterTasks() {
const selectedTag = document.getElementById('tagFilter').value;
const selectedPerson = document.getElementById('personFilter').value;
const customFieldFilter = document.getElementById('customFieldFilter').value.trim().toLowerCase();
const keywordFilter = document.getElementById('keywordFilter').value.trim().toLowerCase();
function matchesCustomFilters(taskContainer) {
const customFieldInputs = taskContainer.querySelectorAll('.custom-field-input');
for (const input of customFieldInputs) {
if (input.value.toLowerCase() === customFieldFilter) {
return true;
}
}
return customFieldFilter === '';
}
function matchesKeyword(taskContainer) {
const label = taskContainer.querySelector('.checklist-label').value.toLowerCase();
return label.includes(keywordFilter);
}
function matchesFilters(taskContainer) {
const tag = taskContainer.getAttribute('data-tag');
const person = taskContainer.getAttribute('data-person');
const matchesTag = selectedTag === '' || tag === selectedTag;
const matchesPerson = selectedPerson === '' || person === selectedPerson;
const matchesCustom = matchesCustomFilters(taskContainer);
const matchesKeywords = matchesKeyword(taskContainer);
return matchesTag && matchesPerson && matchesCustom && matchesKeywords;
}
function filterTask(taskContainer) {
const showTask = matchesFilters(taskContainer);
const subTasks = taskContainer.querySelectorAll('.checklist-container');
let showSubTasks = false;
subTasks.forEach(subTaskContainer => {
if (filterTask(subTaskContainer)) {
showSubTasks = true;
}
});
if (showTask || showSubTasks) {
taskContainer.style.display = 'flex';
} else {
taskContainer.style.display = 'none';
}
return showTask || showSubTasks;
}
const checklistItems = document.querySelectorAll('#checklistItems > .checklist-container');
checklistItems.forEach(taskContainer => {
filterTask(taskContainer);
});
}
function filterBlockers() {
const checklistItems = document.querySelectorAll('#checklistItems > .checklist-container');
checklistItems.forEach(taskContainer => {
const isBlocker = taskContainer.classList.contains('blocker');
const subTasks = taskContainer.querySelectorAll('.checklist-container');
let showTask = isBlocker;
subTasks.forEach(subTaskContainer => {
if (filterTask(subTaskContainer) && subTaskContainer.classList.contains('blocker')) {
showTask = true;
}
});
if (showTask) {
taskContainer.style.display = 'flex';
} else {
taskContainer.style.display = 'none';
}
});
}
function filterProjectTitles() {
const checklistItems = document.querySelectorAll('#checklistItems > .checklist-container');
checklistItems.forEach(taskContainer => {
const isProjectTitle = taskContainer.classList.contains('project-title');
const subTasks = taskContainer.querySelectorAll('.checklist-container');
let showTask = isProjectTitle;
subTasks.forEach(subTaskContainer => {
if (filterTask(subTaskContainer) && subTaskContainer.classList.contains('project-title')) {
showTask = true;
}
});
if (showTask) {
taskContainer.style.display = 'flex';
} else {
taskContainer.style.display = 'none';
}
});
}
function sortTasksByNumber() {
const checklistItems = document.getElementById('checklistItems');
const tasks = Array.from(checklistItems.children);
tasks.sort((a, b) => b.getAttribute('data-number') - a.getAttribute('data-number'));
tasks.forEach(task => checklistItems.appendChild(task));
}
function generateSortedNumberReport() {
const tasks = JSON.parse(localStorage.getItem('checklistItems')) || [];
const sortedNumberReport = document.getElementById('sortedNumberReport');
sortedNumberReport.innerHTML = '';
const allTasks = [];
function collectTasks(task) {
allTasks.push(task);
if (task.subTasks) {
task.subTasks.forEach(subTask => collectTasks(subTask));
}
}
tasks.forEach(task => collectTasks(task));
allTasks.sort((a, b) => b.number - a.number);
allTasks.forEach(task => {
const taskDiv = document.createElement('div');
taskDiv.className = 'report-item';
taskDiv.textContent = `Número: ${task.number}, Nome: ${task.name}, Pessoa: ${task.person}`;
sortedNumberReport.appendChild(taskDiv);
});
}
function handleKeyPress(event) {
if (event.key === 'Enter') {
addTask();
}
}
function moveToCompleted(taskContainer) {
const completedTasks = document.getElementById('completedTasks');
taskContainer.classList.add('completed-task');
completedTasks.appendChild(taskContainer);
}
function updateCalendar() {
const calendar = document.getElementById('calendar');
calendar.innerHTML = '';
const tasks = JSON.parse(localStorage.getItem('checklistItems')) || [];
const currentDate = new Date();
const currentMonth = currentDate.getMonth();
const currentYear = currentDate.getFullYear();
for (let i = 0; i < 36; i++) {
const year = currentYear + Math.floor((currentMonth + i) / 12);
const monthIndex = (currentMonth + i) % 12;
const monthDiv = document.createElement('div');
monthDiv.classList.add('calendar-month');
monthDiv.textContent = `${getMonthName(monthIndex)} ${year}`;
calendar.appendChild(monthDiv);
const firstDayOfMonth = new Date(year, monthIndex, 1).getDay();
const daysInMonth = new Date(year, monthIndex + 1, 0).getDate();
let weekDiv = document.createElement('div');
weekDiv.classList.add('calendar-week');
calendar.appendChild(weekDiv);
for (let blank = 0; blank < firstDayOfMonth; blank++) {
const blankDay = document.createElement('div');
blankDay.classList.add('calendar-day');
weekDiv.appendChild(blankDay);
}
for (let day = 1; day <= daysInMonth; day++) {
if ((day + firstDayOfMonth - 1) % 7 === 0) {
weekDiv = document.createElement('div');
weekDiv.classList.add('calendar-week');
calendar.appendChild(weekDiv);
}
const date = new Date(year, monthIndex, day);
const dateString = date.toISOString().split('T')[0];
const dayElement = document.createElement('div');
dayElement.classList.add('calendar-day');
dayElement.textContent = day;
dayElement.addEventListener('click', () => {
openTaskModal(dateString);
});
const eventsForDay = getAllEventsForDay(tasks, dateString);
if (eventsForDay.length > 0) {
dayElement.classList.add('occupied');
eventsForDay.sort((a, b) => a.time.localeCompare(b.time));
eventsForDay.forEach(event => {
const eventElement = document.createElement('div');
eventElement.classList.add('calendar-event');
if (event.isEnd) {
eventElement.classList.add('end');
}
eventElement.innerHTML = `${event.time ? event.time + ' - ' : ''}${event.name}`;
dayElement.appendChild(eventElement);
});
}
weekDiv.appendChild(dayElement);
}
}
}
function getAllEventsForDay(tasks, dateString) {
let events = [];
tasks.forEach(task => {
if (task.date === dateString) {
events.push({ name: task.name, reason: task.reason, location: task.location, method: task.method, time: task.time });
}
if (task.endDate === dateString) {
events.push({ name: task.name, reason: task.reason, location: task.location, method: task.method, time: task.time, isEnd: true });
}
if (task.subTasks) {
events = events.concat(getSubTasksForDay(task.subTasks, dateString));
}
});
return events;
}
function getSubTasksForDay(subTasks, dateString) {
let events = [];
subTasks.forEach(subTask => {
if (subTask.date === dateString) {
events.push({ name: subTask.name, reason: subTask.reason, location: subTask.location, method: subTask.method, time: subTask.time });
}
if (subTask.endDate === dateString) {
events.push({ name: subTask.name, reason: subTask.reason, location: subTask.location, method: subTask.method, time: subTask.time, isEnd: true });
}
if (subTask.subTasks) {
events = events.concat(getSubTasksForDay(subTask.subTasks, dateString));
}
});
return events;
}
function getMonthName(monthIndex) {
const months = ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'];
return months[monthIndex % 12];
}
function generateBlockerReport() {
const tasks = JSON.parse(localStorage.getItem('checklistItems')) || [];
const blockerReport = document.getElementById('blockerReport');
blockerReport.innerHTML = '';
const blockersByPerson = {};
function collectBlockers(task) {
if (task.blocker) {
if (!blockersByPerson[task.person]) {
blockersByPerson[task.person] = [];
}
blockersByPerson[task.person].push(task);
}
if (task.subTasks) {
task.subTasks.forEach(subTask => collectBlockers(subTask));
}
}
tasks.forEach(task => collectBlockers(task));
for (const person in blockersByPerson) {
const personDiv = document.createElement('div');
personDiv.className = 'report-item';
personDiv.innerHTML = `<h3>${person}</h3>`;
const taskList = document.createElement('ul');
blockersByPerson[person].forEach(task => {
const taskItem = document.createElement('li');
taskItem.textContent = task.name;
taskList.appendChild(taskItem);
});
personDiv.appendChild(taskList);
blockerReport.appendChild(personDiv);
}
}
function generateProjectTitleReport() {
const tasks = JSON.parse(localStorage.getItem('checklistItems')) || [];
const projectTitleReport = document.getElementById('projectTitleReport');
projectTitleReport.innerHTML = '';
const projectTitlesByPerson = {};
function collectProjectTitles(task) {
if (task.projectTitle) {
if (!projectTitlesByPerson[task.person]) {
projectTitlesByPerson[task.person] = [];
}
projectTitlesByPerson[task.person].push(task);
}
if (task.subTasks) {
task.subTasks.forEach(subTask => collectProjectTitles(subTask));
}
}
tasks.forEach(task => collectProjectTitles(task));
for (const person in projectTitlesByPerson) {
const personDiv = document.createElement('div');
personDiv.className = 'report-item';
personDiv.innerHTML = `<h3>${person}</h3>`;
const taskList = document.createElement('ul');
projectTitlesByPerson[person].forEach(task => {
const taskItem = document.createElement('li');
taskItem.textContent = task.name;
taskList.appendChild(taskItem);
});
personDiv.appendChild(taskList);
projectTitleReport.appendChild(personDiv);
}
}
function addCustomField(taskContainer) {
const fieldName = prompt('Digite o nome do novo campo:');
if (fieldName) {
const customField = document.createElement('input');
customField.type = 'text';
customField.placeholder = fieldName;
customField.className = 'custom-field-input';
customField.addEventListener('change', function() {
taskContainer.setAttribute(`data-custom-${fieldName}`, customField.value);
saveChecklistState();
});
taskContainer.querySelector('div').appendChild(customField);
taskContainer.setAttribute(`data-custom-${fieldName}`, customField.value);
saveChecklistState();
}
}
function openTaskModal(dateString) {
const taskInput = document.getElementById('newTask');
taskInput.value = '';
document.getElementById('newTag').value = '';
document.getElementById('newNumber').value = '';
document.getElementById('newPerson').value = '';
document.getElementById('newDate').value = dateString;
document.getElementById('newEndDate').value = '';
document.getElementById('newTime').value = '';
document.getElementById('newAmount').value = '';
document.getElementById('newReason').value = '';
document.getElementById('newLocation').value = '';
document.getElementById('newMethod').value = '';
const addButton = document.querySelector('.add-task-button');
addButton.onclick = function() {
addTask();
updateCalendar();
};
const modal = document.createElement('div');
modal.className = 'modal';
modal.style.position = 'fixed';
modal.style.top = '50%';
modal.style.left = '50%';
modal.style.transform = 'translate(-50%, -50%)';
modal.style.backgroundColor = 'white';
modal.style.padding = '20px';
modal.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.5)';
const modalContent = `
<h2>Adicionar Tarefa para ${dateString}</h2>
<div class="add-task-container">
<input type="text" id="newTaskModal" class="add-task-input" placeholder="Digite uma nova tarefa">
<input type="text" id="newTagModal" class="add-tag-input" placeholder="Digite uma tag">
<input type="number" id="newNumberModal" class="add-number-input" placeholder="Número" min="1">
<input type="text" id="newPersonModal" class="add-person-input" placeholder="Atribuir a">
<input type="date" id="newDateModal" class="add-date-input" value="${dateString}">
<input type="date" id="newEndDateModal" class="add-end-date-input" placeholder="Data de término">
<input type="time" id="newTimeModal" class="add-time-input" placeholder="Horário">
<input type="number" id="newAmountModal" class="add-amount-input" placeholder="Quanto" step="0.01">
<input type="text" id="newReasonModal" class="add-reason-input" placeholder="Por que da tarefa?">
<input type="text" id="newLocationModal" class="add-location-input" placeholder="Onde será a tarefa?">
<input type="text" id="newMethodModal" class="add-method-input" placeholder="Como será feita essa tarefa?">
<button onclick="addTaskFromModal('${dateString}')" class="add-task-button">Adicionar Tarefa</button>
</div>
`;
modal.innerHTML = modalContent;
document.body.appendChild(modal);
const closeButton = document.createElement('button');
closeButton.textContent = 'Fechar';
closeButton.onclick = function() {
document.body.removeChild(modal);
};
modal.appendChild(closeButton);
}
function addTaskFromModal(dateString) {
const taskName = document.getElementById('newTaskModal').value.trim();
const tagName = document.getElementById('newTagModal').value.trim().toLowerCase();
const taskNumber = document.getElementById('newNumberModal').value.trim();
const personName = document.getElementById('newPersonModal').value.trim();
const taskDate = document.getElementById('newDateModal').value;
const endDate = document.getElementById('newEndDateModal').value;
const taskTime = document.getElementById('newTimeModal').value;
const amount = document.getElementById('newAmountModal').value.trim();
const taskReason = document.getElementById('newReasonModal').value.trim();
const taskLocation = document.getElementById('newLocationModal').value.trim();
const taskMethod = document.getElementById('newMethodModal').value.trim();
if (taskName !== '' && taskNumber !== '') {
const checklistItems = document.getElementById('checklistItems');
const newTaskId = `task-${Date.now()}`;
const taskContainer = document.createElement('div');
taskContainer.className = 'checklist-container';
taskContainer.setAttribute('data-tag', tagName);
taskContainer.setAttribute('data-number', taskNumber);
taskContainer.setAttribute('data-person', personName);
taskContainer.setAttribute('data-date', taskDate);
taskContainer.setAttribute('data-end-date', endDate);
taskContainer.setAttribute('data-time', taskTime);
taskContainer.setAttribute('data-amount', amount);
taskContainer.setAttribute('data-reason', taskReason);
taskContainer.setAttribute('data-location', taskLocation);
taskContainer.setAttribute('data-method', taskMethod);
const taskHeader = document.createElement('div');
taskHeader.style.display = 'flex';
taskHeader.style.alignItems = 'center';
const toggleButton = document.createElement('span');
toggleButton.className = 'toggle';
toggleButton.textContent = '+';
toggleButton.addEventListener('click', function() {
const nested = taskContainer.querySelector('.nested-list');
if (nested.style.display === 'block') {
nested.style.display = 'none';
toggleButton.textContent = '+';
} else {
nested.style.display = 'block';
toggleButton.textContent = '-';
}
});
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = newTaskId;
checkbox.className = 'checklist-input';
checkbox.addEventListener('change', function() {
if (checkbox.checked) {
if (confirm('Você tem certeza que deseja concluir essa tarefa?')) {
label.classList.toggle('completed', checkbox.checked);
moveToCompleted(taskContainer);
saveChecklistState();
} else {
checkbox.checked = false;
}
} else {
label.classList.toggle('completed', checkbox.checked);
checklistItems.appendChild(taskContainer);
saveChecklistState();
}
});
const label = document.createElement('input');
label.type = 'text';
label.className = 'checklist-label';
label.value = taskName;
label.addEventListener('change', function() {
saveChecklistState();
});
const numberInputField = document.createElement('input');
numberInputField.type = 'number';
numberInputField.value = taskNumber;
numberInputField.className = 'edit-number-input';
numberInputField.placeholder = "Número";
numberInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-number', numberInputField.value);
saveChecklistState();
});
const tagInputField = document.createElement('input');
tagInputField.type = 'text';
tagInputField.value = tagName;
tagInputField.className = 'edit-tag-input';
tagInputField.placeholder = "Tag";
tagInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-tag', tagInputField.value.toLowerCase());
saveChecklistState();
updateFilterDropdown();
});
const personInputField = document.createElement('input');
personInputField.type = 'text';
personInputField.value = personName;
personInputField.className = 'edit-person-input';
personInputField.placeholder = "Atribuir a";
personInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-person', personInputField.value);
saveChecklistState();
updatePersonFilterDropdown();
});
const dateInputField = document.createElement('input');
dateInputField.type = 'date';
dateInputField.value = taskDate;
dateInputField.className = 'edit-date-input';
dateInputField.placeholder = "Data de realização";
dateInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-date', dateInputField.value);
saveChecklistState();
updateCalendar();
});
const endDateInputField = document.createElement('input');
endDateInputField.type = 'date';
endDateInputField.value = endDate;
endDateInputField.className = 'edit-end-date-input';
endDateInputField.placeholder = "Data de término";
endDateInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-end-date', endDateInputField.value);
saveChecklistState();
updateCalendar();
});
const timeInputField = document.createElement('input');
timeInputField.type = 'time';
timeInputField.value = taskTime;
timeInputField.className = 'edit-time-input';
timeInputField.placeholder = "Horário";
timeInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-time', timeInputField.value);
saveChecklistState();
updateCalendar();
});
const amountInputField = document.createElement('input');
amountInputField.type = 'number';
amountInputField.value = amount;
amountInputField.className = 'edit-amount-input';
amountInputField.placeholder = "Quanto";
amountInputField.step = "0.01";
amountInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-amount', amountInputField.value);
saveChecklistState();
});
const reasonInputField = document.createElement('input');
reasonInputField.type = 'text';
reasonInputField.value = taskReason;
reasonInputField.className = 'edit-reason-input';
reasonInputField.placeholder = "Por que da tarefa?";
reasonInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-reason', reasonInputField.value);
saveChecklistState();
});
const locationInputField = document.createElement('input');
locationInputField.type = 'text';
locationInputField.value = taskLocation;
locationInputField.className = 'edit-location-input';
locationInputField.placeholder = "Onde será a tarefa?";
locationInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-location', locationInputField.value);
saveChecklistState();
});
const methodInputField = document.createElement('input');
methodInputField.type = 'text';
methodInputField.value = taskMethod;
methodInputField.className = 'edit-method-input';
methodInputField.placeholder = "Como será feita essa tarefa?";
methodInputField.addEventListener('change', function() {
taskContainer.setAttribute('data-method', methodInputField.value);
saveChecklistState();
});
const removeButton = document.createElement('button');
removeButton.type = 'button';
removeButton.className = 'remove-task-button';
removeButton.textContent = 'x';
removeButton.addEventListener('click', function() {
if (confirm('Você tem certeza que deseja excluir essa tarefa?')) {
taskContainer.remove();
saveChecklistState();
updateCalendar();
}
});
const blockerButton = document.createElement('button');
blockerButton.type = 'button';
blockerButton.className = 'blocker-button';
blockerButton.innerHTML = '⚠';
blockerButton.addEventListener('click', function() {
taskContainer.classList.toggle('blocker');
saveChecklistState();
});
const projectTitleButton = document.createElement('button');
projectTitleButton.type = 'button';
projectTitleButton.className = 'project-title-button';
projectTitleButton.innerHTML = '★';
projectTitleButton.addEventListener('click', function() {
taskContainer.classList.toggle('project-title');
saveChecklistState();
});
const addSubTaskButton = document.createElement('button');
addSubTaskButton.type = 'button';
addSubTaskButton.className = 'add-task-button';
addSubTaskButton.textContent = 'Adicionar Subtarefa';
addSubTaskButton.style.marginLeft = '10px';
addSubTaskButton.addEventListener('click', function() {
const subTaskName = prompt('Digite a nova subtarefa:');
if (subTaskName) {
addSubTask(taskContainer, subTaskName);
}
});
const customFieldButton = document.createElement('button');
customFieldButton.type = 'button';
customFieldButton.className = 'add-task-button';
customFieldButton.textContent = 'Adicionar Campo Personalizado';
customFieldButton.style.marginLeft = '10px';
customFieldButton.addEventListener('click', function() {
addCustomField(taskContainer);
});
const nestedList = document.createElement('div');
nestedList.className = 'nested-list';
taskHeader.appendChild(toggleButton);
taskHeader.appendChild(checkbox);
taskHeader.appendChild(label);
taskHeader.appendChild(tagInputField);
taskHeader.appendChild(numberInputField);
taskHeader.appendChild(personInputField);
taskHeader.appendChild(dateInputField);
taskHeader.appendChild(endDateInputField);
taskHeader.appendChild(timeInputField);
taskHeader.appendChild(amountInputField);
taskHeader.appendChild(reasonInputField);
taskHeader.appendChild(locationInputField);
taskHeader.appendChild(methodInputField);
taskHeader.appendChild(blockerButton);
taskHeader.appendChild(projectTitleButton);
taskHeader.appendChild(removeButton);
taskHeader.appendChild(addSubTaskButton);
taskHeader.appendChild(customFieldButton);
taskContainer.appendChild(taskHeader);
taskContainer.appendChild(nestedList);
checklistItems.appendChild(taskContainer);
document.querySelector('.modal').remove();
saveChecklistState();
updateFilterDropdown();
updatePersonFilterDropdown();
updateCalendar();
initializeSortable(nestedList);
}
}
function deleteTaskFromCalendar(event, taskId) {
event.stopPropagation();
const taskContainer = document.querySelector(`#${taskId}`).closest('.checklist-container');
if (taskContainer && confirm('Você tem certeza que deseja excluir essa tarefa?')) {
taskContainer.remove();
saveChecklistState();
updateCalendar();
}
}
function completeTaskFromCalendar(event, taskId) {
event.stopPropagation();
const taskCheckbox = document.querySelector(`#${taskId}`);
if (taskCheckbox && !taskCheckbox.checked) {
taskCheckbox.checked = true;
const taskContainer = taskCheckbox.closest('.checklist-container');
const label = taskContainer.querySelector('.checklist-label');
label.classList.toggle('completed', taskCheckbox.checked);
moveToCompleted(taskContainer);
saveChecklistState();
updateCalendar();
}
}
document.addEventListener("DOMContentLoaded", () => {
restoreChecklistState();
const checklistItems = document.getElementById('checklistItems');
initializeSortable(checklistItems);
updateCalendar();
});
// Function to flatten tasks and subtasks
function flattenTasks(tasks) {
const flattened = [];
function addTasks(task, parentId = null) {
const { subTasks, ...taskWithoutSubtasks } = task;
flattened.push({ ...taskWithoutSubtasks, parentId });
if (subTasks) {
subTasks.forEach(subTask => addTasks(subTask, task.id));
}
}
tasks.forEach(task => addTasks(task));
return flattened;
}
// Function to build hierarchical structure from flattened tasks
function buildHierarchy(flattenedTasks) {
const taskMap = {};
flattenedTasks.forEach(task => {
task.subTasks = [];
taskMap[task.id] = task;
});
const rootTasks = [];
flattenedTasks.forEach(task => {
if (task.parentId) {
taskMap[task.parentId].subTasks.push(task);
} else {
rootTasks.push(task);
}
});
return rootTasks;
}
// Function to download the checklist as an Excel file
function downloadExcel() {
const tasks = JSON.parse(localStorage.getItem('checklistItems')) || [];
const flattenedTasks = flattenTasks(tasks);
const worksheet = XLSX.utils.json_to_sheet(flattenedTasks);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Checklist');
XLSX.writeFile(workbook, 'checklist.xlsx');
}
// Function to upload the Excel file and restore the checklist
function uploadExcel(event) {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function (e) {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
const sheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[sheetName];
const flattenedTasks = XLSX.utils.sheet_to_json(worksheet);
const tasks = buildHierarchy(flattenedTasks);
localStorage.setItem('checklistItems', JSON.stringify(tasks));
document.getElementById('checklistItems').innerHTML = '';
restoreChecklistState();
};
reader.readAsArrayBuffer(file);
}
</script>
</body>
</html>
O Sistema funcionando
Quais funcionalidades?
Projetos x Tarefas
Tarefas
Funcionalidade por funcionalidade
Tarefas e subtarefas podem ser marcadas como bloqueantes. (borda fica vermelha) Há uma funcionalidade para filtrar e gerar relatórios de tarefas bloqueantes.
Tarefas e subtarefas podem ser marcadas como título de projeto. (borda fica verde) Há uma funcionalidade para filtrar e gerar relatórios de títulos de projetos, (Objetivo de se destacar para facilitar a visualização e diferenciação das tarefas que representam inicio de etapas mais importantes.)
Exibição de um calendário mensal que mostra os eventos/tarefas agendadas. O calendário destaca os dias com tarefas e exibe detalhes dos eventos ao clicar.
Posso clicar no calendário para adicionar uma tarefa e a mesma tarefa será adicionada no checklist lá em cima. ( tarefas podem ser adicionados diretamente.)
Posso editar no calendário que a mesma tarefa será editada lá em cima no calendário (Integração dos eventos das tarefas com o calendário espelhados, permitindo edição simultanea de todas as edições dos campos mudando automaticamente tanto no checklist da tarefa como no calendário.)
Permitir concluir a atividade a partir do click da tarefa também através do calendário.
Permitir excluir a atividade a partir do click da tarefa também através do calendário.
Geração de um relatório detalhado das tarefas bloqueantes agrupadas por pessoa atribuída.
Criação de relatórios detalhados de atividades bloqueantes, incluindo informações sobre subtarefas e campos personalizados.
Impressão do relatório de bloqueantes
Geração de um relatório detalhado das tarefas destacadas agrupadas por pessoa atribuída..
Todas as funcionalidades
Permite ao usuário adicionar novas tarefas com vários atributos, como nome, tag, número, pessoa atribuída, datas (início e término), horário, quantidade, razão, local e método de execução.
Possibilidade de adicionar subtarefas a uma tarefa principal.
Cada tarefa pode ter subtarefas aninhadas e desaninhadas, permitindo uma estrutura hierárquica de tarefas.
Possibilidade de adicionar e retirar subtarefas a cada tarefa, com a mesma funcionalidade de detalhamento e edição.
Permite adicionar e retirar subtarefas aninhadas dentro de uma tarefa.
Permite mover tarefas e subtarefas de maneira livre entre todas as tarefas e subtarefas
Permite mover subtarefas para que elas virem tarefas também
Cada tarefa pode ter subtarefas aninhadas.
Subtarefas podem ser adicionadas, editadas e removidas.
As subtarefas possuem os mesmos campos personalizados das tarefas principais.
Cada tarefa e subtarefa pode ser personalizada com campos adicionais criados pelo usuário.
Estas funcionalidades permitem ao usuário gerenciar eficientemente suas tarefas, subtarefas e eventos, oferecendo flexibilidade e personalização para adaptar o sistema às suas necessidades específicas.
Adição de campos personalizados a cada tarefa para maior flexibilidade na descrição de tarefas.
Movimentação de Tarefas e Subtarefas:
Tarefas e subtarefas podem ser movidas livremente entre listas, permitindo a criação de hierarquias flexíveis.
Subtarefas podem ser movidas para se tornarem tarefas principais e vice-versa.
Possibilidade de adicionar campos personalizados a cada tarefa, permitindo a customização conforme as necessidades do usuário.
Usuário pode adicionar novos campos personalizados a uma tarefa ou subtarefa
Campos personalizados, permitindo ao usuário visualizar tarefas específicas com base nesses critérios.
Palavras-chave e destaque (Inclua a funcionalidade de filtrar por Palavras-chave, mesmo que as tarefas e subtarefas estejam minizadas)
Filtro para mostrar apenas tarefas bloqueantes. (Filtragem de tarefas bloqueantes)
Filtrar por títulos de projetos (Destaque (tarefas destacadas)..)
Função para ordenar tarefas pelo número associado a elas.
(Ordenar da maior para a menor independente de ser tarefa ou subtarefas
Tarefas podem ser marcadas como concluídas, sendo movidas para a seção de atividades concluídas e exibidas com um estilo diferente (riscadas).
Você tem certeza que deseja concluir essa tarefa?
Gerenciamento de Bloqueantes e títulos de projetos
Tarefas podem ser marcadas como bloqueantes. (borda fica vermelha) Há uma funcionalidade para filtrar e gerar relatórios de tarefas bloqueantes.
Tarefas podem ser marcadas como título de projeto. (borda fica verde) Há uma funcionalidade para filtrar e gerar relatórios de títulos de projetos, (Objetivo de se destacar para facilitar a visualização e diferenciação das tarefas que representam inicio de etapas mais importantes.) (Permite marcar tarefas e subtarefas como títulos de projeto (borda verde).)
Agenda com Calendário Integrado:
Exibição de um calendário mensal que mostra os eventos/tarefas agendadas. O calendário destaca os dias com tarefas e exibe detalhes dos eventos ao clicar.
Integração com tarefas para mostrar eventos no calendário.
Eventos são exibidos nos dias correspondentes, incluindo eventos de início e término.
Adicionar Tarefas Direto no Calendário: Permite adicionar tarefas diretamente clicando em um dia específico no calendário, com os mesmos campos das tarefas principais. (Posso clicar no calendário para adicionar uma tarefa e a mesma tarefa será adicionada no checklist lá em cima. ( tarefas podem ser adicionados diretamente tanto no checklist como no calendário.) Como se ao clicar o calendário eu estivesse clicando no botão Sub tarefa, quero que tenha a função exatada desse botão no checklist lá em cima.)
Posso editar no calendário que a mesma tarefa será editada lá em cima no calendário (Integração dos eventos das tarefas com o calendário espelhados, permitindo edição simultanea de todas as edições dos campos mudando automaticamente tanto no checklist da tarefa como no calendário.)
Permitir concluir a atividade a partir do click da tarefa também através do calendário.
Permitir excluir a atividade a partir do click da tarefa também através do calendário.
Permitir que eu arraste a terafa do calendário para outro dia do calendário e que a tarefa acima lá no checklist se atualize sozinha
Funcionalidade para excluir ou marcar como concluída uma tarefa diretamente do calendário.
Relatório de Bloqueantes e tarefas destacadas (Títulos de Projeto) e Relatório de Tarefas Ordenadas por Número: :
Geração de um relatório detalhado das tarefas bloqueantes agrupadas por pessoa atribuída. (Gera um relatório de todas as tarefas e subtarefas bloqueantes.)
Criação de relatórios detalhados de atividades bloqueantes, incluindo informações sobre subtarefas e campos personalizados. (Gera um relatório de todas as tarefas e subtarefas marcadas como títulos de projeto.)
Geração de relatórios de tarefas bloqueantes e títulos de projeto, agrupados por pessoa atribuída.
Impressão do relatório de bloqueantes
Geração de um relatório detalhado das tarefas destacadas agrupadas por pessoa atribuída..
Gera um relatório de todas as tarefas e subtarefas ordenadas por número, da maior para a menor.
Uso do localStorage para salvar e restaurar o estado das tarefas, mantendo a persistência de dados mesmo após recarregar a página.
Banco de dados próprio
Banco de dados no servidor
Tarefas podem ser editadas diretamente na interface, incluindo a alteração de atributos como tag, número, pessoa, datas, horário, etc.
Editar o nome da tarefa e subtarefas ( O nome das tarefas e subtarefas também podem ser editadas (Permite a edição do nome das tarefas e subtarefas.)
Tarefas do calendário podem ser editadas e sincronizadas com o checklist.
Tarefas e subtarefas podem ser removidas da lista.
Você tem certeza que você deseja excluir essa tarefa?
Histórico de Tarefas Concluídas:
Registro de tarefas concluídas com possibilidade de visualização de um histórico.
Interface Responsiva: e Usabilidade Interativa:
Expansão e contração de listas de tarefas e subtarefas. (Permite expandir e contrair subtarefas para melhor organização visual.)
Marcação de tarefas como concluídas com a opção de mover para o histórico de atividades concluídas.
Uso de botões para adicionar, editar e remover tarefas e subtarefas.
Integração com LocalStorage para salvar o estado do checklist.
Eventos de Teclado: Permite adicionar tarefas pressionando a tecla Enter.
Modal para adicionar tarefas específicas para datas selecionadas no calendário.
Funções para Atualizar o Calendário: Funções para atualizar o calendário com base nas tarefas adicionadas e modificadas.
Confirmar ao excluir tarefas: "Você tem certeza que deseja excluir essa tarefa?
Confirmar ao concluir tarefas: "Você tem certeza que deseja concluir essa tarefa?
Manipulação de Elementos DOM:
Utilização de eventos DOM para adicionar, remover, editar e marcar tarefas diretamente na interface do usuário.
Drag and Drop
Implementação de arrastar e soltar para reordenar tarefas e subtarefas usando a biblioteca Sortable.
O código acima implementa um sistema de produtividade com várias funcionalidades organizadas em torno de um checklist e um calendário mensal. Aqui estão as principais funcionalidades presentes:
Funcionalidades de Backup e Restauração:
Download do Checklist em Excel: Permite fazer o download do checklist de tarefas e subtarefas em formato Excel
Upload de Checklist em Excel: Permite fazer o upload de um arquivo Excel para restaurar o checklist de tarefas e subtarefas.
Próxima atualização fazer com que o calendário possa tudo isso que já tem.
Funções para Atualizar o Calendário: Funções para atualizar o calendário com base nas tarefas adicionadas e modificadas.
Funcionalidade para excluir ou marcar como concluída uma tarefa diretamente do calendário.
Tarefas podem ser marcadas como concluídas, sendo movidas para a seção de atividades concluídas e exibidas com um estilo diferente (riscadas).
Você tem certeza que deseja concluir essa tarefa?
Tarefas podem ser editadas diretamente na interface, incluindo a alteração de atributos como tag, número, pessoa, datas, horário, etc.
Editar o nome da tarefa e subtarefas ( O nome das tarefas e subtarefas também podem ser editadas (Permite a edição do nome das tarefas e subtarefas.)
Tarefas do calendário podem ser editadas e sincronizadas com o checklist.
O sistema acima, "Ballaminut Networking - Sistema de produtividade", é uma aplicação web para gerenciamento de tarefas e produtividade. Abaixo estão listadas as principais funcionalidades do sistema:
Adicionar Tarefas: Permite adicionar novas tarefas com diversos campos:
Adicionar Subtarefas: As tarefas podem ter subtarefas associadas.
Adicionar Campos Personalizados: Permite adicionar campos personalizados às tarefas para atender a necessidades específicas.
Marcar Tarefas como Concluídas: As tarefas podem ser marcadas como concluídas através de um checkbox. Tarefas concluídas são movidas para o histórico de atividades concluídas.
Excluir Tarefas: As tarefas podem ser excluídas.
Marcar Tarefas como Bloqueantes: Tarefas podem ser marcadas como bloqueantes para indicar que estão impedindo o progresso de outras tarefas.
Marcar Tarefas como Títulos de Projeto: Tarefas podem ser marcadas como títulos de projeto para diferenciar projetos principais de tarefas normais.
Filtrar Tarefas: Permite filtrar tarefas por tag, pessoa atribuída, campo personalizado e palavras-chave.
Ordenar Tarefas por Número: Permite ordenar tarefas de acordo com o número associado a elas.
Mostrar Bloqueantes: Permite filtrar a visualização para mostrar apenas tarefas bloqueantes.
Mostrar Títulos de Projeto: Permite filtrar a visualização para mostrar apenas tarefas marcadas como títulos de projeto.
Gerar Relatório de Bloqueantes: Gera um relatório de todas as tarefas bloqueantes, agrupadas por pessoa atribuída.
Gerar Relatório de Títulos de Projeto: Gera um relatório de todas as tarefas marcadas como títulos de projeto, agrupadas por pessoa atribuída.
Gerar Relatório Ordenado por Número: Gera um relatório de todas as tarefas, ordenadas por número.
Visualização de Calendário Mensal: Exibe um calendário mensal com as tarefas distribuídas nos respectivos dias.
Adicionar Tarefas através do Calendário: Permite adicionar tarefas diretamente no calendário, selecionando o dia desejado.
As principais funcionalidades
Não mude nada, só confirme para mim se esse código está condizente com:
IDE: 1xjgb-5xt7SB0WzmwtWUYZQodKzMym2iAlzWzy8qRyFE
Aba da planilha: Projects
Link da Instalação do Script: https://script.google.com/macros/s/AKfycbz3GuCR5O2Gw1pK4YTURCzZI5bImw0nzXFw9UyDxmTFD9MlF9FyZxi3ZCwVw4IfVLqbrg/exec
Código do GS que está no google apps:
function doPost(e) {
var action = e.parameter.action;
if (action == 'addProject') {
return addProject(e);
} else if (action == 'getProjects') {
return getProjects();
}
return ContentService.createTextOutput(JSON.stringify({ status: 'failure', message: 'Action not recognized' }));
}
function addProject(e) {
var projectName = e.parameter.projectName;
var activities = JSON.parse(e.parameter.activities);
var sheet = SpreadsheetApp.openById('1xjgb-5xt7SB0WzmwtWUYZQodKzMym2iAlzWzy8qRyFE').getSheetByName('Projects');
var row = [projectName];
activities.forEach(function(activity) {
row.push(activity);
});
sheet.appendRow(row);
return ContentService.createTextOutput(JSON.stringify({ status: 'success' }));
}
function getProjects() {
var sheet = SpreadsheetApp.openById('1xjgb-5xt7SB0WzmwtWUYZQodKzMym2iAlzWzy8qRyFE').getSheetByName('Projects');
var data = sheet.getDataRange().getValues();
return ContentService.createTextOutput(JSON.stringify(data));
}
backend
Plataforma
Url da implantação
https://script.google.com/macros/s/AKfycbyEfLdcASrTYzLh_mE_rLKMsGOrQOxl4z0KBKQtVQjvrrQIbhy2mkK96xKbIO-4HLEC7A/exec
FrontEnd
Sistemas
Para criar um sistema web completo com banco de dados, interconexões entre páginas e funcionalidades de login, aqui estão os passos gerais que você pode seguir:
Com dedicação e prática constante, você poderá desenvolver sistemas web completos com banco de dados e funcionalidades avançadas de login.