From 258fc72c6d7394ddedb6258c54f63269d31c3c25 Mon Sep 17 00:00:00 2001 From: Sea0Soda Date: Mon, 19 May 2025 23:26:18 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=EC=8A=A4=ED=94=84=EB=A6=B0=ED=8A=B8=20?= =?UTF-8?q?=EB=AF=B8=EC=85=984=201=EC=B0=A8=20=EC=99=84=EC=84=B1=EB=B3=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- items.html | 11 ++++ js/login.js | 102 +++++++++++++++++++++++++++++++ js/signup.js | 152 ++++++++++++++++++++++++++++++++++++++++++++++ login/index.html | 1 + login/login.css | 25 ++++++++ login/signup.html | 1 + 6 files changed, 292 insertions(+) create mode 100644 items.html create mode 100644 js/login.js create mode 100644 js/signup.js diff --git a/items.html b/items.html new file mode 100644 index 00000000..68d8f88f --- /dev/null +++ b/items.html @@ -0,0 +1,11 @@ + + + + + + items + + +

item pages

+ + diff --git a/js/login.js b/js/login.js new file mode 100644 index 00000000..641d9132 --- /dev/null +++ b/js/login.js @@ -0,0 +1,102 @@ +document.addEventListener('DOMContentLoaded', function () { + const emailInput = document.getElementById('email') + const passwordInput = document.getElementById('password') + const loginButton = document.querySelector('.login_button') + + // 이메일 부분 + + emailInput.addEventListener('blur', () => { + const value = emailInput.value.trim() + const errorMsg = getOrCreateErrorElement(emailInput) + + if (!value) { + showError(emailInput, errorMsg, '이메일을 입력해주세요.') + } else if (!isValidEmail(value)) { + showError(emailInput, errorMsg, '잘못된 이메일 형식입니다.') + } else { + clearError(emailInput, errorMsg) + } + updateButtonState() + }) + + // 비밀번호 부분 + + passwordInput.addEventListener('blur', () => { + const value = passwordInput.value.trim() + const errorMsg = getOrCreateErrorElement(passwordInput) + + if (!value) { + showError(passwordInput, errorMsg, '비밀번호를 입력해주세요.') + } else if (value.length < 8) { + showError(passwordInput, errorMsg, '비밀번호를 8자 이상 입력해주세요.') + } else { + clearError(passwordInput, errorMsg) + } + updateButtonState() + }) + + function isValidEmail(email) { + const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + return regex.test(email) + } + + function showError(input, errorElement, message) { + const wrapper = input.closest('.login_password_wrap') || input + wrapper.classList.add('error') + errorElement.textContent = message + errorElement.style.display = 'block' + } + + function clearError(input, errorElement) { + const wrapper = input.closest('.login_password_wrap') || input + wrapper.classList.remove('error') + errorElement.textContent = '' + errorElement.style.display = 'none' + } + + function getOrCreateErrorElement(input) { + let wrapper = input.closest('.login_password_wrap') || input + let next = wrapper.nextElementSibling + if (!next || !next.classList.contains('error-message')) { + const error = document.createElement('p') + error.className = 'error-message' + error.style.color = 'red' + error.style.fontSize = '14px' + error.style.marginTop = '4px' + wrapper.parentNode.insertBefore(error, wrapper.nextSibling) + return error + } + return next + } + function updateButtonState() { + const emailValue = emailInput.value.trim() + const passwordValue = passwordInput.value.trim() + + const hasEmailError = getOrCreateErrorElement(emailInput).textContent !== '' + const hasPasswordError = + getOrCreateErrorElement(passwordInput).textContent !== '' + + const isValid = + emailValue && passwordValue && !hasEmailError && !hasPasswordError + + loginButton.disabled = !isValid + + if (isValid) { + loginButton.classList.add('active') + } else { + loginButton.classList.remove('active') + } + } + emailInput.addEventListener('input', updateButtonState) + passwordInput.addEventListener('input', updateButtonState) + + const loginForm = document.querySelector('.login_form_container') + + loginForm.addEventListener('submit', function (e) { + e.preventDefault() // 폼 제출 방지 + if (!loginButton.disabled) { + window.location.href = '/items.html' + } + }) + updateButtonState() +}) diff --git a/js/signup.js b/js/signup.js new file mode 100644 index 00000000..7bd6ce2d --- /dev/null +++ b/js/signup.js @@ -0,0 +1,152 @@ +document.addEventListener('DOMContentLoaded', function () { + const emailInput = document.getElementById('email') + const nicknameInput = document.getElementById('nickname') + const passwordInput = document.getElementById('password') + const passwordCheckInput = document.getElementById('passwordCheck') + const signupButton = document.querySelector('.login_button') + const signupForm = document.querySelector('.signup_form_frame') + + // 이메일 부분 + emailInput.addEventListener('blur', () => { + const value = emailInput.value.trim() + const errorMsg = getOrCreateErrorElement(emailInput) + + if (!value) { + showError(emailInput, errorMsg, '이메일을 입력해주세요.') + } else if (!isValidEmail(value)) { + showError(emailInput, errorMsg, '잘못된 이메일 형식입니다.') + } else { + clearError(emailInput, errorMsg) + } + + updateButtonState() + }) + + // 닉네임 부분 + nicknameInput.addEventListener('blur', () => { + const value = nicknameInput.value.trim() + const errorMsg = getOrCreateErrorElement(nicknameInput) + + if (!value) { + showError(nicknameInput, errorMsg, '닉네임을 입력해주세요.') + } else { + clearError(nicknameInput, errorMsg) + } + + updateButtonState() + }) + + // 비밀번호 부분 + passwordInput.addEventListener('blur', () => { + const value = passwordInput.value.trim() + const errorMsg = getOrCreateErrorElement(passwordInput) + + if (!value) { + showError(passwordInput, errorMsg, '비밀번호를 입력해주세요.') + } else if (value.length < 8) { + showError(passwordInput, errorMsg, '비밀번호를 8자 이상 입력해주세요.') + } else { + clearError(passwordInput, errorMsg) + } + + updateButtonState() + }) + + // 비밀번호 확인 부분분 + passwordCheckInput.addEventListener('blur', () => { + const pwValue = passwordInput.value.trim() + const checkValue = passwordCheckInput.value.trim() + const errorMsg = getOrCreateErrorElement(passwordCheckInput) + + if (pwValue !== checkValue) { + showError(passwordCheckInput, errorMsg, '비밀번호가 일치하지 않습니다.') + } else { + clearError(passwordCheckInput, errorMsg) + } + + updateButtonState() + }) + + emailInput.addEventListener('input', updateButtonState) + nicknameInput.addEventListener('input', updateButtonState) + passwordInput.addEventListener('input', updateButtonState) + passwordCheckInput.addEventListener('input', updateButtonState) + + function updateButtonState() { + const emailValue = emailInput.value.trim() + const nicknameValue = nicknameInput.value.trim() + const passwordValue = passwordInput.value.trim() + const passwordCheckValue = passwordCheckInput.value.trim() + + const hasEmailError = getOrCreateErrorElement(emailInput).textContent !== '' + const hasNicknameError = + getOrCreateErrorElement(nicknameInput).textContent !== '' + const hasPasswordError = + getOrCreateErrorElement(passwordInput).textContent !== '' + const hasPasswordCheckError = + getOrCreateErrorElement(passwordCheckInput).textContent !== '' + + const isValid = + emailValue && + nicknameValue && + passwordValue && + passwordCheckValue && + !hasEmailError && + !hasNicknameError && + !hasPasswordError && + !hasPasswordCheckError + + signupButton.disabled = !isValid + + if (isValid) { + signupButton.classList.add('active') + } else { + signupButton.classList.remove('active') + } + } + + // 회원가입시 로그인페이지로 + signupForm.addEventListener('submit', function (e) { + e.preventDefault() + if (!signupButton.disabled) { + window.location.href = '/login/index.html' + } + }) + + function isValidEmail(email) { + const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + return regex.test(email) + } + + function showError(input, errorElement, message) { + const wrapper = input.closest('.login_password_wrap') || input + wrapper.classList.add('error') + errorElement.textContent = message + errorElement.style.display = 'block' + } + + function clearError(input, errorElement) { + const wrapper = input.closest('.login_password_wrap') || input + wrapper.classList.remove('error') + errorElement.textContent = '' + errorElement.style.display = 'none' + } + + function getOrCreateErrorElement(input) { + let wrapper = input.closest('.login_password_wrap') || input + let next = wrapper.nextElementSibling + if (!next || !next.classList.contains('error-message')) { + const error = document.createElement('p') + error.className = 'error-message' + error.style.color = 'red' + error.style.fontSize = '14px' + error.style.marginTop = '4px' + wrapper.parentNode.insertBefore(error, wrapper.nextSibling) + return error + } + return next + } + + // 페이지 로드 초기화 + updateButtonState() +}) diff --git a/login/index.html b/login/index.html index 81b40fd1..3b13fd8a 100644 --- a/login/index.html +++ b/login/index.html @@ -79,5 +79,6 @@ + diff --git a/login/login.css b/login/login.css index 3585a546..e34e9df9 100644 --- a/login/login.css +++ b/login/login.css @@ -262,3 +262,28 @@ html { max-width: 640px; } } + +.error { + border: 1px solid red; +} + +.error-message { + color: red; + font-size: 14px; + margin-top: 4px; +} + +.login_input.error { + border: 1px solid red !important; +} + +.login_password_wrap.error { + border: 1px solid red; +} + +.login_button:disabled { + background-color: #d1d5db; + color: white; + cursor: not-allowed; + opacity: 1; +} diff --git a/login/signup.html b/login/signup.html index b341ce42..8eaabf5e 100644 --- a/login/signup.html +++ b/login/signup.html @@ -96,5 +96,6 @@ + From 53f3c767968f0baf6a31cde48230c54cb4164e99 Mon Sep 17 00:00:00 2001 From: Sea0Soda Date: Wed, 21 May 2025 11:27:20 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20?= =?UTF-8?q?=EB=B0=8F=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=9C=A0=ED=9A=A8?= =?UTF-8?q?=EC=84=B1=20=EA=B2=80=EC=82=AC=20=EB=A1=9C=EC=A7=81=20=EB=AA=A8?= =?UTF-8?q?=EB=93=88=ED=99=94=20=EB=B0=8F=20=EC=A4=91=EB=B3=B5=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - validateInput 함수와 validationRules 객체를 활용해 공통 로직 분리 - 이메일, 비밀번호, 닉네임 등 조건 검사를 모듈에서 관리하도록 개선 - 중복된 blur 이벤트 로직 간소화 - 함수 이름(getOrCreateErrorElement → validateErrorMessage) 통일로 가독성 향상 --- js/ValidationRules.js | 40 ++++++++++++++++++++++ js/login.js | 49 ++++++++++++-------------- js/signup.js | 80 +++++++++++++++++++------------------------ login/index.html | 2 +- login/signup.html | 2 +- 5 files changed, 98 insertions(+), 75 deletions(-) create mode 100644 js/ValidationRules.js diff --git a/js/ValidationRules.js b/js/ValidationRules.js new file mode 100644 index 00000000..2a37e068 --- /dev/null +++ b/js/ValidationRules.js @@ -0,0 +1,40 @@ +function isValidEmail(email) { + const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + return regex.test(email) +} + +export const validationRules = { + email: [ + { condition: (v) => !v, message: '이메일을 입력해주세요.' }, + { + condition: (v) => !isValidEmail(v), + message: '잘못된 이메일 형식입니다.', + }, + ], + password: [ + { condition: (v) => !v, message: '비밀번호를 입력해주세요.' }, + { + condition: (v) => v.length < 8, + message: '비밀번호를 8자 이상 입력해주세요.', + }, + ], + nickname: [{ condition: (v) => !v, message: '닉네임을 입력해주세요.' }], +} + +export function validateInput( + input, + type, + validateErrorMessage, + showError, + clearError +) { + const value = input.value.trim() + const errorEl = validateErrorMessage(input) + const failed = validationRules[type].find(({ condition }) => condition(value)) + + if (failed) { + showError(input, errorEl, failed.message) + } else { + clearError(input, errorEl) + } +} diff --git a/js/login.js b/js/login.js index 641d9132..55458eae 100644 --- a/js/login.js +++ b/js/login.js @@ -1,3 +1,5 @@ +import { validateInput } from './ValidationRules.js' + document.addEventListener('DOMContentLoaded', function () { const emailInput = document.getElementById('email') const passwordInput = document.getElementById('password') @@ -6,40 +8,29 @@ document.addEventListener('DOMContentLoaded', function () { // 이메일 부분 emailInput.addEventListener('blur', () => { - const value = emailInput.value.trim() - const errorMsg = getOrCreateErrorElement(emailInput) - - if (!value) { - showError(emailInput, errorMsg, '이메일을 입력해주세요.') - } else if (!isValidEmail(value)) { - showError(emailInput, errorMsg, '잘못된 이메일 형식입니다.') - } else { - clearError(emailInput, errorMsg) - } + validateInput( + emailInput, + 'email', + validateErrorMessage, + showError, + clearError + ) updateButtonState() }) // 비밀번호 부분 passwordInput.addEventListener('blur', () => { - const value = passwordInput.value.trim() - const errorMsg = getOrCreateErrorElement(passwordInput) - - if (!value) { - showError(passwordInput, errorMsg, '비밀번호를 입력해주세요.') - } else if (value.length < 8) { - showError(passwordInput, errorMsg, '비밀번호를 8자 이상 입력해주세요.') - } else { - clearError(passwordInput, errorMsg) - } + validateInput( + passwordInput, + 'password', + validateErrorMessage, + showError, + clearError + ) updateButtonState() }) - function isValidEmail(email) { - const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ - return regex.test(email) - } - function showError(input, errorElement, message) { const wrapper = input.closest('.login_password_wrap') || input wrapper.classList.add('error') @@ -54,7 +45,7 @@ document.addEventListener('DOMContentLoaded', function () { errorElement.style.display = 'none' } - function getOrCreateErrorElement(input) { + function validateErrorMessage(input) { let wrapper = input.closest('.login_password_wrap') || input let next = wrapper.nextElementSibling if (!next || !next.classList.contains('error-message')) { @@ -68,13 +59,14 @@ document.addEventListener('DOMContentLoaded', function () { } return next } + function updateButtonState() { const emailValue = emailInput.value.trim() const passwordValue = passwordInput.value.trim() - const hasEmailError = getOrCreateErrorElement(emailInput).textContent !== '' + const hasEmailError = validateErrorMessage(emailInput).textContent !== '' const hasPasswordError = - getOrCreateErrorElement(passwordInput).textContent !== '' + validateErrorMessage(passwordInput).textContent !== '' const isValid = emailValue && passwordValue && !hasEmailError && !hasPasswordError @@ -87,6 +79,7 @@ document.addEventListener('DOMContentLoaded', function () { loginButton.classList.remove('active') } } + emailInput.addEventListener('input', updateButtonState) passwordInput.addEventListener('input', updateButtonState) diff --git a/js/signup.js b/js/signup.js index 7bd6ce2d..cfc9dcfd 100644 --- a/js/signup.js +++ b/js/signup.js @@ -1,3 +1,5 @@ +import { validateInput } from './ValidationRules.js' + document.addEventListener('DOMContentLoaded', function () { const emailInput = document.getElementById('email') const nicknameInput = document.getElementById('nickname') @@ -8,55 +10,43 @@ document.addEventListener('DOMContentLoaded', function () { // 이메일 부분 emailInput.addEventListener('blur', () => { - const value = emailInput.value.trim() - const errorMsg = getOrCreateErrorElement(emailInput) - - if (!value) { - showError(emailInput, errorMsg, '이메일을 입력해주세요.') - } else if (!isValidEmail(value)) { - showError(emailInput, errorMsg, '잘못된 이메일 형식입니다.') - } else { - clearError(emailInput, errorMsg) - } - + validateInput( + emailInput, + 'email', + validateErrorMessage, + showError, + clearError + ) updateButtonState() }) // 닉네임 부분 - nicknameInput.addEventListener('blur', () => { - const value = nicknameInput.value.trim() - const errorMsg = getOrCreateErrorElement(nicknameInput) - - if (!value) { - showError(nicknameInput, errorMsg, '닉네임을 입력해주세요.') - } else { - clearError(nicknameInput, errorMsg) - } - - updateButtonState() - }) + nicknameInput.addEventListener('blur', () => + validateInput( + nicknameInput, + 'nickname', + validateErrorMessage, + showError, + clearError + ) + ) // 비밀번호 부분 - passwordInput.addEventListener('blur', () => { - const value = passwordInput.value.trim() - const errorMsg = getOrCreateErrorElement(passwordInput) - - if (!value) { - showError(passwordInput, errorMsg, '비밀번호를 입력해주세요.') - } else if (value.length < 8) { - showError(passwordInput, errorMsg, '비밀번호를 8자 이상 입력해주세요.') - } else { - clearError(passwordInput, errorMsg) - } - - updateButtonState() - }) - - // 비밀번호 확인 부분분 + passwordInput.addEventListener('blur', () => + validateInput( + passwordInput, + 'password', + validateErrorMessage, + showError, + clearError + ) + ) + + // 비밀번호 확인 부분 passwordCheckInput.addEventListener('blur', () => { const pwValue = passwordInput.value.trim() const checkValue = passwordCheckInput.value.trim() - const errorMsg = getOrCreateErrorElement(passwordCheckInput) + const errorMsg = validateErrorMessage(passwordCheckInput) if (pwValue !== checkValue) { showError(passwordCheckInput, errorMsg, '비밀번호가 일치하지 않습니다.') @@ -78,13 +68,13 @@ document.addEventListener('DOMContentLoaded', function () { const passwordValue = passwordInput.value.trim() const passwordCheckValue = passwordCheckInput.value.trim() - const hasEmailError = getOrCreateErrorElement(emailInput).textContent !== '' + const hasEmailError = validateErrorMessage(emailInput).textContent !== '' const hasNicknameError = - getOrCreateErrorElement(nicknameInput).textContent !== '' + validateErrorMessage(nicknameInput).textContent !== '' const hasPasswordError = - getOrCreateErrorElement(passwordInput).textContent !== '' + validateErrorMessage(passwordInput).textContent !== '' const hasPasswordCheckError = - getOrCreateErrorElement(passwordCheckInput).textContent !== '' + validateErrorMessage(passwordCheckInput).textContent !== '' const isValid = emailValue && @@ -132,7 +122,7 @@ document.addEventListener('DOMContentLoaded', function () { errorElement.style.display = 'none' } - function getOrCreateErrorElement(input) { + function validateErrorMessage(input) { let wrapper = input.closest('.login_password_wrap') || input let next = wrapper.nextElementSibling if (!next || !next.classList.contains('error-message')) { diff --git a/login/index.html b/login/index.html index 3b13fd8a..2293ba83 100644 --- a/login/index.html +++ b/login/index.html @@ -79,6 +79,6 @@ - + diff --git a/login/signup.html b/login/signup.html index 8eaabf5e..f9b67125 100644 --- a/login/signup.html +++ b/login/signup.html @@ -96,6 +96,6 @@ - +