diff --git a/css/common.css b/css/common.css
index 24e665f0..74eb7e99 100644
--- a/css/common.css
+++ b/css/common.css
@@ -24,6 +24,7 @@
--color-input: #f3f4f6;
--color-white: #ffffff;
--color-text-login: #1f2937;
+ --color-error-red: #f74747;
/* Typography */
--font-primary: "Pretendard-Regular", sans-serif;
@@ -58,3 +59,7 @@ body {
background-color: var(--color-disabled);
}
/* 비활성화시에 속성이랑 클래스 둘다 넣어야 함 */
+
+.display-none {
+ display: none;
+}
diff --git a/css/login-signup-style.css b/css/login-signup-style.css
index b73ef144..c84e4894 100644
--- a/css/login-signup-style.css
+++ b/css/login-signup-style.css
@@ -46,17 +46,31 @@ main {
font-size: 16px;
}
+.form__input.invalid {
+ border: 1px solid var(--color-error-red);
+}
+
+.form__error-msg {
+ position: relative;
+ top: -12px;
+ padding-left: 16px;
+ color: var(--color-error-red);
+ font-weight: 500;
+ font-size: 14px;
+}
+
.input--password {
position: relative;
}
-.btn--visibility-off {
+.btn--visibility {
border: none;
background-color: var(--color-input);
position: absolute;
top: 16px;
right: 24px;
bottom: 16px;
+ padding: 0;
}
.btn--interactions {
diff --git a/faq.html b/faq.html
index e69de29b..93e4fdf5 100644
--- a/faq.html
+++ b/faq.html
@@ -0,0 +1 @@
+
diff --git a/index.html b/index.html
index b3ead464..5d17cbb3 100644
--- a/index.html
+++ b/index.html
@@ -9,7 +9,7 @@
/>
-
+
판다마켓
diff --git a/js/btn-functions.js b/js/btn-functions.js
new file mode 100644
index 00000000..4a031a67
--- /dev/null
+++ b/js/btn-functions.js
@@ -0,0 +1,24 @@
+//모든 input의 유효성 검사를 통과했을 때에만 누를 수 있어야하므로 validate와 작동방식이 달라야함
+export function toggleBtnStatus() {
+ const btn = document.querySelector(".btn--interactions");
+ const errorMessages = document.querySelectorAll(".form__error-msg");
+ const inputs = document.querySelectorAll(".form__input");
+
+ for (const message of errorMessages) {
+ if (message.textContent) {
+ btn.setAttribute("disabled", "");
+ btn.classList.add("btn--disabled");
+ return;
+ }
+ }
+ for (const input of inputs) {
+ if (!input.value) {
+ btn.setAttribute("disabled", "");
+ btn.classList.add("btn--disabled");
+ return;
+ }
+ }
+
+ btn.removeAttribute("disabled");
+ btn.classList.remove("btn--disabled");
+}
diff --git a/js/login-signup.js b/js/login-signup.js
new file mode 100644
index 00000000..42fc036c
--- /dev/null
+++ b/js/login-signup.js
@@ -0,0 +1,60 @@
+import {
+ isEmpty,
+ validateEmail,
+ validatePassword,
+ validatePasswordConfirm,
+ validatePasswordConfirmReverse,
+ validateNickname,
+} from "./validate.js";
+import { toggleBtnStatus } from "./btn-functions.js";
+
+function toggleVisibility(event) {
+ const btn = event.target.parentElement;
+ const passwordInput = btn.previousElementSibling;
+ const iconOff = btn.children[0];
+ const iconOn = btn.children[1];
+
+ if (passwordInput.getAttribute("type") === "password") {
+ passwordInput.setAttribute("type", "text");
+ btn.setAttribute("aria-pressed", "true");
+ } else {
+ passwordInput.setAttribute("type", "password");
+ btn.setAttribute("aria-pressed", "false");
+ }
+ iconOff.classList.toggle("display-none");
+ iconOn.classList.toggle("display-none");
+}
+
+function isSignupPage() {
+ return window.location.pathname.search("signup") === -1 ? false : true;
+}
+
+const form = document.querySelector(".container--form");
+const validateMap = {
+ email: validateEmail,
+ password: validatePassword,
+ "password-confirm": validatePasswordConfirm,
+ nickname: validateNickname,
+};
+
+form.addEventListener("focusout", (event) => {
+ const { id } = event.target;
+
+ if (validateMap[id]) {
+ validateMap[id](event);
+ //비밀번호확인란부터 입력후 비밀번호를 변경할 시 비밀번호 확인 유효성 검사
+ if (id === "password" && isSignupPage()) {
+ const passwordConfirmInput = document.getElementById("password-confirm");
+ const passwordConfirm = passwordConfirmInput.value;
+ if (!isEmpty(passwordConfirm)) {
+ validatePasswordConfirmReverse();
+ }
+ }
+ toggleBtnStatus();
+ }
+});
+form.addEventListener("click", (event) => {
+ if (event.target.classList.contains("form__icon")) {
+ toggleVisibility(event);
+ }
+});
diff --git a/js/validate.js b/js/validate.js
new file mode 100644
index 00000000..ce83eba6
--- /dev/null
+++ b/js/validate.js
@@ -0,0 +1,118 @@
+// common functions
+export function isEmpty(value) {
+ return value ? false : true;
+}
+
+function addInvalid(input) {
+ input.classList.add("invalid");
+}
+
+function removeInvalid(input) {
+ input.classList.remove("invalid");
+}
+
+// email functions
+const emailPattern = /^[A-Za-z0-9_\.\-]+@[A-Za-z0-9\-]+\.[A-Za-z0-9\-]+/;
+
+function checkEmailFormat(email) {
+ if (emailPattern.test(email)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+export function validateEmail(event) {
+ const emailInput = event.target;
+ const email = emailInput.value;
+ let divErrorMessage = document.querySelector(".error-msg--email");
+
+ if (isEmpty(email)) {
+ divErrorMessage.textContent = "이메일을 입력해주세요";
+ addInvalid(emailInput);
+ } else if (!checkEmailFormat(email)) {
+ divErrorMessage.textContent = "잘못된 이메일 형식입니다";
+ addInvalid(emailInput);
+ } else {
+ divErrorMessage.textContent = "";
+ removeInvalid(emailInput);
+ }
+}
+
+// password functions
+function checkPasswordFormat(password) {
+ if (password.length < 8) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+function checkPassword(password, passwordConfirm) {
+ return password === passwordConfirm ? true : false;
+}
+
+export function validatePassword(event) {
+ const passwordInput = event.target;
+ const password = passwordInput.value;
+ let divErrorMessage = document.querySelector(".error-msg--password");
+
+ if (isEmpty(password)) {
+ divErrorMessage.textContent = "비밀번호를 입력해주세요";
+ addInvalid(passwordInput);
+ } else if (!checkPasswordFormat(password)) {
+ divErrorMessage.textContent = "비밀번호를 8자 이상 입력해주세요";
+ addInvalid(passwordInput);
+ } else {
+ divErrorMessage.textContent = "";
+ removeInvalid(passwordInput);
+ }
+}
+
+export function validatePasswordConfirm(event) {
+ const passwordInput = document.getElementById("password");
+ const password = passwordInput.value;
+ const passwordConfirmInput = event.target;
+ const passwordConfirm = passwordConfirmInput.value;
+ let divErrorMessage = document.querySelector(".error-msg--password-confirm");
+
+ if (!checkPassword(password, passwordConfirm)) {
+ divErrorMessage.textContent = "비밀번호가 일치하지 않습니다";
+ addInvalid(passwordConfirmInput);
+ } else {
+ divErrorMessage.textContent = "";
+ removeInvalid(passwordConfirmInput);
+ }
+}
+
+//password유효성 검사를 하면서 password-confirm검사를 하기 위해 event가 아닌 고정으로 값을 가져오도록 함
+export function validatePasswordConfirmReverse() {
+ const passwordInput = document.getElementById("password");
+ const password = passwordInput.value;
+ const passwordConfirmInput = document.getElementById("password-confirm");
+ const passwordConfirm = passwordConfirmInput.value;
+ let divErrorMessage = document.querySelector(".error-msg--password-confirm");
+
+ if (!checkPassword(password, passwordConfirm)) {
+ divErrorMessage.textContent = "비밀번호가 일치하지 않습니다";
+ addInvalid(passwordConfirmInput);
+ } else {
+ divErrorMessage.textContent = "";
+ removeInvalid(passwordConfirmInput);
+ }
+}
+
+//nickname functions
+export function validateNickname(event) {
+ const nicknameInput = event.target;
+ const nickname = nicknameInput.value;
+ let divErrorMessage = document.querySelector(".error-msg--nickname");
+
+ if (isEmpty(nickname)) {
+ divErrorMessage.textContent = "닉네임을 입력해주세요";
+ addInvalid(nicknameInput);
+ } else {
+ divErrorMessage.textContent = "";
+ removeInvalid(nicknameInput);
+ }
+}
diff --git a/login.html b/login.html
index 2557c53f..5ead6fd4 100644
--- a/login.html
+++ b/login.html
@@ -17,7 +17,12 @@
판다마켓
-
+