Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/fonts/Roboto/Roboto-Regular.ttf
Binary file not shown.
142 changes: 134 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,136 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Contact Us</title>
<link rel="stylesheet" href="./styles/styles.css" />
</head>
<body>
<header>
<h1>Contact us</h1>
</header>
<main>
<form class="form">
<fieldset class="inputContainer name">
<legend>Name</legend>
<input type="text" name="Name" placeholder="Name" />
<label class="invalidText">Input character range is (1 - 50)</label>
</fieldset>
<fieldset class="inputContainer lastname">
<legend>Last Name</legend>
<input type="text" name="Last Name" placeholder="Last Name" />
<label class="invalidText">Input character range is (1 - 50)</label>
</fieldset>
<fieldset class="inputContainer email">
<legend>Email</legend>
<input type="email" name="Email" placeholder="Email" />
<label class="invalidText">Enter a valid email address</label>
</fieldset>
<fieldset class="inputContainer tel">
<legend>Tel</legend>
<input type="tel" name="Tel" placeholder="Tel" />
<label class="invalidText">Enter a valid telephone number</label>
</fieldset>
<fieldset class="inputContainer">
<legend>Purpose of contact</legend>
<select id="purpose" class="dropdown" name="Purpose of contact">
<option value="" hidden>Select an option</option>
<option value="General-inquiry">General Inquiry</option>
<option value="Product-support">Product Support</option>
<option value="Sales-inquiry">Sales Inquiry</option>
<option value="Media-press-inquiry">Media/Press Inquiry</option>
<option value="Feedback-suggestions">Feedback/Suggestions</option>
<option value="Other">Other</option>
</select>
<label class="invalidText">Select an option</label>
</fieldset>
<fieldset class="inputContainer">
<legend>Contact me via</legend>
<label class="radioLabel telEmailLabel"
>Email
<input type="radio" name="Contact via" id="email" value="Email"
/></label>
<label class="radioLabel telEmailLabel"
>Tel <input type="radio" name="Contact via" id="tel" value="Tel"
/></label>
<label class="invalidText">Select an option</label>
<br />
<label class="hidden" id="emailSpecificationLabel1"
>Use entered email
<input
type="radio"
name="Email specification"
value="Use entered email"
/></label>
<label class="hidden" id="emailSpecificationLabel2"
>Use another email
<input
type="radio"
name="Email specification"
value="Use another email"
/></label>
<label class="invalidText">Select an option</label>
</fieldset>
<fieldset class="inputContainer message">
<legend>Message</legend>
<label
><input
type="checkbox"
name="checkboxMessage"
class="notRequired"
id="message"
/>Leave a Message</label
>
<input
type="text"
name="MessageText"
class="hidden"
placeholder="...Write something"
/>
<label class="invalidText">Input character range is (1 - 50)</label>
</fieldset>
<label class="termsLabel"
><input type="checkbox" name="checkboxTerms" id="terms" />
Accept terms
<label class="invalidText">Check this box to proceed</label></label
>
<button type="submit" class="registerButton">Submit</button>
</form>
</main>

<dialog class="modal">
<h3 class="modalTitle">Terms and policies</h3>
<p class="modalText">
1. ACCEPTANCE THE USE OF LOREM IPSUM TERMS AND CONDITIONS Your access to
and use of Lorem Ipsum (the app) is subject exclusively to these Terms
and Conditions. You will not use the app for any purpose that is
unlawful or prohibited by these Terms and Conditions. By using the app
you are fully accepting the terms, conditions and disclaimers contained
in this notice. If you do not accept these Terms and Conditions you must
immediately stop using the app.<br /><br />
2. CREDIT CARD DETAILS All Lorem Ipsum purchases are managed by the
individual App Stores (Apple, Google Windows) and Lorem Ipsum will never
store your credit card information or make it available to any third
parties. Any purchasing information provided will be provided directly
from you to the respective App Store and you will be subject to their
credit card policies.<br /><br />
3. LEGAL ADVICE The contents of Lorem Ipsum app do not constitute advice
and should not be relied upon in making or refraining from making, any
decision. All material contained on Lorem Ipsum is provided without any
or warranty of any kind. You use the material on Lorem Ipsum at your own
discretion <br /><br />
4. CHANGE OF USE Lorem Ipsum reserves the right to:<br />
4.1 change or remove (temporarily or permanently) the app or any part of
it without notice and you confirm that Lorem Ipsum shall not be liable
to you for any such change or removal and.<br />
4.2 change these Terms and Conditions at any time, and your continued
use of the app following any changes shall be deemed to be your
acceptance of such change.
</p>
<button class="closeModalButton">Close</button>
<button class="continueModalButton" disabled>Continue</button>
</dialog>
<script src="./js/script.js"></script>
</body>
</html>
184 changes: 184 additions & 0 deletions js/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
const form = document.querySelector("form");
const checkboxMessage = document.querySelector("input[name='checkboxMessage']");
const checkboxTerms = document.querySelector("input[name='checkboxTerms']");
const radioButtonsContactVia = Array.from(
document.querySelectorAll("input[name='Contact via']")
);
const dropdown = document.querySelector("select");
const modal = document.querySelector(".modal");
const modalText = document.querySelector(".modalText");
const modalCloseButton = document.querySelector(".closeModalButton");
const modalContinueButton = document.querySelector(".continueModalButton");

function initializeInputs() {
// refresh all inputs on reload (Firefox) and add event listeners
const textInputs = document.querySelectorAll(
'select,input:not([type="checkbox"],[type="radio"],.notRequired)'
);
const buttons = document.querySelectorAll(
'input:is([type="checkbox"],[type="radio"]):not(.notRequired)'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified the selectors for text inputs and buttons to exclude the unnecessary :is and :not pseudo-classes.

);

textInputs.forEach((textInput) => {
textInput.value = "";
textInput.addEventListener("input", (e) => validateInput(e.target));
});
dropdown.addEventListener("change", () =>
dropdown.classList.remove("invalid")
);
buttons.forEach((button) => {
button.checked = false;
button.addEventListener("click", (e) => validateInput(e.target));
});
checkboxMessage.checked = false;
}

window.addEventListener("load", () => initializeInputs());

function handleRadioButtonTelEmailClick(clickedRadioButtonTelEmail) {
const radioButtonsEmailSpecification = Array.from(
document.querySelectorAll("input[name='Email specification']")
);

radioButtonsEmailSpecification.forEach((radioButtonEmailSpecification) => {
if (clickedRadioButtonTelEmail.id === "email") {
radioButtonEmailSpecification.parentElement.classList.remove("hidden");
} else {
radioButtonEmailSpecification.parentElement.classList.add("hidden");
radioButtonEmailSpecification.parentElement.classList.remove("invalid");
radioButtonEmailSpecification.checked = false;
}
});
}

radioButtonsContactVia.forEach((radioButtonContactVia) => {
radioButtonContactVia.addEventListener("click", () =>
handleRadioButtonTelEmailClick(radioButtonContactVia)
);
});

checkboxMessage.addEventListener("click", () => {
const messageTextInput = document.querySelector("input[name='MessageText']");
if (messageTextInput.classList.contains("hidden")) {
messageTextInput.classList.remove("hidden");
} else {
messageTextInput.value = "";
messageTextInput.classList.add("hidden");
messageTextInput.classList.remove("invalid");
}
});

function validateButton(buttonName) {
const buttons = Array.from(
document.querySelectorAll(`input[name='${buttonName}']`)
);
let isAnyButtonClicked = false;

buttons.forEach((button) => {
button.parentElement.classList.remove("invalid");
if (button.checked) {
isAnyButtonClicked = true;
button.classList.remove("notRequired");
} else {
button.classList.add("notRequired");
}
});
if (!isAnyButtonClicked) {
//none of the buttons are clicked
buttons.forEach((button) => {
button.parentElement.classList.add("invalid");
button.classList.remove("notRequired");
});
}

return isAnyButtonClicked;
}

function validateInput(input) {
let isInputValid = false;

switch (input.type) {
case "text":
isInputValid =
input.value.trim().length > 0 && input.value.trim().length <= 50;
break;
case "email":
const EmailRegEx = /^[\w-.]+@([\w-]+\.)+[\w-]{2,}$/;
isInputValid = EmailRegEx.test(input.value);
break;
case "tel":
const TelRegEx = /^\d{9,10}$/;
input.value = input.value.replace(/\D/g, "");
isInputValid = TelRegEx.test(input.value);
break;
case "select-one":
isInputValid = input.value !== "";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used strict equality (===) instead of loose equality (==) for comparison to ensure consistent behavior.

break;
case "radio":
isInputValid = validateButton(input.name);
break;
default:
return true;
}

if (isInputValid) input.classList.remove("invalid");
else input.classList.add("invalid");
return isInputValid;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor to:
if (isInputValid) {
input.classList.remove("invalid");
} else {
input.classList.add("invalid");
}

return isInputValid;

}

function validateForm(formEvent) {
formEvent.preventDefault();

const inputs = Array.from(
document.querySelectorAll(
"select,input:not(.hidden,.hidden *,.notRequired,[type='checkbox'])"
)
);
let isFormValid = true;

inputs.forEach((input) => {
if (!validateInput(input)) isFormValid = false;
});

if (!checkboxTerms.checked) {
isFormValid = false;
checkboxTerms.parentElement.classList.add("invalid");
}

if (!isFormValid) return;

const inputsText = inputs
.filter((input) => input.value !== "on")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used strict equality (===) instead of loose equality (==) for comparison to ensure consistent behavior.

.map((filteredInput) => `${filteredInput.name}: ${filteredInput.value}`)
.join("\n");

alert(inputsText);
}

form.addEventListener("submit", (e) => validateForm(e));

checkboxTerms.addEventListener("click", (e) => {
if (!modalContinueButton.disabled) modalContinueButton.disabled = true;

if (checkboxTerms.checked) {
e.preventDefault();
modal.showModal();
} else checkboxTerms.checked = false;
});

modalCloseButton.addEventListener("click", () => {
modalText.scrollTop = 0;
modal.close();
});
modalContinueButton.addEventListener("click", () => {
checkboxTerms.checked = true;
checkboxTerms.parentElement.classList.remove("invalid");
modalText.scrollTop = 0;
modal.close();
});

modalText.addEventListener("scroll", (e) => {
const { scrollHeight, scrollTop, clientHeight } = e.target;
if (Math.abs(scrollHeight - clientHeight - scrollTop) < 1)
modalContinueButton.disabled = false;
});
Loading