<!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>
<button onclick="saveChecklistToFile()" class="add-task-button">Salvar Checklist</button>
<button onclick="loadChecklistFromFile()" class="add-task-button">Carregar Checklist</button>
<button onclick="window.print()" class="add-task-button">Imprimir Checklist</button>
<button onclick="downloadHTMLBackup()" class="add-task-button">Baixar Backup HTML</button>
<input type="file" id="uploadFile" class="add-task-button" style="display: none;" onchange="loadChecklistFromFile()">
<button onclick="document.getElementById('uploadHTML').click()" class="add-task-button">Subir HTML</button>
<input type="file" id="uploadHTML" class="add-task-button" style="display: none;" onchange="uploadHTML(event)">
</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';
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);
task.subTasks.forEach(subTask => {
addSubTaskFromData(nestedList, subTask);
});
for (const [key, value] of Object.entries(task.customFields)) {
addCustomFieldFromData(taskContainer, key, value);
}
initializeSortable(nestedList);
}
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);
subTask.subTasks.forEach(subSubTask => {
addSubTaskFromData(subNestedList, subSubTask);
});
for (const [key, value] of Object.entries(subTask.customFields)) {
addCustomFieldFromData(subTaskContainer, key, value);
}
initializeSortable(subNestedList);
}
function addCustomField(taskContainer) {
const fieldName = prompt('Digite o nome do novo campo:');
if (fieldName) {
const customFieldInput = document.createElement('input');
customFieldInput.type = 'text';
customFieldInput.className = 'custom-field-input';
customFieldInput.placeholder = fieldName;
customFieldInput.addEventListener('change', function() {
saveChecklistState();
});
taskContainer.appendChild(customFieldInput);
saveChecklistState();
}
}
function addCustomFieldFromData(taskContainer, fieldName, fieldValue) {
const customFieldInput = document.createElement('input');
customFieldInput.type = 'text';
customFieldInput.className = 'custom-field-input';
customFieldInput.placeholder = fieldName;
customFieldInput.value = fieldValue;
customFieldInput.addEventListener('change', function() {
saveChecklistState();
});
taskContainer.appendChild(customFieldInput);
}
function moveToCompleted(taskContainer) {
const completedTasks = document.getElementById('completedTasks');
completedTasks.appendChild(taskContainer);
}
function handleKeyPress(event) {
if (event.key === 'Enter') {
addTask();
}
}
function filterTasks() {
const tagFilter = document.getElementById('tagFilter').value.toLowerCase();
const personFilter = document.getElementById('personFilter').value;
const customFieldFilter = document.getElementById('customFieldFilter').value.toLowerCase();
const keywordFilter = document.getElementById('keywordFilter').value.toLowerCase();
const checklistItems = document.querySelectorAll('#checklistItems > .checklist-container');
checklistItems.forEach((taskContainer) => {
const tag = taskContainer.getAttribute('data-tag').toLowerCase();
const person = taskContainer.getAttribute('data-person');
const customFields = getCustomFields(taskContainer);
const taskName = taskContainer.querySelector('.checklist-label').value.toLowerCase();
const isTagMatch = tagFilter === '' || tag.includes(tagFilter);
const isPersonMatch = personFilter === '' || person === personFilter;
const isCustomFieldMatch = customFieldFilter === '' || Object.values(customFields).some(value => value.toLowerCase().includes(customFieldFilter));
const isKeywordMatch = keywordFilter === '' || taskName.includes(keywordFilter);
if (isTagMatch && isPersonMatch && isCustomFieldMatch && isKeywordMatch) {
taskContainer.style.display = 'block';
} else {
taskContainer.style.display = 'none';
}
});
}
function updateFilterDropdown() {
const tagFilter = document.getElementById('tagFilter');
const tags = Array.from(document.querySelectorAll('.edit-tag-input')).map(input => input.value.toLowerCase()).filter(tag => tag !== '');
const uniqueTags = [...new Set(tags)];
tagFilter.innerHTML = '<option value="">Todas</option>';
uniqueTags.forEach((tag) => {
const option = document.createElement('option');
option.value = tag;
option.textContent = tag;
tagFilter.appendChild(option);
});
}
function updatePersonFilterDropdown() {
const personFilter = document.getElementById('personFilter');
const persons = Array.from(document.querySelectorAll('.edit-person-input')).map(input => input.value).filter(person => person !== '');
const uniquePersons = [...new Set(persons)];
personFilter.innerHTML = '<option value="">Todas</option>';
uniquePersons.forEach((person) => {
const option = document.createElement('option');
option.value = person;
option.textContent = person;
personFilter.appendChild(option);
});
}
function sortTasksByNumber() {
const checklistItems = document.getElementById('checklistItems');
const tasks = Array.from(checklistItems.children);
tasks.sort((a, b) => {
const aNumber = parseInt(a.getAttribute('data-number'), 10);
const bNumber = parseInt(b.getAttribute('data-number'), 10);
return aNumber - bNumber;
});
tasks.forEach(task => checklistItems.appendChild(task));
saveChecklistState();
}
function filterBlockers() {
const checklistItems = document.querySelectorAll('#checklistItems > .checklist-container');
checklistItems.forEach((taskContainer) => {
const isBlocker = taskContainer.classList.contains('blocker');
if (isBlocker) {
taskContainer.style.display = 'block';
} else {
taskContainer.style.display = 'none';
}
});
}
function generateBlockerReport() {
const blockerReport = document.getElementById('blockerReport');
blockerReport.innerHTML = '';
const checklistItems = document.querySelectorAll('#checklistItems > .checklist-container');
checklistItems.forEach((taskContainer) => {
const isBlocker = taskContainer.classList.contains('blocker');
if (isBlocker) {
const taskName = taskContainer.querySelector('.checklist-label').value;
const blockerItem = document.createElement('div');
blockerItem.className = 'report-item';
blockerItem.textContent = taskName;
blockerReport.appendChild(blockerItem);
}
});
}
function filterProjectTitles() {
const checklistItems = document.querySelectorAll('#checklistItems > .checklist-container');
checklistItems.forEach((taskContainer) => {
const isProjectTitle = taskContainer.classList.contains('project-title');
if (isProjectTitle) {
taskContainer.style.display = 'block';
} else {
taskContainer.style.display = 'none';
}
});
}
function generateProjectTitleReport() {
const projectTitleReport = document.getElementById('projectTitleReport');
projectTitleReport.innerHTML = '';
const checklistItems = document.querySelectorAll('#checklistItems > .checklist-container');
checklistItems.forEach((taskContainer) => {
const isProjectTitle = taskContainer.classList.contains('project-title');
if (isProjectTitle) {
const taskName = taskContainer.querySelector('.checklist-label').value;
const projectTitleItem = document.createElement('div');
projectTitleItem.className = 'report-item';
projectTitleItem.textContent = taskName;
projectTitleReport.appendChild(projectTitleItem);
}
});
}
function generateSortedNumberReport() {
const sortedNumberReport = document.getElementById('sortedNumberReport');
sortedNumberReport.innerHTML = '';
const checklistItems = document.querySelectorAll('#checklistItems > .checklist-container');
const tasks = Array.from(checklistItems).map(taskContainer => {
const taskName = taskContainer.querySelector('.checklist-label').value;
const taskNumber = taskContainer.getAttribute('data-number');
return { taskName, taskNumber };
});
tasks.sort((a, b) => a.taskNumber - b.taskNumber);
tasks.forEach(task => {
const sortedNumberItem = document.createElement('div');
sortedNumberItem.className = 'report-item';
sortedNumberItem.textContent = `${task.taskNumber} - ${task.taskName}`;
sortedNumberReport.appendChild(sortedNumberItem);
});
}
function initializeSortable(nestedList) {
new Sortable(nestedList, {
group: 'nested',
animation: 150,
fallbackOnBody: true,
swapThreshold: 0.65
});
}
function updateCalendar() {
const calendar = document.getElementById('calendar');
calendar.innerHTML = '';
const tasks = getAllTasks();
const events = tasks.map(task => ({
date: task.date,
endDate: task.endDate,
time: task.time,
title: task.name,
id: task.id
}));
const currentMonth = new Date().getMonth();
const currentYear = new Date().getFullYear();
const monthNames = [
'Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho',
'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'
];
const firstDay = new Date(currentYear, currentMonth, 1).getDay();
const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate();
const calendarMonth = document.createElement('div');
calendarMonth.className = 'calendar-month';
calendarMonth.textContent = `${monthNames[currentMonth]} ${currentYear}`;
calendar.appendChild(calendarMonth);
const calendarWeek = document.createElement('div');
calendarWeek.className = 'calendar-week';
calendar.appendChild(calendarWeek);
const daysOfWeek = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'];
daysOfWeek.forEach(day => {
const dayOfWeek = document.createElement('div');
dayOfWeek.className = 'calendar-day';
dayOfWeek.textContent = day;
calendarWeek.appendChild(dayOfWeek);
});
let day = 1;
for (let i = 0; i < 6; i++) {
const calendarWeek = document.createElement('div');
calendarWeek.className = 'calendar-week';
calendar.appendChild(calendarWeek);
for (let j = 0; j < 7; j++) {
const calendarDay = document.createElement('div');
calendarDay.className = 'calendar-day';
if (i === 0 && j < firstDay) {
calendarDay.textContent = '';
} else if (day > daysInMonth) {
calendarDay.textContent = '';
} else {
calendarDay.textContent = day;
const eventForDay = events.filter(event => new Date(event.date).getDate() === day);
eventForDay.forEach(event => {
const eventDiv = document.createElement('div');
eventDiv.className = 'calendar-event';
eventDiv.textContent = event.title;
calendarDay.appendChild(eventDiv);
});
day++;
}
calendarWeek.appendChild(calendarDay);
}
}
}
function getAllTasks() {
const tasks = [];
const checklistItems = document.querySelectorAll('#checklistItems > .checklist-container');
checklistItems.forEach(taskContainer => {
const taskData = getTaskData(taskContainer);
tasks.push(taskData);
taskData.subTasks.forEach(subTask => {
tasks.push(subTask);
});
});
return tasks;
}
function saveChecklistToFile() {
const checklistHTML = document.getElementById('checklistItems').innerHTML;
const blob = new Blob([checklistHTML], { type: 'text/html' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'checklist.html';
a.click();
URL.revokeObjectURL(url);
}
function loadChecklistFromFile() {
const fileInput = document.getElementById('uploadFile');
const file = fileInput.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(event) {
const html = event.target.result;
document.getElementById('checklistItems').innerHTML = html;
restoreChecklistState();
updateCalendar();
};
reader.readAsText(file);
}
}
function downloadHTMLBackup() {
const tasks = getAllTasks();
const htmlContent = JSON.stringify(tasks, null, 2);
const blob = new Blob([htmlContent], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'backup.html';
a.click();
URL.revokeObjectURL(url);
}
function uploadHTML(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
const htmlContent = e.target.result;
const tasks = JSON.parse(htmlContent);
document.getElementById('checklistItems').innerHTML = '';
tasks.forEach(task => {
addTaskFromData(task);
});
updateCalendar();
};
reader.readAsText(file);
}
}
function downloadExcel() {
const tasks = getAllTasks();
const worksheet = XLSX.utils.json_to_sheet(tasks);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, 'Checklist');
XLSX.writeFile(workbook, 'checklist.xlsx');
}
function uploadExcel(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
const tasks = XLSX.utils.sheet_to_json(worksheet);
document.getElementById('checklistItems').innerHTML = '';
tasks.forEach(task => {
addTaskFromData(task);
});
updateCalendar();
};
reader.readAsArrayBuffer(file);
}
}
document.addEventListener('DOMContentLoaded', function() {
restoreChecklistState();
});
</script>
</body>
</html>
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:
Salvar o estado da checklist no localStorage.
Exportar e importar checklists em formato HTML e Excel.
Baixar backups em HTML e Excel e carregar arquivos de checklist desses formatos.
Impressão e Backup:
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.
Adicionar Tarefas e Subtarefas:
Adicionar novas tarefas com campos personalizados como tag, número, pessoa responsável, data, horário, valor, razão, local, e método de execução.
Adicionar subtarefas dentro de tarefas principais.
Campos Personalizados:
Adicionar e gerenciar campos personalizados para cada tarefa.
Filtragem e Ordenação:
Filtrar tarefas por tag, pessoa, campo personalizado e palavras-chave.
Ordenar tarefas por número.
Checklist Interativo:
Marcar tarefas como concluídas, movendo-as para um histórico de atividades concluídas.
Identificar e marcar tarefas bloqueantes e títulos de projetos.
Relatórios:
Gerar relatórios de tarefas bloqueantes, títulos de projetos, e tarefas ordenadas por número.
Visualizar tarefas bloqueantes e títulos de projetos filtrados.
Agenda e Calendário:
Visualizar as tarefas e eventos em um calendário mensal, com horários específicos.
Destacar eventos ocupados no calendário.
Salvamento e Carregamento:
Salvar o estado da checklist no localStorage.
Exportar e importar checklists em formato HTML e Excel.
Baixar backups em HTML e Excel e carregar arquivos de checklist desses formatos.
Impressão e Backup:
Imprimir a checklist.
Baixar um backup em formato HTML.
Subir arquivos HTML para restaurar a checklist.
Interface Interativa:
Usar botões interativos para expandir/colapsar subtarefas, marcar tarefas como bloqueantes ou títulos de projetos, e remover tarefas.
Implementação de sortable para arrastar e soltar tarefas dentro da checklist.
Essas funcionalidades permitem uma gestão detalhada e personalizada de tarefas e projetos, auxiliando na organização e na visualização do progresso das atividades.