Build a Customer Complaint Form - Build a Customer Complaint Form. Step 31

Tell us what’s happening:

Hi, i’m challenged with passing 31 step of this lab
My code seems to meet all the requirements and it works well when i test the form. Though i stuck.
Moreover i’b a bit confused with function isValid(). There are two interpretations of how it should look like.
1/ function isValid should take the object returned by validateForm as argument …
2/ isValid function should take the validateForm() as argument.
I tried both and it still didn’t work. Perhaps it’s not about that. thanks in advance.

Your code so far

<!-- file: index.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Customer Complaint Form</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
</head>

<body>
    <h1>Complaint Form</h1>
    <form id="form">
        <fieldset id="personal-info">
            <div>
                <label for="full-name">Full Name:</label>
                <input type="text" id="full-name" name="full-name" placeholder="John Doe">
            </div>

            <div>
                <label for="email">Email Address:</label>
                <input type="email" id="email" name="email" placeholder="example@domain.com">
            </div>
        </fieldset>
        <hr>
        <fieldset id="product-info">
            <div>
                <label for="order-no">Order No:</label>
                <input type="text" id="order-no" name="order-no" placeholder="2024######">
            </div>
            <div>
                <label for="product-code">Product Code:</label>
                <input type="text" id="product-code" name="product-code" placeholder="XX##-X###-XX#">
            </div>
            <div>
                <label for="quantity">Quantity:</label>
                <input type="number" id="quantity" name="quantity" min="1">
            </div>
        </fieldset>

        <fieldset id="complaints-group">
            <legend>Complaint Reason:</legend>
            <div>
                <input type="checkbox" id="damaged-product" name="complaint" value="damaged-product">
                <label for="damaged-product">Damaged Product</label>
            </div>

            <div>
                <input type="checkbox" id="nonconforming-product" name="complaint" value="nonconforming-product">
                <label for="nonconforming-product">Nonconforming Product</label>
            </div>

            <div>
                <input type="checkbox" id="delayed-dispatch" name="complaint" value="delayed-dispatch">
                <label for="delayed-dispatch">Delayed Dispatch</label>
            </div>

            <div>
                <input type="checkbox" id="other-complaint" name="complaint" value="other">
                <label for="other-complaint">Other</label>
            </div>
        </fieldset>

        <fieldset id="complaint-description-container">
            <legend>Description of Complaint Reason</legend>
            <textarea placeholder="Describe the reason of your complaint in at least 20 characters"
                name="complaint-textarea" id="complaint-description"></textarea>
        </fieldset>

        <fieldset id="solutions-group">
            <legend>Desired Solution</legend>
            <input type="radio" name="solutions" id="refund" value="refund">
            <label for="refund">Refund</label>

            <input type="radio" name="solutions" id="exchange" value="exchange">
            <label for="exchange">Exchange</label>

            <input type="radio" name="solutions" id="other-solution" value="other">
            <label for="other-solution">Other</label>
        </fieldset>

        <fieldset id="solution-description-container">
            <legend>Description of Desired Solution</legend>
            <textarea placeholder="Describe the desired solution to your issue in at least 20 characters"
                name="solution-textarea" id="solution-description"></textarea>
        </fieldset>
        <div id="btn-container">
            <button type="submit" id="submit-btn">Submit</button>
            <span id="message-box" aria-live="polite"></span>
        </div>

    </form>

    <script src="script.js"></script>
</body>

</html>
/* file: styles.css */
* {
    box-sizing: border-box;
}

h1 {
    text-align: center;
}

#form {
    max-width: 70%;
    margin: auto;
    border-radius: 10px;
    box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
    padding: 10px;
}

input {
    border-color: rgb(118, 118, 118);
}

#personal-info input, #product-info input {
    width: 100%;
    margin-bottom: 10px;
}


fieldset {
    margin-bottom: 10px;
    border-radius: 5px;
    border-color: rgb(118, 118, 118);
}

textarea {
    width: 100%;
    border-color: rgb(118, 118, 118);
}

#btn-container {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

#submit-btn, #clear-btn {
    margin: 10px 15px 0;
}
const complaintForm = document.getElementById("form");
const personInfo = document.getElementById("personal-info");
const productInfo = document.getElementById("product-info");
const reasonsCheckbox = document.getElementById("complaints-group");
const complaintDescription = document.getElementById("complaint-description");
const solutionRadioBtn = document.getElementById("solutions-group");
const solutionDescription = document.getElementById("solution-description");

function validateForm() {
  const formData = {};

  // Full name
  const nameInput = personInfo.querySelector("#full-name");
  formData["full-name"] = nameInput.value.trim() !== "";

  // Email
  const emailInput = personInfo.querySelector("#email");
  formData.email = emailInput.checkValidity();

  // Order number
  const orderNumber = productInfo.querySelector("#order-no");
  formData["order-no"] =
    orderNumber.value.length === 10 && orderNumber.value.startsWith("2024");

  // Product code
  const productCode = productInfo.querySelector("#product-code");
  const regex = /^[A-Za-z]{2}\d{2}-[A-Za-z]\d{3}-[A-Za-z]{2}\d$/;
  formData["product-code"] = regex.test(productCode.value);

  // Quantity
  const quantity = productInfo.querySelector("#quantity");
  formData.quantity = Number.isInteger(+quantity.value) && +quantity.value > 0;

  // Complaints
  const complaintsOptions = reasonsCheckbox.querySelectorAll('[name="complaint"]');
  const hasChecked = !!reasonsCheckbox.querySelector('[name="complaint"]:checked');
  formData["complaints-group"] = hasChecked;

  // Complaint description (if "other" checked)
 const otherCheckbox = Array.from(complaintsOptions).find(opt => opt.value === "other");
formData["complaint-description"] =
  !otherCheckbox.checked || complaintDescription.value.trim().length >= 20;

  // Solutions group
  const hasSolution = !!solutionRadioBtn.querySelector('[name="solutions"]:checked');
  formData["solutions-group"] = hasSolution;

  // Solution description (if "other" selected)
  const otherSolution = solutionRadioBtn.querySelector('[value="other"]');
formData["solution-description"] =
  !otherSolution.checked || solutionDescription.value.trim().length >= 20;

  return formData;
}

function isValid(formData) {
  const values = Object.values(formData);
 if (values.length > 0 && values.every(v => v === true)) {
    return true;
  } else {
    return false;
  }
}

complaintForm.addEventListener("change", (e) => {
  const field = e.target;
  const formData = validateForm();
  const id = field.id;

  // Email
  if (field.id === "email") {
  const isValidEmail = field.checkValidity() && field.value.trim() !== "";
  field.style.borderColor = isValidEmail ? "green" : "red";
  return;
}

  // Checkboxes
  if (field.name === "complaint") {
    const hasChecked = !!reasonsCheckbox.querySelector('[name="complaint"]:checked');
    reasonsCheckbox.style.borderColor = hasChecked ? "green" : "red";
    return;
  }

  // Complaint description
  if (field.id === "complaint-description") {
    const otherCheckbox = reasonsCheckbox.querySelector('[value="other"]');
    const valid = !otherCheckbox.checked || field.value.trim().length >= 20;
    field.style.borderColor = valid ? "green" : "red";
    return;
  }

  // Radio buttons
  if (field.name === "solutions") {
    const hasChecked = !!solutionRadioBtn.querySelector('[name="solutions"]:checked');
    solutionRadioBtn.style.borderColor = hasChecked ? "green" : "red";
    return;
  }

  // Solution description
  if (field.id === "solution-description") {
    const otherSolution = solutionRadioBtn.querySelector('[value="other"]');
    const valid = !otherSolution.checked || field.value.trim().length >= 20;
    field.style.borderColor = valid ? "green" : "red";
    return;
  }

  // Все остальные поля (order-no, full-name, product-code, quantity)
  if (id in formData) {
    field.style.borderColor = formData[id] ? "green" : "red";
  }
});


complaintForm.addEventListener("submit", (e) => {
  e.preventDefault();

  const formData = validateForm();
  const formIsValid = isValid(formData);

  if (!formIsValid) {
    for (const [key, value] of Object.entries(formData)) {
      if (!value) {
        const invalidField =
          document.getElementById(key) ||
          document.querySelector(`#${key}-container`) ||
          document.querySelector(`#${key}-group`);
        if (invalidField) invalidField.style.borderColor = "red";
      }
    }
  } else {
    console.log("✅ Форма успешно прошла проверку!");
  }
});
/* file: script.js */

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36

Challenge Information:

Build a Customer Complaint Form - Build a Customer Complaint Form

https://www.freecodecamp.org/learn/full-stack-developer/lab-customer-complaint-form/build-a-customer-complaint-form

Please test around your form to see how it behaves in the preview. For example, I entered just the name and the quantity. When I submitted the form, the email input element was not bordered in red like the other elements left blank.

thank you. I’ve tested the form and looked through the code and found the missing part breaking the valisdation. Now it works as expacted.