Build a Customer Complaint Form - Build a Customer Complaint Form

Tell us what’s happening:

The testing engine refuses to accept my solution despite it being correct in my opinion, at least.

Your code so far

<!-- file: index.html -->

/* file: script.js */
const fullName = document.querySelector("#full-name");
const emailAddress = document.querySelector("#email");
const orderNo = document.querySelector("#order-no");
const productCode = document.querySelector("#product-code");
const quantity = document.querySelector("#quantity");
const complaintsGroup = document.querySelectorAll("#complaints-group input[type='checkbox']");
const complaintDesc = document.querySelector("#complaint-description");
const solutionsGroup = document.querySelectorAll("#solutions-group input[type='radio']");
const solutionDesc = document.querySelector("#solution-description");
const submitBtn = document.querySelector("#submit-btn");
const message = document.querySelector("#message-box");

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/i;
const orderRegex = /^2024\d{6}$/;
const productRegex = /^[a-zA-Z]{2}\d{2}-[a-zA-Z]{1}\d{3}-[a-zA-Z]{2}\d{1}$/;
let storeObj = {};

const validateForm = () => {
  let hasName = false;
  let hasEmail = false;
  let hasOrderNo = false;
  let hasProductCode = false;
  let hasQuantity = false;
  let isComplaintsGroupChecked = false;
  let hasComplaintDesc = false;
  let isSolutionsGroupSelected = false;
  let hasSolutionDesc = false;
  let hasComplaintDescLen = false;
  let hasSolutionDescLen = false;
  let complaintValue = complaintDesc.value;
  let solutionValue = solutionDesc.value;

  if (fullName.value.length > 0) {
    hasName = true;
  }
  if (emailAddress.value.match(emailRegex)) {
    hasEmail = true;
  }
  if (orderNo.value.match(orderRegex)) {
    hasOrderNo = true;
  }
  if (productCode.value.match(productRegex)) {
    hasProductCode = true;
  }
  if (Number(quantity.value) > 0) {
    hasQuantity = true;
  }
  complaintsGroup.forEach(complaint => {
    if (complaint.checked && complaint.value === "other") {
      isComplaintsGroupChecked = true;
      hasComplaintDesc = true;
      if (complaintValue.length >= 20) {
        hasComplaintDescLen = true;
      }
    } else if (complaint.checked) {
      isComplaintsGroupChecked = true;
    }
  });
  solutionsGroup.forEach(solution => {
    if (solution.checked && solution.value === "other") {
      isSolutionsGroupSelected = true;
      hasSolutionDesc = true;
      if (solutionValue.length >= 20) {
        hasSolutionDescLen = true;
      }
    }
    if (solution.checked) {
      isSolutionsGroupSelected = true;
    }
  });

  storeObj = {
    "complaint-desc-len": hasComplaintDescLen,
    "solution-desc-len": hasSolutionDescLen
  };

  return {
    "full-name": hasName,
    email: hasEmail,
    "order-no": hasOrderNo,
    "product-code": hasProductCode,
    quantity: hasQuantity,
    "complaints-group": isComplaintsGroupChecked,
    "solutions-group": isSolutionsGroupSelected,
    "complaint-description": hasComplaintDesc,
    "solution-description": hasSolutionDesc
  };
}

const isValid = obj => {
  let arr = [];

  let isEveryValTrue = false;
  let hasComplaintDesc = obj["complaint-description"];
  let hasSolutionDesc = obj["solution-description"];
  let hasComplaintDescLen = storeObj["complaint-desc-len"];
  let hasSolutionDescLen = storeObj["solution-desc-len"];
  let counter = 0;

  for (const value in obj) {
    counter++;
    if (counter < 8) {
      arr.push(obj[value]);
    }
  }
  isEveryValTrue = arr.every(val => val);
  console.log(arr);
  
  if (hasComplaintDesc && isEveryValTrue) {
    if (hasComplaintDescLen) {
      return true;
    } else {
      return false;
    }
  }

  if (hasSolutionDesc && isEveryValTrue) {
    if (hasSolutionDescLen)  {
      return true;
    } else {
      return false;
    }
  }
  
  if (isEveryValTrue && !(hasComplaintDesc || hasSolutionDesc)) {
    return true;
  } else {
    return false;
  }
}


const complaintsGroupFieldset = document.querySelector("#complaints-group");
const solutionsGroupFieldset = document.querySelector("#solutions-group");
const complaintDescContainer = document.querySelector("#complaint-description-container");
const solutionDescContainer = document.querySelector("#solution-description-container");

complaintDescContainer.classList.add("hide");
solutionDescContainer.classList.add("hide");

fullName.addEventListener("change", () => {
  let hasName = validateForm()["full-name"];
  
  if (hasName) {
    fullName.style.borderColor = "green";
  } else {
    fullName.style.borderColor = "red";
  }
});
emailAddress.addEventListener("change", () => {
  let hasEmail = validateForm().email;

  if (hasEmail) {
    emailAddress.style.borderColor = "green";
  } else {
    emailAddress.style.borderColor = "red";
  }
});
orderNo.addEventListener("change", () => {
  let hasOrderNo = validateForm()["order-no"];

  if (hasOrderNo) {
    orderNo.style.borderColor = "green";
  } else {
    orderNo.style.borderColor = "red";
  }
});
productCode.addEventListener("change", () => {
  let hasProductCode = validateForm()["product-code"];

  if (hasProductCode) {
    productCode.style.borderColor = "green";
  } else {
    productCode.style.borderColor = "red";
  }
});
quantity.addEventListener("change", () => {
  let hasQuantity = validateForm().quantity;

  if (hasQuantity) {
    quantity.style.borderColor = "green";
  } else {
    quantity.style.borderColor = "red";
  }
});
complaintDesc.addEventListener("change", () => {
  let hasComplaintDescValue = validateForm()["complaint-description"];
  let hasComplaintDescLen = storeObj["complaint-desc-len"];

  if (hasComplaintDescValue && hasComplaintDescLen) {
    complaintDesc.style.borderColor = "green";
  } else {
    complaintDesc.style.borderColor = "red";
  }
});
solutionDesc.addEventListener("change", () => {
  let hasSolutionDescValue = validateForm()["solution-description"];
  let hasSolutionDescLen = storeObj["solution-desc-len"];

  if (hasSolutionDescValue && hasSolutionDescLen) {
    solutionDesc.style.borderColor = "green";
  } else {
    solutionDesc.style.borderColor = "red";
  }
});

complaintsGroup.forEach(complaint => {
  complaint.addEventListener("change", () => {
    let hasComplaintDesc = validateForm()["complaint-description"];
    let isComplaintsGroupChecked = validateForm()["complaints-group"];

    if (isComplaintsGroupChecked && hasComplaintDesc) {
      complaintsGroupFieldset.style.borderColor = "green";
      complaintDescContainer.classList.remove("hide");
    } else if (isComplaintsGroupChecked && !hasComplaintDesc) {
      complaintsGroupFieldset.style.borderColor = "green";
      complaintDescContainer.classList.add("hide");
    } else {
      complaintsGroupFieldset.style.borderColor = "red";
      complaintDescContainer.classList.add("hide");
    }

  });
});
solutionsGroup.forEach(solution => {
  solution.addEventListener("change", () => {
    let hasSolutionDesc = validateForm()["solution-description"];
    let isSolutionsGroupSelected = validateForm()["solutions-group"];

    if (isSolutionsGroupSelected && hasSolutionDesc) {
      solutionsGroupFieldset.style.borderColor = "green";
      solutionDescContainer.classList.remove("hide");
    } else if (isSolutionsGroupSelected && !hasSolutionDesc) {
      solutionsGroupFieldset.style.borderColor = "green";
      solutionDescContainer.classList.add("hide");
    } else {
      solutionsGroupFieldset.style.borderColor = "red";
      solutionDescContainer.classList.add("hide");
    }

  });
});

submitBtn.addEventListener("click", () => {
  if (isValid(validateForm())) {
    message.textContent = "Form was submitted";
  } else {
    message.textContent = "Please, fill out the required fields correctly before submitting.";
  }
  return isValid(validateForm());
});
/* file: styles.css */

Your browser information:

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

Challenge Information:

Build a Customer Complaint Form - Build a Customer Complaint Form

it seems the tests are not written to deal with the situation you have created: the tests are creating an event on the fieldset, and not on the checkboxes

would you mind opening an issue about this?

it will take some time for this to be changed, meanwhile you can move the eventlistener on the fieldset element

1 Like

There appears to be an issue with logic that I’m not completely sure about how to solve:

const fullName = document.querySelector("#full-name");
const emailAddress = document.querySelector("#email");
const orderNo = document.querySelector("#order-no");
const productCode = document.querySelector("#product-code");
const quantity = document.querySelector("#quantity");
const complaintsGroup = document.querySelectorAll("#complaints-group input[type='checkbox']");
const complaintDesc = document.querySelector("#complaint-description");
const solutionsGroup = document.querySelectorAll("#solutions-group input[type='radio']");
const solutionDesc = document.querySelector("#solution-description");
const submitBtn = document.querySelector("#submit-btn");
const message = document.querySelector("#message-box");

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/i;
const orderRegex = /^2024\d{6}$/;
const productRegex = /^[a-zA-Z]{2}\d{2}-[a-zA-Z]{1}\d{3}-[a-zA-Z]{2}\d{1}$/;

const validateForm = () => {
  let hasName = false;
  let hasEmail = false;
  let hasOrderNo = false;
  let hasProductCode = false;
  let hasQuantity = false;
  let isComplaintsGroupChecked = false;
  let hasComplaintDesc = false;
  let isSolutionsGroupSelected = false;
  let hasSolutionDesc = false;
  let complaintValue = complaintDesc.value;
  let solutionValue = solutionDesc.value;

  if (fullName.value.length > 0) {
    hasName = true;
  }
  if (emailAddress.value.match(emailRegex)) {
    hasEmail = true;
  }
  if (orderNo.value.match(orderRegex)) {
    hasOrderNo = true;
  }
  if (productCode.value.match(productRegex)) {
    hasProductCode = true;
  }
  if (Number(quantity.value) > 0) {
    hasQuantity = true;
  }
  complaintsGroup.forEach(complaint => {
    if (complaint.checked && complaint.value === "other" && complaintValue.length >= 20) {
      isComplaintsGroupChecked = true;
      hasComplaintDesc = true;
    } else if (complaint.checked) {
      isComplaintsGroupChecked = true;
    }
  });
  solutionsGroup.forEach(solution => {
    if (solution.checked && solution.value === "other" && solutionValue.length >= 20) {
      isSolutionsGroupSelected = true;
      hasSolutionDesc = true;
    }
    if (solution.checked) {
      isSolutionsGroupSelected = true;
    }
  });

  return {
    "full-name": hasName,
    email: hasEmail,
    "order-no": hasOrderNo,
    "product-code": hasProductCode,
    quantity: hasQuantity,
    "complaints-group": isComplaintsGroupChecked,
    "solutions-group": isSolutionsGroupSelected,
    "complaint-description": hasComplaintDesc,
    "solution-description": hasSolutionDesc
  };
}

const isValid = obj => {
  if ((obj["complaint-description"] || obj["solution-description"]) && obj["full-name"] && obj["email"] && obj["order-no"] && obj["product-code"] && obj["quantity"] && obj["complaints-group"] && obj["solutions-group"]) {
    return true;
  } else if (!(obj["complaint-description"] && obj["solution-description"]) && obj["full-name"] && obj["email"] && obj["order-no"] && obj["product-code"] && obj["quantity"] && obj["complaints-group"] && obj["solutions-group"]) {
    return true;
  } else {
    return false;
  }
}


const complaintsGroupFieldset = document.querySelector("#complaints-group");
const solutionsGroupFieldset = document.querySelector("#solutions-group");
const complaintDescContainer = document.querySelector("#complaint-description-container");
const solutionDescContainer = document.querySelector("#solution-description-container");

fullName.addEventListener("change", () => {
  let hasName = validateForm()["full-name"];
  
  if (hasName) {
    fullName.style.borderColor = "green";
  } else {
    fullName.style.borderColor = "red";
  }
});
emailAddress.addEventListener("change", () => {
  let hasEmail = validateForm().email;

  if (hasEmail) {
    emailAddress.style.borderColor = "green";
  } else {
    emailAddress.style.borderColor = "red";
  }
});
orderNo.addEventListener("change", () => {
  let hasOrderNo = validateForm()["order-no"];

  if (hasOrderNo) {
    orderNo.style.borderColor = "green";
  } else {
    orderNo.style.borderColor = "red";
  }
});
productCode.addEventListener("change", () => {
  let hasProductCode = validateForm()["product-code"];

  if (hasProductCode) {
    productCode.style.borderColor = "green";
  } else {
    productCode.style.borderColor = "red";
  }
});
quantity.addEventListener("change", () => {
  let hasQuantity = validateForm().quantity;

  if (hasQuantity) {
    quantity.style.borderColor = "green";
  } else {
    quantity.style.borderColor = "red";
  }
});
complaintDesc.addEventListener("change", () => {
  let hasComplaintDescValue = validateForm()["complaint-description"];

  if (hasComplaintDescValue) {
    complaintDesc.style.borderColor = "green";
  } else {
    complaintDesc.style.borderColor = "red";
  }
});
solutionDesc.addEventListener("change", () => {
  let hasSolutionDescValue = validateForm()["solution-description"];

  if (hasSolutionDescValue) {
    solutionDesc.style.borderColor = "green";
  } else {
    solutionDesc.style.borderColor = "red";
  }
});

complaintsGroupFieldset.addEventListener("change", () => {
    let hasComplaintDesc = validateForm()["complaint-description"];
    let isComplaintsGroupChecked = validateForm()["complaints-group"];

    if (isComplaintsGroupChecked && hasComplaintDesc) {
      complaintsGroupFieldset.style.borderColor = "green";
    } else if (isComplaintsGroupChecked && !hasComplaintDesc) {
      complaintsGroupFieldset.style.borderColor = "green";
    } else {
      complaintsGroupFieldset.style.borderColor = "red";
    }

});
solutionsGroupFieldset.addEventListener("change", () => {
    let hasSolutionDesc = validateForm()["solution-description"];
    let isSolutionsGroupSelected = validateForm()["solutions-group"];

    if (isSolutionsGroupSelected && hasSolutionDesc) {
      solutionsGroupFieldset.style.borderColor = "green";
      //solutionDescContainer.classList.remove("hide");
    } else if (isSolutionsGroupSelected && !hasSolutionDesc) {
      solutionsGroupFieldset.style.borderColor = "green";
      //solutionDescContainer.classList.add("hide");
    } else {
      solutionsGroupFieldset.style.borderColor = "red";
      //solutionDescContainer.classList.add("hide");
    }
});

submitBtn.addEventListener("submit", () => {
  console.log(isValid(validateForm()));

  if (isValid(validateForm())) {
    message.textContent = "Form was submitted";
  } else {
    message.textContent = "Please, fill out the required fields correctly before submitting.";
  }
  return isValid(validateForm());
});

what logic? can you give more details?

By logic I mean these parts or functions with main logic:

const validateForm = () => {
  let hasName = false;
  let hasEmail = false;
  let hasOrderNo = false;
  let hasProductCode = false;
  let hasQuantity = false;
  let isComplaintsGroupChecked = false;
  let hasComplaintDesc = false;
  let isSolutionsGroupSelected = false;
  let hasSolutionDesc = false;
  let complaintValue = complaintDesc.value;
  let solutionValue = solutionDesc.value;

  if (fullName.value.length > 0) {
    hasName = true;
  }
  if (emailAddress.value.match(emailRegex)) {
    hasEmail = true;
  }
  if (orderNo.value.match(orderRegex)) {
    hasOrderNo = true;
  }
  if (productCode.value.match(productRegex)) {
    hasProductCode = true;
  }
  if (Number(quantity.value) > 0) {
    hasQuantity = true;
  }
  complaintsGroup.forEach(complaint => {
    if (complaint.checked && complaint.value === "other" && complaintValue.length >= 20) {
      isComplaintsGroupChecked = true;
      hasComplaintDesc = true;
    } else if (complaint.checked) {
      isComplaintsGroupChecked = true;
    }
  });
  solutionsGroup.forEach(solution => {
    if (solution.checked && solution.value === "other" && solutionValue.length >= 20) {
      isSolutionsGroupSelected = true;
      hasSolutionDesc = true;
    }
    if (solution.checked) {
      isSolutionsGroupSelected = true;
    }
  });

  return {
    "full-name": hasName,
    email: hasEmail,
    "order-no": hasOrderNo,
    "product-code": hasProductCode,
    quantity: hasQuantity,
    "complaints-group": isComplaintsGroupChecked,
    "solutions-group": isSolutionsGroupSelected,
    "complaint-description": hasComplaintDesc,
    "solution-description": hasSolutionDesc
  };
}

const isValid = obj => {
  if ((obj["complaint-description"] || obj["solution-description"]) && obj["full-name"] && obj["email"] && obj["order-no"] && obj["product-code"] && obj["quantity"] && obj["complaints-group"] && obj["solutions-group"]) {
    return true;
  } else if (!(obj["complaint-description"] && obj["solution-description"]) && obj["full-name"] && obj["email"] && obj["order-no"] && obj["product-code"] && obj["quantity"] && obj["complaints-group"] && obj["solutions-group"]) {
    return true;
  } else {
    return false;
  }
}

I’m not certain as to what part or parts here could be problematic or whether I should rethink it all altogether.
The errors messages are(They seem to be alternating by changing parts of isValid function logic):

30. Your isValid function should take the validateForm() as its argument and return true when all the form fields have been filled correctly.
31. Your isValid function should take the validateForm() as its argument and return false when not all the form fields have been filled correctly.

I’d try to simplify it. isValid is intended to be rather simple - if everything inside the passed object is true then it should return true, otherwise it should return false. It doesn’t need to know any details like specific object keys, or how they might interact with each other.

Been there, tried that:

const isValid = obj => {
  if (obj["full-name"] && obj["email"] && obj["order-no"] && obj["product-code"] && obj["quantity"] && obj["complaints-group"] && obj["solutions-group"] && obj["complaint-description"] && obj["solution-description"]) {
    return true;
  } else {
    return false;
  }
}

Again, a change in a condition seems to either bring the 30 or 31 test error

This isn’t wrong. What other tests are failing?

Only 30 and 31. Tried asking AI methods for help to no avail since they basically tell me to do the same thing.
Here’s updated code:


const fullName = document.querySelector("#full-name");
const emailAddress = document.querySelector("#email");
const orderNo = document.querySelector("#order-no");
const productCode = document.querySelector("#product-code");
const quantity = document.querySelector("#quantity");
const complaintsGroup = document.querySelectorAll("#complaints-group input[type='checkbox']");
const complaintDesc = document.querySelector("#complaint-description");
const solutionsGroup = document.querySelectorAll("#solutions-group input[type='radio']");
const solutionDesc = document.querySelector("#solution-description");
const formSubmit = document.querySelector("#form");
const message = document.querySelector("#message-box");

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/i;
const orderRegex = /^2024\d{6}$/;
const productRegex = /^[a-zA-Z]{2}\d{2}-[a-zA-Z]{1}\d{3}-[a-zA-Z]{2}\d{1}$/;

const validateForm = () => {
  let hasName = false;
  let hasEmail = false;
  let hasOrderNo = false;
  let hasProductCode = false;
  let hasQuantity = false;
  let isComplaintsGroupChecked = false;
  let hasComplaintDesc = false;
  let isSolutionsGroupSelected = false;
  let hasSolutionDesc = false;
  let complaintValue = complaintDesc.value;
  let solutionValue = solutionDesc.value;

  if (fullName.value.length > 0) {
    hasName = true;
  }
  if (emailAddress.value.match(emailRegex)) {
    hasEmail = true;
  }
  if (orderNo.value.match(orderRegex)) {
    hasOrderNo = true;
  }
  if (productCode.value.match(productRegex)) {
    hasProductCode = true;
  }
  if (Number(quantity.value) > 0) {
    hasQuantity = true;
  }
  complaintsGroup.forEach(complaint => {
    if (complaint.checked && complaint.value === "other" && complaintValue.length >= 20) {
      hasComplaintDesc = true;
    } else if (complaint.checked) {
      isComplaintsGroupChecked = true;
    }
  });
  solutionsGroup.forEach(solution => {
    if (solution.checked && solution.value === "other" && solutionValue.length >= 20) {
      hasSolutionDesc = true;
    } else if (solution.checked) {
      isSolutionsGroupSelected = true;
    }
  });

  return {
    "full-name": hasName,
    email: hasEmail,
    "order-no": hasOrderNo,
    "product-code": hasProductCode,
    quantity: hasQuantity,
    "complaints-group": isComplaintsGroupChecked,
    "complaint-description": hasComplaintDesc,
    "solutions-group": isSolutionsGroupSelected,
    "solution-description": hasSolutionDesc
  };
}

const isValid = obj => {
  if (obj["full-name"] && obj["email"] && obj["order-no"] && obj["product-code"] && obj["quantity"] && obj["complaints-group"] && obj["solutions-group"] && obj["complaint-description"] && obj["solution-description"]) {
    return true;
  } else {
    return false;
  }
}

const complaintsGroupFieldset = document.querySelector("#complaints-group");
const solutionsGroupFieldset = document.querySelector("#solutions-group");
const complaintDescContainer = document.querySelector("#complaint-description-container");
const solutionDescContainer = document.querySelector("#solution-description-container");

//solutionDescContainer.classList.add("hide");
const changeColor = (el, isFirstCondition, isSecondCondition = false) => {
  if (isFirstCondition && isSecondCondition) {
    el.style.borderColor = "green";
  } else if (isFirstCondition && !isSecondCondition) {
    el.style.borderColor = "green";
  } else {
    el.style.borderColor = "red";
  }
}

fullName.addEventListener("change", () => {
  let hasName = validateForm()["full-name"];
  
  changeColor(fullName, hasName);
});
emailAddress.addEventListener("change", () => {
  let hasEmail = validateForm().email;

  changeColor(emailAddress, hasEmail);
});

orderNo.addEventListener("change", () => {
  let hasOrderNo = validateForm()["order-no"];

  changeColor(orderNo, hasOrderNo);
});
productCode.addEventListener("change", () => {
  let hasProductCode = validateForm()["product-code"];

  changeColor(productCode, hasProductCode);
});

quantity.addEventListener("change", () => {
  let hasQuantity = validateForm().quantity;

  changeColor(quantity, hasQuantity);
});

complaintDesc.addEventListener("change", () => {
  let hasComplaintDescValue = validateForm()["complaint-description"];

  changeColor(complaintDesc, hasComplaintDescValue);
});
solutionDesc.addEventListener("change", () => {
  let hasSolutionDescValue = validateForm()["solution-description"];

  changeColor(solutionDesc, hasSolutionDescValue);
});

complaintsGroupFieldset.addEventListener("change", () => {
  let hasComplaintDesc = validateForm()["complaint-description"];
  let isComplaintsGroupChecked = validateForm()["complaints-group"];

  changeColor(complaintsGroupFieldset, isComplaintsGroupChecked, hasComplaintDesc);
});
solutionsGroupFieldset.addEventListener("change", () => {
  let hasSolutionDesc = validateForm()["solution-description"];
  let isSolutionsGroupSelected = validateForm()["solutions-group"];

  changeColor(solutionsGroupFieldset, isSolutionsGroupSelected, hasSolutionDesc);
});

formSubmit.addEventListener("submit", (e) => {
  e.preventDefault();
  console.log(validateForm());

  if (isValid(validateForm())) {
    message.textContent = "Form was submitted";
  } else {
    message.textContent = "Please, fill out the required fields correctly before submitting.";
  }
});

Hmm, I don’t think the solution description or complaint description should validate to false, when relevant Other option is not picked

1 Like

Thank you, that helped!