Skip to content

[이재원] sprint4 #71

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File renamed without changes
File renamed without changes
13 changes: 9 additions & 4 deletions login.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css"
/>
<link rel="stylesheet" href="styles/global.css" />
<link rel="stylesheet" href="styles/login-signup.css" />
<link rel="stylesheet" href="styles/auth.css" />
</head>

<body>
Expand All @@ -21,19 +21,23 @@
<img src="images/logo.png" alt="판다마켓" class="login-log" />
</a>
<div class="login-content">
<form action="/login" method="POST" class="login-form">
<form action="items.html" method="get" class="login-form">
<div class="form-group">
<label for="userId">이메일</label>
<input id="userId" type="email" name="email" />
<p id="IdError" style="display: none; color: red"></p>
</div>
<div class="form-group">
<label for="password">비밀번호</label>
<div class="input-wrapper">
<input id="password" type="password" name="password" />
<img src="images/password-icon1.png" alt="보기 아이콘" />
<img id="viewIcon" src="images/eye-close.png" alt="보기 아이콘" />
<p id="passwordError" style="display: none; color: red"></p>
</div>
</div>
<a href="login.html" class="login-btn button">로그인</a>
<button type="submit" id="loginBtn" class="login-btn button" disabled>
로그인
</button>
</form>
<div class="simple-login">
간편 로그인하기
Expand All @@ -51,5 +55,6 @@
</div>
</div>
</div>
<script src="login.js"></script>
</body>
</html>
68 changes: 68 additions & 0 deletions login.js
Copy link
Collaborator

Choose a reason for hiding this comment

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

login.js 와 signup.js 에서 아래와 같은 유틸 함수가 중복되어 있습니다.

  • 이메일 형식 검사
  • 비밀번호 길이 검사
  • 값이 비어있는지 확인하는 로직

이러한 구조는 유지보수에 불리하고, 검증 기준이 바뀔 경우 양 파일을 모두 수정해야 하므로 실수를 유발하기 쉽습니다. 이런 유효성 판단 함수는 아래와 같이 ** 공통 유틸 함수**로 분리 하면 좋을 것 같네요.

// validation.js 등으로 분리
export function showError(input, errorEl, message) { ... }
export function clearError(input, errorEl) { ... }
export function isEmailValid(value) { ... }
export function isNotEmpty(value) { ... }

Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const $userId = document.querySelector('#userId');
const $IdError = document.querySelector('#IdError');
const $password = document.querySelector('#password');
const $passwordError = document.querySelector('#passwordError');
const $loginBtn = document.querySelector('#loginBtn');
const $viewIcon = document.querySelector('#viewIcon');
let idCheck = false;
let passwordCheck = false;

function btnCheck() {
if (idCheck && passwordCheck) {
$loginBtn.disabled = false;
} else {
$loginBtn.disabled = true;
}
}

function handleFocustOutId() {
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const value = $userId.value.trim();
Copy link
Collaborator

Choose a reason for hiding this comment

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

공백 입력을 고려한 trim() 메소드 활용 좋습니다! 👍

if (value === '') {
$IdError.style.display = 'block';
$IdError.innerText = '이메일을 입력해주세요.';
$userId.style.border = '2px solid red';
idCheck = false;
} else if (!emailPattern.test(value)) {
$IdError.style.display = 'block';
$IdError.innerText = '잘못된 이메일 형식입니다.';
$userId.style.border = '2px solid red';
idCheck = false;
} else {
$IdError.style.display = 'none';
$userId.style.border = '';
idCheck = true;
}
btnCheck();
}
function handleFocutOutPassWord() {
const value = $password.value.trim();
if (value === '') {
$passwordError.style.display = 'block';
$passwordError.innerText = '비밀번호를 입력해주세요.';
$password.style.border = '2px solid red';
passwordCheck = false;
} else if (value.length < 8) {
$passwordError.style.display = 'block';
$passwordError.innerText = '비밀번호를 8자 이상 입력해주세요.';
$password.style.border = '2px solid red';
passwordCheck = false;
} else {
$passwordError.style.display = 'none';
$password.style.border = '';
passwordCheck = true;
}
btnCheck();
}

function handlePassWordView() {
const isPassWordVisible = $password.type === 'text';
$password.type = isPassWordVisible ? 'password' : 'text';
$viewIcon.src = isPassWordVisible
Copy link
Collaborator

Choose a reason for hiding this comment

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

src 컨트롤로 토글 버튼 구현해주신 점 좋네요!👏

? 'images/eye-close.png'
: 'images/eye-open.png';
}

$userId.addEventListener('focusout', handleFocustOutId);
$password.addEventListener('focusout', handleFocutOutPassWord);
$viewIcon.addEventListener('click', handlePassWordView);
22 changes: 17 additions & 5 deletions signup.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css"
/>
<link rel="stylesheet" href="styles/global.css" />
<link rel="stylesheet" href="styles/login-signup.css" />
<link rel="stylesheet" href="styles/auth.css" />
</head>

<body>
Expand All @@ -21,30 +21,41 @@
<img src="images/logo.png" alt="판다마켓" class="signup-logo" />
</a>
<div class="signup-content">
<form action="/signup" method="POST" class="signup-form">
<form action="login.html" method="POST" class="signup-form">
<div class="form-group">
<label for="userId">이메일</label>
<input id="userId" type="email" name="email" />
<p id="IdError" style="display: none; color: red"></p>
</div>
<div class="form-group">
<label for="nickname">닉네임</label>
<input id="nickname" type="text" name="text" />
<p id="nicknameError" style="display: none; color: red"></p>
</div>
<div class="form-group">
<label for="password">비밀번호</label>
<div class="input-wrapper">
<input id="password" type="password" name="password" />
<img src="images/password-icon1.png" alt="보기 아이콘" />
<img id="viewIcon" src="images/eye-close.png" alt="보기 아이콘" />
<p id="passwordError" style="display: none; color: red"></p>
Copy link
Collaborator

Choose a reason for hiding this comment

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

현재 에러 메세지 요소를 보여줄때, JS에서 직접 인라인 스타일을 조작하고 계신데요, 이는 간단한 방법이긴 하지만 CSS 클래스와 충돌하거나 덮어쓰기 위험이 있어 유지보수에 불리합니다.

차라리 아래와 같이 에러 메시지용 클래스를 정의하고, js에서는 클래스 추가/제거만 담당하는 구조로 수정해보시면 어떨까요??

/* CSS */
.error-message {
  display: none;
  color: red;
  font-size: 14px;
}

.error-message.visible {
  display: block;
}

</div>
</div>
<div class="form-group">
<label for="passwordCheck">비밀번호 확인</label>
<div class="input-wrapper">
<input id="passwordCheck" type="text" name="text" />
<img src="images/password-icon2.png" alt="보기 아이콘" />
<img id="viewIcon2" src="images/eye-open.png" alt="보기 아이콘" />
<p id="passwordCheckError" style="display: none; color: red"></p>
</div>
</div>
<a href="login.html" class="signup-btn button">회원가입</a>
<button
type="submit"
id="signupBtn"
class="signup-btn button"
disabled
>
회원가입
</button>
</form>
<div class="simple-login">
간편 로그인하기
Expand All @@ -62,5 +73,6 @@
</div>
</div>
</div>
<script src="signup.js"></script>
</body>
</html>
117 changes: 117 additions & 0 deletions signup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
const $userId = document.querySelector('#userId');
const $IdError = document.querySelector('#IdError');
const $nickName = document.querySelector('#nickname');
const $nicknameError = document.querySelector('#nicknameError');
const $password = document.querySelector('#password');
const $passwordError = document.querySelector('#passwordError');
const $passwordCheck = document.querySelector('#passwordCheck');
const $passwordCheckError = document.querySelector('#passwordCheckError');
const $signupBtn = document.querySelector('#signupBtn');
const $viewIcon = document.querySelector('#viewIcon');
const $viewIcon2 = document.querySelector('#viewIcon2');
let idCheck = false;
let passwordCheck = false;
Copy link
Collaborator

Choose a reason for hiding this comment

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

passwordCheck라는 변수명이 비밀번호 일치 여부인지, 비밀번호 유효성인지 불명확한 것 같습니다. isPasswordValid, isPasswordConfirmed 등으로 명확히 분리하면 좋을 것 같습니다.

let nicknameCheck = false;
let passwordAuthCheck = false;

function btnCheck() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

함수명은 보다 직관적이게, 그리고 가급적 동사로 시작되도록 지어주시는게 좋습니다!
updateSubmitButtonState 정도로 수정하면 좋을것 같네요.

if (idCheck && passwordCheck && nicknameCheck && passwordAuthCheck) {
$signupBtn.disabled = false;
} else {
$signupBtn.disabled = true;
}
}

function handleFocustOutId() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

이메일 인풋과 관련된 이벤트핸들러이니 handleFocuseOutEmail 이 더 적합할 것 같네요.

const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const value = $userId.value.trim();
if (value === '') {
Copy link
Collaborator

Choose a reason for hiding this comment

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

$xxxError.style.display = 'block';
$xxxError.innerText = 'xxx를 입력해주세요.';
$xxx.style.border = '2px solid red';
xxxCheck = false;

위와 같은 코드 라인이 이메일, 닉네임, 비밀번호 등에서 계속 반복되고 있습니다.
아래와 같이 추상화해서 중복 코드를 제거하면 좋을 것 같습니다.

function showError(input, errorEl, message) {
  errorEl.style.display = 'block';
  errorEl.innerText = message;
  input.style.border = '2px solid red';
}

function clearError(input, errorEl) {
  errorEl.style.display = 'none';
  input.style.border = '';
}

$IdError.style.display = 'block';
$IdError.innerText = '이메일을 입력해주세요.';
$userId.style.border = '2px solid red';
idCheck = false;
} else if (!emailPattern.test(value)) {
$IdError.style.display = 'block';
$IdError.innerText = '잘못된 이메일 형식입니다.';
$userId.style.border = '2px solid red';
idCheck = false;
} else {
$IdError.style.display = 'none';
$userId.style.border = '';
idCheck = true;
}
btnCheck();
}

function handleFocusOutNickName() {
const value = $nickName.value.trim();
if (value === '') {
$nicknameError.style.display = 'block';
$nicknameError.innerText = '닉네임을 입력해주세요.';
$nickName.style.border = '2px solid red';
passwordCheck = false;
} else {
$nicknameError.style.display = 'none';
$nickName.style.border = '';
nicknameCheck = true;
}
btnCheck();
}

function handleFocutOutPassWord() {
const value = $password.value.trim();
if (value === '') {
$passwordError.style.display = 'block';
$passwordError.innerText = '비밀번호를 입력해주세요.';
$password.style.border = '2px solid red';
passwordCheck = false;
} else if (value.length < 8) {
$passwordError.style.display = 'block';
$passwordError.innerText = '비밀번호를 8자 이상 입력해주세요.';
$password.style.border = '2px solid red';
passwordCheck = false;
} else {
$passwordError.style.display = 'none';
$password.style.border = '';
passwordCheck = true;
}
btnCheck();
}

function handleFocusOutPassWordCheck() {
const value = $passwordCheck.value.trim();
if (value === $password.value) {
$passwordCheckError.style.display = 'none';
$passwordCheck.style.border = '';
passwordAuthCheck = true;
} else {
$passwordCheckError.style.display = 'block';
$passwordCheckError.innerText = '비밀번호가 일치하지 않습니다.';
$passwordCheck.style.border = '2px solid red';
passwordAuthCheck = false;
}
btnCheck();
}

function handlePassWordView() {
const isPassWordVisible = $password.type === 'text';
$password.type = isPassWordVisible ? 'password' : 'text';
$viewIcon.src = isPassWordVisible
? 'images/eye-close.png'
: 'images/eye-open.png';
}

function handlePassWordView2() {
const isPassWordVisible = $passwordCheck.type === 'text';
$passwordCheck.type = isPassWordVisible ? 'password' : 'text';
$viewIcon2.src = isPassWordVisible
? 'images/eye-close.png'
: 'images/eye-open.png';
}

$userId.addEventListener('focusout', handleFocustOutId);
$password.addEventListener('focusout', handleFocutOutPassWord);
$nickName.addEventListener('focusout', handleFocusOutNickName);
$passwordCheck.addEventListener('focusout', handleFocusOutPassWordCheck);
$viewIcon.addEventListener('click', handlePassWordView);
$viewIcon2.addEventListener('click', handlePassWordView2);
1 change: 1 addition & 0 deletions styles/login-signup.css → styles/auth.css
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
.signup-btn {
height: 56px;
border-radius: 40px;
font-size: 20px;
}

.simple-login {
Expand Down
Loading