Skip to content

[문지영] sprint4 #137

New issue

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

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

Already on GitHub? # to your account

Merged
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 modified .DS_Store
Binary file not shown.
80 changes: 80 additions & 0 deletions js/#.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
function showError(inputEl, message) {
const errorEl = inputEl.parentElement.querySelector('.error-message');
inputEl.classList.add('error');
if (errorEl) errorEl.textContent = message;
}

function clearError(inputEl) {
const errorEl = inputEl.parentElement.querySelector('.error-message');
inputEl.classList.remove('error');
if (errorEl) errorEl.textContent = '';
}

// 이메일 input에서 focus out 할 때,
// 값이 없을 경우 input에 빨강색 테두리와 아래에 “이메일을 입력해주세요.” 빨강색 에러 메세지를 보입니다.
// 이메일 input에서 focus out 할 때,
// 이메일 형식에 맞지 않는 경우 input에 빨강색 테두리와 아래에 “잘못된 이메일 형식입니다” 빨강색 에러 메세지를 보입니다.

const emailInput = document.querySelector('#login-email');
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

emailInput.addEventListener('focusout', function() {
if (emailInput.value === '') {
showError(emailInput, '이메일을 입력해주세요.');
} else if (!emailPattern.test(emailInput.value)) {
showError(emailInput, '잘못된 이메일 형식입니다');
} else {
clearError(emailInput);
}
});

// 비밀번호 input에서 focus out 할 때,
// 값이 없을 경우 아래에 “비밀번호를 입력해주세요.” 에러 메세지를 보입니다
// 비밀번호 input에서 focus out 할 때,
// 값이 8자 미만일 경우 아래에 “비밀번호를 8자 이상 입력해주세요.” 에러 메세지를 보입니다.

const pwInput = document.querySelector('#password');

function validatePassword() {
if (pwInput.value === '') {
showError(pwInput, '비밀번호를 입력해주세요.');
} else if (pwInput.value.length < 8) {
showError(pwInput, '비밀번호를 8자 이상 입력해주세요.');
} else {
clearError(pwInput)};
}

pwInput.addEventListener('focusout', validatePassword)
pwInput.addEventListener('input', validatePassword)
Comment on lines +1 to +48
Copy link
Collaborator

Choose a reason for hiding this comment

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

관련있는 코드끼리 모아놓고, 재사용 가능한 단위로 단일 책임을 가진 함수를 만들면 코드 양도 많이 줄어들어 간결해보이고, 독립적으로 테스트할수도있어 디버깅하기도 편할거예요.

  • 유효성 검사 규칙
  • 유효성 검사 수행에 따른 에러 토글
  • 이벤트 리스너 연결

이렇게 세가지 관심사를 기준으로 코드를 리팩토링해볼까요?

Copy link
Collaborator

Choose a reason for hiding this comment

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

예시)

// 유효성 검사 함수들
const validators = {
  required: (value) => ({
    isValid: value !== '',
    errorMessage: '이메일을 입력해주세요.'
  }),
  email: (value) => ({
    isValid: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value),
    errorMessage: '잘못된 이메일 형식입니다'
  }),
  password: (value) => ({
    isValid: value.length >= 8,
    errorMessage: '비밀번호를 8자 이상 입력해주세요.'
  })
};

// 에러 표시 함수
function toggleError(inputEl, message = '') {
  const errorEl = inputEl.parentElement.querySelector('.error-message');
  inputEl.classList.toggle('error', message !== '');
  if (errorEl) errorEl.textContent = message;
}

// 유효성 검사 실행 & 에러 토글
function validateInput(inputEl, validationRules) {
  const value = inputEl.value;
  
  for (const rule of validationRules) {
    const { isValid, errorMessage } = validators[rule](value);
    if (!isValid) {
      toggleError(inputEl, errorMessage);
      return false;
    }
  }
  
  toggleError(inputEl);
  return true;
}

// 이메일 유효성 검사
const emailInput = document.querySelector('#login-email');
emailInput.addEventListener('focusout', () => {
  validateInput(emailInput, ['required', 'email']);
});

// 비밀번호 유효성 검사
const pwInput = document.querySelector('#password');
const validatePassword = () => {
  validateInput(pwInput, ['required', 'password']);
};

pwInput.addEventListener('focusout', validatePassword);
pwInput.addEventListener('input', validatePassword);

Copy link
Collaborator

Choose a reason for hiding this comment

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

이렇게 나눠놓고보니, validators와 toggleError, validateInput은 login뿐만이 아닌 정해둔 유효성 검사 규칙을 기준으로 검사를 수행하고 에러를 토글해야하는 다른 페이지 (e.g #) 에서도 필요해보여요. 이럴땐 모듈화하고 재사용해주면 코드 중복도 줄어들수있겠죠? :)


// input 에 빈 값이 있거나 에러 메세지가 있으면 ‘로그인’ 버튼은 비활성화 됩니다.
// Input 에 유효한 값을 입력하면 ‘로그인' 버튼이 활성화 됩니다.

const allInput = document.querySelectorAll('input');
const loginBtn = document.querySelector('#login-btn');

function checkAllValid() {
let isValid = true;

allInput.forEach((input) => {
const errorText = input.parentElement.querySelector('.error-message').textContent;
if (input.value ==='' || errorText !== '') {
isValid = false;
}
});

loginBtn.disabled = !isValid;
}

allInput.forEach((input) => {
input.addEventListener('input', checkAllValid);
input.addEventListener('focusout', checkAllValid);
});

// 활성화된 ‘로그인’ 버튼을 누르면 “/items” 로 이동합니다.

loginBtn.addEventListener('click', () => {
if (!loginBtn.disabled) {
window.location.href = '/itmes';
}
});
Comment on lines +53 to +80
Copy link
Collaborator

Choose a reason for hiding this comment

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

NIT: 이런 코드들은 UI에 결합되어있어 쉽게 바뀔 수 있고 (변경의 가능성이 큼) 재사용하기 쉽지 않아요. 위에 드린 코멘트에 있는 함수들은 재사용하기 수월하고요. 따라서 이런 코드는 모듈화의 대상이 된다기보다는 지금처럼 login.js (페이지별 js파일)에 있는게 적절하겠죠? :)

51 changes: 37 additions & 14 deletions js/#.js
Copy link
Collaborator

Choose a reason for hiding this comment

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

이 파일에서도 모듈화된 함수를 사용해주면 코드 중복을 줄일 수 있겠죠? :)

Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ function clearError(inputEl) {
}

// 이메일 input에서 focus out 할 때,
// 값이 없을 경우 input에 빨강색 테두리와 아래에 “이메일을 입력해주세요.”
// 빨강색 에러 메세지를 보입니다.
// 값이 없을 경우 input에 빨강색 테두리와 아래에 “이메일을 입력해주세요.” 빨강색 에러 메세지를 보입니다.

// 이메일 input에서 focus out 할 때,
// 이메일 형식에 맞지 않는 경우 input에 빨강색 테두리와 아래에 “잘못된 이메일 형식입니다”
// 빨강색 에러 메세지를 보입니다.
// 이메일 형식에 맞지 않는 경우 input에 빨강색 테두리와 아래에 “잘못된 이메일 형식입니다” 빨강색 에러 메세지를 보입니다.

const emailInput = document.querySelector('#login-email');
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
Expand All @@ -27,12 +25,12 @@ emailInput.addEventListener('focusout', function() {
} else if (!emailPattern.test(emailInput.value)) {
showError(emailInput, '잘못된 이메일 형식입니다');
} else {
clearError(emailInput)};
});
clearError(emailInput);
}
});

// 닉네임 input에서 focus out 할 때,
// 값이 없을 경우 input에 빨강색 테두리와 아래에 “닉네임을 입력해주세요.”
// 빨강색 에러 메세지를 보입니다.
// 값이 없을 경우 input에 빨강색 테두리와 아래에 “닉네임을 입력해주세요.” 빨강색 에러 메세지를 보입니다.

const nicknameInput = document.querySelector('#nickname');

Expand All @@ -45,15 +43,15 @@ nicknameInput.addEventListener('focusout', function() {
});

// 비밀번호 input에서 focus out 할 때,
// 값이 없을 경우 아래에 “비밀번호를 입력해주세요.”
// 에러 메세지를 보입니다
// 값이 없을 경우 아래에 “비밀번호를 입력해주세요.” 에러 메세지를 보입니다
// 비밀번호 input에서 focus out 할 때,
// 값이 8자 미만일 경우 아래에 “비밀번호를 8자 이상 입력해주세요.”
// 에러 메세지를 보입니다.
// 값이 8자 미만일 경우 아래에 “비밀번호를 8자 이상 입력해주세요.” 에러 메세지를 보입니다.

// 비밀번호 input과 비밀번호 확인 input의 값이 다른 경우,
// 비밀번호 확인 input 아래에 “비밀번호가 일치하지 않습니다..”
// 에러 메세지를 보입니다.
const pwInput = document.querySelector('#password');
const pwcheckInput = document.querySelector('#password-check');

function validatePassword() {
if (pwInput.value === '') {
Expand All @@ -66,7 +64,7 @@ function validatePassword() {
}

function validatePasswordMatch() {
if (pwcheckInput.value !== pwInput.value && pwcheckInput !== '') {
if (pwcheckInput.value === '' || pwcheckInput.value !== pwInput.value) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

pwcheckInput.value === '' 일때는 '비밀번호를 입력해주세요' 와 같은 에러메시지를 따로 보여주는게 좋지않을까요? 논리합 연산자를 사용하게되면 두가지 조건중 하나만 true여도 if문 블락이 실행되니까, 사용자 입장에서 잘못된 피드백을 받게 될 수 있겠죠?

showError(pwcheckInput, '비밀번호가 일치하지 않습니다..');
} else {
clearError(pwcheckInput);
Expand All @@ -82,5 +80,30 @@ pwcheckInput.addEventListener('input', validatePasswordMatch)
// input 에 빈 값이 있거나 에러 메세지가 있으면 ‘회원가입’ 버튼은 비활성화 됩니다.
// Input 에 유효한 값을 입력하면 ‘회원가입' 버튼이 활성화 됩니다.

// 활성화된 ‘회원가입’ 버튼을 누르면 로그인 페이지로 이동합니다
const allInput = document.querySelectorAll('input');
const #Btn = document.querySelector('##-btn');

function checkAllValid() {
let isValid = true;

allInput.forEach((input) => {
const errorText = input.parentElement.querySelector('.error-message').textContent;
if (input.value ==='' || errorText !== '') {
isValid = false;
}
});

#Btn.disabled = !isValid;
}

allInput.forEach((input) => {
input.addEventListener('input', checkAllValid);
input.addEventListener('focusout', checkAllValid);
});

// 활성화된 ‘회원가입’ 버튼을 누르면 로그인 페이지로 이동합니다
#Btn.addEventListener('click', () => {
if (!#Btn.disabled) {
window.location.href = '/#';
}
});
7 changes: 5 additions & 2 deletions login-page.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
placeholder="이메일을 입력해주세요"
required
/>
<div class="error-message"></div>
</div>
<div class="user-info">
<label for="password">비밀번호</label>
Expand All @@ -40,10 +41,11 @@
placeholder="비밀번호를 입력해주세요"
required
/>
<div class="error-message"></div>
</div>
<div class="login-#-button flex-center">
<button type="button" id="login-btn" class="login-#-button flex-center" disabled>
<span>로그인</span>
</div>
</button>
<div class="sns-login">
<p>간편 로그인하기</p>
<div class="sns-logo">
Expand All @@ -61,5 +63,6 @@
</footer>
</form>
</main>
<script src="js/#.js"></script>
</body>
</html>
4 changes: 2 additions & 2 deletions #-page.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@
/>
<div class="error-message"></div>
</div>
<div class="login-#-button flex-center">
<button type="button" id="#-btn" class="login-#-button flex-center" disabled>
<span>회원가입</span>
</div>
</button>
<div class="sns-login">
<p>간편 로그인하기</p>
<div class="sns-logo">
Expand Down
7 changes: 7 additions & 0 deletions style/#-#-page.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,14 @@
width: 100%;
height: 56px;
border-radius: 40px;
border: 0px;
padding: 16px 124px;
cursor: pointer;
}

.login-#-button:disabled {
background-color: #9ca3af;
cursor: not-allowed;
}

.login-#-button span {
Expand Down
Loading