Build a Customer Complaint Form

Problem

Alright so I’ve checked a few forum posts and can’t find a clear solution to this problem. The code executes properly, everything looks fine in the preview, but it doesn’t pass in the tests. I suspect it’s because of the order of some lines of code, but I don’t know what exactly is wrong because the logic seems sound to me and it looks fine.

Failed tests: 13, 16, 17, 19, 21, 24, 25, 27, 30

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>

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;
}

JavaScript

// fetching variables
const form = document.getElementById("form");
const fullName = document.getElementById("full-name");
const email = document.getElementById("email");
const orderNo = document.getElementById("order-no");
const productCode = document.getElementById("product-code");
const quantity = document.getElementById("quantity");
const complaintsGroup = document.getElementById("complaints-group");
const complaintsOptions = Array.from(document.querySelectorAll("input[name='complaint']"));
const complaintDescription = document.getElementById("complaint-description");
const solutionsGroup = document.getElementById("solutions-group");
const solutionsOptions = Array.from(document.querySelectorAll("input[name='solutions']"));
const solutionDescription = document.getElementById("solution-description");
let isOtherComplaint = false;
let isOtherSolution = false;

// functions
function validateForm() {
  const isFullName = fullName.value !== '';
  const isEmail = /.+@.+\.com/i.test(email.value);
  const isOrderNo = /2024\d{6}/.test(orderNo.value);
  const isProdCode = /\w{2}\d{2}-\w\d{3}-\w{2}\d/.test(productCode.value);
  const isQuantity = quantity.value > 0;
  const isComplaintsGroup = complaintsOptions.some((c) => c.hasAttribute("checked"));
  const isComplaintDescription = isOtherComplaint && /.{20,}/.test(complaintDescription.value);
  const isSolutionsGroup = solutionsOptions.some((s) => s.hasAttribute("checked"));
  const isSolutionDescription = isOtherSolution && /.{20,}/.test(solutionDescription.value);
  
  const validObj = {
    "full-name": isFullName,
    "email": isEmail,
    "order-no": isOrderNo,
    "product-code": isProdCode,
    "quantity": isQuantity,
    "complaints-group": isComplaintsGroup,
    "complaint-description": isComplaintDescription,
    "solutions-group": isSolutionsGroup,
    "solution-description": isSolutionDescription
  }

  // const validObj = {
  //   "full-name": true,
  //   "email": true,
  //   "order-no": true,
  //   "product-code": false,
  //   "quantity": true,
  //   "complaints-group": true,
  //   "complaint-description": true,
  //   "solutions-group": true,
  //   "solution-description": true
  // }

  //console.log(validObj, "function");
  
  return validObj;
}

function isValid(list) {
  return Object.values(list).every((item) => item);
}

// all event listeners
form.addEventListener('submit', () => {
  isValid(validateForm());
});
fullName.addEventListener("change", (e) => {
  e.target.style.borderColor = validateForm()['full-name'] ? "green" : "red";
});

email.addEventListener("change", (e) => {
  e.target.style.borderColor = validateForm()['email'] ? "green" : "red";
});

orderNo.addEventListener("change", (e) => {
  e.target.style.borderColor = validateForm()['order-no'] ? "green" : "red";
});

productCode.addEventListener("change", (e) => {
  e.target.style.borderColor = validateForm()['product-code'] ? "green" : "red";
});

quantity.addEventListener("change", (e) => {
  e.target.style.borderColor = validateForm()['quantity'] ? "green" : "red";
});

complaintDescription.addEventListener("input", (e) => {
  e.target.style.borderColor = validateForm()['complaint-description'] ? "green" : "red";
  console.log(validateForm()['complaint-description']);
});

solutionDescription.addEventListener("input", (e) => {
  e.target.style.borderColor = validateForm()['solution-description'] ? "green" : "red";
});

for (const option of complaintsOptions) {
  option.addEventListener('change', (e) => { 
    e.target.toggleAttribute("checked");

    complaintsOptions[complaintsOptions.length - 1].hasAttribute("checked") ? isOtherComplaint = true : isOtherComplaint = false;

    complaintsGroup.style.borderColor = validateForm()['complaints-group'] ? "green" : "red";
  });
}

for (const option of solutionsOptions) {
  option.addEventListener('change', (e) => {
    e.target.toggleAttribute("checked");

    e.target.value === "other" ? isOtherSolution = true : isOtherSolution = false;

    solutionsGroup.style.borderColor = validateForm()['solutions-group'] ? "green" : "red";
  });
}

Please share a link to the challenge

If you have a question about a specific challenge as it relates to your written code for that challenge and need some help, click the Get Help > Ask for Help button located on the challenge.

The Ask for Help button will create a new topic with all code you have written and include a link to the challenge also. You will still be able to ask any questions in the post before submitting it to the forum.

Thank you.

Sorry,

I resolved this and passed the lab using chatgpt to help. The logic I was using to set const isComplaintDescription and const isSolutionDescription was incorrect and always returning false even when “Other” was not checked in either.

Now with

const isComplaintDescription = !otherComplaint.checked || /.{20,}/.test(complaintDescription.value);
const isSolutionDescription = !otherSolution.checked || /.{20,}/.test(solutionDescription.value);

It passes for edge cases when “other” is not checked and the description textareas are empty or filled with stuff.

I also replaced all .hasAttribute("checked"); with .checked because checkboxes and radios are validated using .checked instead of .hasAttribute(). Apparently it was the difference of using attributes rather than DOM properties, which I can assume take precedence when it comes to form validation.