diff --git a/html/index.html b/html/index.html index a70cdc838..b3645793e 100644 --- a/html/index.html +++ b/html/index.html @@ -25,7 +25,7 @@ 판다마켓 - 로그인 + 로그인
diff --git a/html/login.html b/html/signin.html similarity index 73% rename from html/login.html rename to html/signin.html index e04dc757f..b4e761e10 100644 --- a/html/login.html +++ b/html/signin.html @@ -26,6 +26,12 @@ + + 이메일을 입력해주세요. + + + 잘못된 이메일 형식입니다. +
@@ -35,17 +41,16 @@ - - +
+ + 비밀번호를 입력해주세요. + + + 비밀번호를 8자 이상 입력해주세요. +
로그인
@@ -67,5 +72,5 @@
- + diff --git a/html/signup.html b/html/signup.html index 3963f6e39..48fe10b0c 100644 --- a/html/signup.html +++ b/html/signup.html @@ -26,12 +26,21 @@ + + 이메일을 입력해주세요. + + + 잘못된 이메일 형식입니다. +
+ + 닉네임을 입력해주세요. +
@@ -43,35 +52,30 @@ id="password" placeholder="비밀번호를 입력해주세요" /> - - +
+ + 비밀번호를 입력해주세요. + + + 비밀번호를 8자 이상 입력해주세요. +
- +
- - +
+ + 비밀번호가 일치하지 않습니다. +
회원가입
@@ -87,11 +91,11 @@
이미 회원이신가요? - 로그인 + 로그인
- + diff --git a/js/auth.js b/js/auth.js new file mode 100644 index 000000000..9eea7d8d8 --- /dev/null +++ b/js/auth.js @@ -0,0 +1,175 @@ +// 각 필드의 유효성 검사 상태를 전역변수로 저정함 +let isEmailValid = false; +let isNicknameValid = false; +let isPasswordValid = false; +let isPasswordCheckValid = false; + +const emailInput = document.getElementById('email'); +const nicknameInput = document.getElementById('nickname'); +const passwordInput = document.getElementById('password'); +const passwordCheckInput = document.getElementById('passwordCheck'); + +// 에러 표시 함수 +function showError(input, errorId) { + const errorElement = document.getElementById(errorId); + errorElement.style.display = 'block'; + input.style.border = '1px solid #f74747'; +} + +// 상태 초기화 함수(에러 메세지를 숨기고 입력 필드의 테두리를 원상태로 초기화) +function hideError(input, errorId) { + const errorElement = document.getElementById(errorId); + errorElement.style.display = 'none'; + input.style.border = 'none'; +} + +// 정규 표현식을 통한 이메일 유효성 검증 +function emailValidation(email) { + const emailRegex = /^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/; + return emailRegex.test(email); +} + +// 이메일 필드의 유효성 검사 +function checkEmailValidity() { + const emailValue = emailInput.value; + + // 에러 메세지 및 입력 필드의 상태를 먼저 초기화 + isEmailValid = false; + hideError(emailInput, 'emailEmptyError'); + hideError(emailInput, 'emailInvalidError'); + + if (!emailValue) { + showError(emailInput, 'emailEmptyError'); + } else if (!emailValidation(emailValue)) { + showError(emailInput, 'emailInvalidError'); + } else { + isEmailValid = true; + hideError(emailInput, 'emailEmptyError'); + hideError(emailInput, 'emailInvalidError'); + } + + authBtnStatusChange(); +} +// emailInput이 존재한다면 이벤트 발생 / 존재하지 않으면 발생시키지 않음 +if (emailInput) { + emailInput.addEventListener('focusout', checkEmailValidity); +} + +// 닉네임 필드의 유효성 검사 +function checkNicknameValidity() { + const nicknameValue = nicknameInput.value; + + isNicknameValid = false; + hideError(nicknameInput, 'nicknameEmptyError'); + + if (!nicknameValue) { + showError(nicknameInput, 'nicknameEmptyError'); + } else { + isNicknameValid = true; + hideError(nicknameInput, 'nicknameEmptyError'); + } + + authBtnStatusChange(); +} +if (nicknameInput) { + nicknameInput.addEventListener('focusout', checkNicknameValidity); +} + +// 비밀번호 필드의 유효성 검사 +function checkPasswordValidity() { + const passwordValue = passwordInput.value; + + isPasswordValid = false; + hideError(passwordInput, 'passwordEmptyError'); + hideError(passwordInput, 'passwordLengthError'); + + if (!passwordValue) { + showError(passwordInput, 'passwordEmptyError'); + } else if (passwordValue.length < 8) { + showError(passwordInput, 'passwordLengthError'); + } else { + isPasswordValid = true; + hideError(passwordInput, 'passwordEmptyError'); + hideError(passwordInput, 'passwordLengthError'); + } + + authBtnStatusChange(); +} +if (passwordInput) { + passwordInput.addEventListener('focusout', checkPasswordValidity); +} + +// 비밀번호 확인 필드의 유효성 검사 +function checkPasswordCheckValidity() { + const passwordValue = passwordInput.value; + const passwordCheckValue = passwordCheckInput.value; + + isPasswordCheckValid = false; + hideError(passwordCheckInput, 'passwordCheckError'); + + if (passwordValue !== passwordCheckValue) { + showError(passwordCheckInput, 'passwordCheckError'); + } else { + isPasswordCheckValid = true; + hideError(passwordCheckInput, 'passwordCheckError'); + } + + authBtnStatusChange(); +} +if (passwordCheckInput) { + passwordCheckInput.addEventListener('focusout', checkPasswordCheckValidity); +} + +// auth 버튼 비활성화/활성화 상태 변경 +function authBtnStatusChange() { + const authBtn = document.querySelector('.auth-btn'); + + // 회원가입 페이지일때 + if (nicknameInput && passwordCheckInput) { + if ( + isEmailValid && + isNicknameValid && + isPasswordValid && + isPasswordCheckValid + ) { + authBtn.setAttribute('href', '/html/signin.html'); + authBtn.style.backgroundColor = '#3692ff'; + } else { + authBtn.setAttribute('href', '#'); + authBtn.style.backgroundColor = '#9ca3af'; + } + } + // 로그인 페이지일때 + else { + if (isEmailValid && isPasswordValid) { + authBtn.setAttribute('href', '/html/items.html'); + authBtn.style.backgroundColor = '#3692ff'; + } else { + authBtn.setAttribute('href', '#'); + authBtn.style.backgroundColor = '#9ca3af'; + } + } +} + +// 비밀번호 숨기기 버튼 구현 +const pwEyeBtn = document.querySelector('.pw-eye-btn'); +const pwCkEyeBtn = document.querySelector('.pw-ck-eye-btn'); + +function passwordEyeBtnChange(e) { + const pwInput = e.target.parentElement.querySelector('input'); + + if (e.target.getAttribute('src') === '/images/login/pw-eye-btn-off.png') { + e.target.setAttribute('src', '/images/login/pw-eye-btn-on.png'); + pwInput.setAttribute('type', 'text'); + } else { + e.target.setAttribute('src', '/images/login/pw-eye-btn-off.png'); + pwInput.setAttribute('type', 'password'); + } +} + +if (pwEyeBtn) { + pwEyeBtn.addEventListener('click', passwordEyeBtnChange); +} +if (pwCkEyeBtn) { + pwCkEyeBtn.addEventListener('click', passwordEyeBtnChange); +} diff --git a/js/login.js b/js/login.js deleted file mode 100644 index 46a926c07..000000000 --- a/js/login.js +++ /dev/null @@ -1,35 +0,0 @@ -// 비밀번호 눈 모양 버튼 구현 -const PwEyeBtnOff = document.querySelector('.pw-eye-btn-off'); -const PwEyeBtnOn = document.querySelector('.pw-eye-btn-on'); -const PwInput = document.querySelector('#password'); - -function PwEyeBtnChange(e) { - e.target.classList.add('done'); - if (e.target === PwEyeBtnOff) { - PwEyeBtnOn.classList.remove('done'); - PwInput.setAttribute('type', 'text'); - } else { - PwEyeBtnOff.classList.remove('done'); - PwInput.setAttribute('type', 'password'); - } -} - -PwEyeBtnOn.addEventListener('click', PwEyeBtnChange); -PwEyeBtnOff.addEventListener('click', PwEyeBtnChange); - -// auth 버튼 활성화 -const InputEmail = document.querySelector('#email'); -const InputPassword = document.querySelector('#password'); -const AuthBtn = document.querySelector('.auth-btn'); - -function AuthBtnActive() { - console.log('sdf'); - if (InputEmail.value && InputPassword.value) { - AuthBtn.classList.add('active'); - } else { - AuthBtn.classList.remove('active'); - } -} - -InputEmail.addEventListener('input', AuthBtnActive); -InputPassword.addEventListener('input', AuthBtnActive); diff --git a/js/signup.js b/js/signup.js deleted file mode 100644 index 98d8f4fc4..000000000 --- a/js/signup.js +++ /dev/null @@ -1,63 +0,0 @@ -// 비밀번호 눈 모양 버튼 구현 -const PwEyeBtnOff = document.querySelector('.pw-eye-btn-off'); -const PwEyeBtnOn = document.querySelector('.pw-eye-btn-on'); -const PwInput = document.querySelector('#password'); - -function PwEyeBtnChange(e) { - e.target.classList.add('done'); - if (e.target === PwEyeBtnOff) { - PwEyeBtnOn.classList.remove('done'); - PwInput.setAttribute('type', 'text'); - } else { - PwEyeBtnOff.classList.remove('done'); - PwInput.setAttribute('type', 'password'); - } -} - -PwEyeBtnOn.addEventListener('click', PwEyeBtnChange); -PwEyeBtnOff.addEventListener('click', PwEyeBtnChange); - -// 비밀번호 확인 눈 모양 버튼 구현 -const PwCkEyeBtnOff = document.querySelector('.pw-ck-eye-btn-off'); -const PwCkEyeBtnOn = document.querySelector('.pw-ck-eye-btn-on'); -const PwCkInput = document.querySelector('#password-check'); - -function PwCkEyeBtnChange(e) { - e.target.classList.add('done'); - if (e.target === PwCkEyeBtnOff) { - PwCkEyeBtnOn.classList.remove('done'); - PwCkInput.setAttribute('type', 'text'); - } else { - PwCkEyeBtnOff.classList.remove('done'); - PwCkInput.setAttribute('type', 'password'); - } -} - -PwCkEyeBtnOn.addEventListener('click', PwCkEyeBtnChange); -PwCkEyeBtnOff.addEventListener('click', PwCkEyeBtnChange); - -// auth 버튼 활성화 -const InputEmail = document.querySelector('#email'); -const InputNickname = document.querySelector('#nickname'); -const InputPassword = document.querySelector('#password'); -const InputPasswordCheck = document.querySelector('#password-check'); -const AuthBtn = document.querySelector('.auth-btn'); - -function AuthBtnActive() { - console.log('sdf'); - if ( - InputEmail.value && - InputNickname.value && - InputPassword.value && - InputPasswordCheck.value - ) { - AuthBtn.classList.add('active'); - } else { - AuthBtn.classList.remove('active'); - } -} - -InputEmail.addEventListener('input', AuthBtnActive); -InputNickname.addEventListener('input', AuthBtnActive); -InputPassword.addEventListener('input', AuthBtnActive); -InputPasswordCheck.addEventListener('input', AuthBtnActive); diff --git a/styles/auth.css b/styles/auth.css index 39ec274c2..2ce825abe 100644 --- a/styles/auth.css +++ b/styles/auth.css @@ -77,23 +77,29 @@ input:focus { position: relative; } -.pw-eye-btn-on, -.pw-eye-btn-off, -.pw-ck-eye-btn-on, -.pw-ck-eye-btn-off { +.pw-eye-btn, +.pw-ck-eye-btn { position: absolute; top: 16px; right: 16px; } -.pw-eye-btn-on:hover, -.pw-eye-btn-off:hover, -.pw-ck-eye-btn-on:hover, -.pw-ck-eye-btn-off:hover { +.pw-eye-btn, +.pw-ck-eye-btn { cursor: pointer; } -.done { +.error-message { + padding-left: 16px; + margin-top: 8px; + font-weight: 600; + font-size: 14px; + line-height: 24px; + color: var(--red); + display: none; +} + +.hide { display: none; } @@ -132,6 +138,7 @@ input:focus { background-color: var(--blue100); } +/* 모바일 화면 */ @media (max-width: 767px) { body { padding-left: 16px; diff --git a/styles/home.css b/styles/home.css index 4202ba848..7fdd51602 100644 --- a/styles/home.css +++ b/styles/home.css @@ -145,6 +145,7 @@ footer > .container { gap: 12px; } +/* 태블릿 화면 */ @media (max-width: 1199px) { header .container { margin: 0 24px; @@ -233,6 +234,7 @@ footer > .container { } } +/* 모바일 화면 */ @media (max-width: 767px) { header .container { margin: 0 16px;