Author: Pedro Lucas Porcellis <porcellis@eletrotupi.com>
tasks: add form validation, refactor js and add error
css/form.css | 6 + css/header.css | 5 ++ css/tasks.css | 21 ++++++++++ js/tasks.js | 105 +++++++++++++++++++++++++++++++++++++++++++++------ tasks.html | 6 +-
diff --git a/css/form.css b/css/form.css index 67902c805f2485605dd575fa25b37f7da0ff7408..4cccecf8f58d0e220a464e65e59660fb5a14b97c 100644 --- a/css/form.css +++ b/css/form.css @@ -14,10 +14,12 @@ input[type="text"], input[type="email"], input[type="password"], input[type="date"], textarea { width: 100%; padding: 5px; - margin: 10px 0; border: 2px solid #0b0c0c; font-size: 16px; background-color: #ffffff; +} + +input[type="text"], input[type="email"], input[type="password"], input[type="date"] { height: 2.5rem; } @@ -50,7 +52,7 @@ color: #ff0000; } input.error { - border-color: #d4351c; + border-color: #d4351c !important; } button { diff --git a/css/header.css b/css/header.css index 94ad1863b344e653e48f3054e52c1eaf0bb4d345..4a12b626c8779debdb22ce6b6c602e5f221db66e 100644 --- a/css/header.css +++ b/css/header.css @@ -59,4 +59,9 @@ justify-content: center; flex-direction: row; gap: 20px; } + + nav ul.visible { + display: flex; + flex-direction: row; + } } diff --git a/css/tasks.css b/css/tasks.css index 4b4c5554c9a0dee496727633cd971ee6c9f95520..8944165cd221398f23dcd85a1508ad1e6e5a001b 100644 --- a/css/tasks.css +++ b/css/tasks.css @@ -2,3 +2,24 @@ #task-form { display: flex; flex-direction: column; } + +.error-message { + color: #d4351c; + font-size: 0.85rem; + margin-top: 4px; + display: none; +} + +.error-message.visible { + display: block; +} + +input:invalid, textarea:invalid, select:invalid { + border-color: #d4351c; + outline: none; +} + +input:valid, textarea:valid, select:valid { + border-color: green; +} + diff --git a/js/tasks.js b/js/tasks.js index 4e4c059ac340c3e6f7aee8a0f5e196aad7aa0558..eb6db368d62797fb73d7c9233740a67f973298e9 100644 --- a/js/tasks.js +++ b/js/tasks.js @@ -2,30 +2,107 @@ document.addEventListener("DOMContentLoaded", () => { const taskForm = document.getElementById("task-form"); const taskList = document.querySelector("#task-list ul"); - taskForm.addEventListener("submit", (e) => { - e.preventDefault(); + const toggleErrorMessage = (field, condition, message) => { + const errorMessage = field.nextElementSibling; // Mensagem de erro associada ao campo + if (!condition) { + errorMessage.textContent = message; + errorMessage.classList.add("visible"); + field.classList.add("error"); + } else { + errorMessage.textContent = ""; + errorMessage.classList.remove("visible"); + field.classList.remove("error"); + } + }; + + const validateTitle = (field) => { + toggleErrorMessage(field, field.value.trim() !== "", "O título é obrigatório."); + }; + + const validateDescription = (field) => { + toggleErrorMessage(field, field.value.trim() !== "", "A descrição é obrigatória."); + }; + + const validateDeadline = (field) => { + const deadlineDate = new Date(field.value); + const today = new Date(); + toggleErrorMessage( + field, + field.value !== "" && deadlineDate > today, + "O prazo deve ser uma data válida no futuro." + ); + }; - const title = document.getElementById("task-title").value; - const description = document.getElementById("task-desc").value; - const deadline = document.getElementById("task-deadline").value; - const priority = document.getElementById("task-priority").value; + const validatePriority = (field) => { + toggleErrorMessage(field, field.value !== "", "Por favor, selecione uma prioridade."); + }; - if (!title || !description || !deadline || !priority) { - alert("Por favor, preencha todos os campos."); - return; - } + const validateForm = () => { + const title = document.getElementById("task-title"); + const description = document.getElementById("task-desc"); + const deadline = document.getElementById("task-deadline"); + const priority = document.getElementById("task-priority"); + + validateTitle(title); + validateDescription(description); + validateDeadline(deadline); + validatePriority(priority); + + const errors = taskForm.querySelectorAll(".error-message.visible"); + + return errors.length === 0; + }; + const addTaskToList = (task) => { const taskItem = document.createElement("li"); taskItem.innerHTML = ` - <strong>${title}</strong> - <p>${description}</p> - <p>Prazo: ${deadline}</p> - <p>Prioridade: ${priority}</p> + <strong>${task.title}</strong> + <p>${task.description}</p> + <p>Prazo: ${task.deadline}</p> + <p>Prioridade: ${task.priority}</p> <button class="remove-task">Remover</button> `; taskList.appendChild(taskItem); + }; + + const resetForm = () => { taskForm.reset(); + }; + + taskForm.addEventListener("input", (e) => { + const field = e.target; + + switch (field.id) { + case "task-title": + validateTitle(field); + break; + case "task-desc": + validateDescription(field); + break; + case "task-deadline": + validateDeadline(field); + break; + case "task-priority": + validatePriority(field); + break; + } + }); + + taskForm.addEventListener("submit", (e) => { + e.preventDefault(); + + if (validateForm()) { + const task = { + title: document.getElementById("task-title").value.trim(), + description: document.getElementById("task-desc").value.trim(), + deadline: document.getElementById("task-deadline").value, + priority: document.getElementById("task-priority").value, + }; + + addTaskToList(task); + resetForm(); + } }); taskList.addEventListener("click", (e) => { diff --git a/tasks.html b/tasks.html index 8469fdfd897b9efe779cdc44283eb49cc1b068b9..e9f07959915b3933eb9675486b7927b9c9913839 100644 --- a/tasks.html +++ b/tasks.html @@ -30,15 +30,15 @@Adicionar Nova Tarefa
<form id="task-form"> <label for="task-title">Título: <small class="required">*</small></label> - <input type="text" id="task-title" name="title" required> + <input type="text" id="task-title" name="title" placeholder="Comprar legumes"> <small class="error-message hidden">O título é obrigatório.</small> <label for="task-desc">Descrição:</label> - <textarea id="task-desc" name="description" required></textarea> + <textarea id="task-desc" name="description" placeholder="Ir no Cachoeirense, pegar cebolas" rows="10"></textarea> <small class="error-message hidden">A descrição é obrigatória.</small> <label for="task-deadline">Prazo:</label> - <input type="date" id="task-deadline" name="deadline" required> + <input type="date" id="task-deadline" name="deadline"> <small class="error-message hidden">O prazo deve ser uma data válida no futuro.</small> <label for="task-priority">Prioridade:</label>