Skip to content

Conversation

@SanginJeong
Copy link
Collaborator

요구사항

배포링크

기본

로그인

  • 이메일 input에서 focus out 할 때, 값이 없을 경우 input에 빨강색 테두리와 아래에 "이메일을 입력해주세요." 빨강색 에러 메세지를 보입니다.
  • 이메일 input에서 focus out 할 때, 이메일 형식에 맞지 않는 경우 input에 빨강색 테두리와 아래에 "잘못된 이메일 형식입니다" 빨강색 에러 메세지를 보입니다.
  • 비밀번호 input에서 focus out 할 때, 값이 없을 경우 아래에 "비밀번호를 입력해주세요." 에러 메세지를 보입니다
  • 비밀번호 input에서 focus out 할 때, 값이 8자 미만일 경우 아래에 "비밀번호를 8자 이상 입력해주세요." 에러 메세지를 보입니다.
  • input 에 빈 값이 있거나 에러 메세지가 있으면 '로그인' 버튼은 비활성화 됩니다.
  • input 에 유효한 값을 입력하면 '로그인' 버튼이 활성화 됩니다.
  • 활성화된 '로그인' 버튼을 누르면 "/items" 로 이동합니다

회원가입

  • 이메일 input에서 focus out 할 때, 값이 없을 경우 input에 빨강색 테두리와 아래에 "이메일을 입력해주세요." 빨강색 에러 메세지를 보입니다.
  • 이메일 input에서 focus out 할 때, 이메일 형식에 맞지 않는 경우 input에 빨강색 테두리와 아래에 "잘못된 이메일 형식입니다" 빨강색 에러 메세지를 보입니다.
  • 닉네임 input에서 focus out 할 때, 값이 없을 경우 input에 빨강색 테두리와 아래에 "닉네임을 입력해주세요." 빨강색 에러 메세지를 보입니다.
  • 비밀번호 input에서 focus out 할 때, 값이 없을 경우 아래에 "비밀번호를 입력해주세요." 에러 메세지를 보입니다
  • 비밀번호 input에서 focus out 할 때, 값이 8자 미만일 경우 아래에 "비밀번호를 8자 이상 입력해주세요." 에러 메세지를 보입니다.
  • 비밀번호 input과 비밀번호 확인 input의 값이 다른 경우, 비밀번호 확인 input 아래에 "비밀번호가 일치하지 않습니다.." 에러 메세지를 보입니다.
  • input 에 빈 값이 있거나 에러 메세지가 있으면 '회원가입' 버튼은 비활성화 됩니다.
  • input 에 유효한 값을 입력하면 '회원가입' 버튼이 활성화 됩니다.
  • 활성화된 '회원가입' 버튼을 누르면 로그인 페이지로 이동합니다

심화

  • 눈 모양 아이콘 클릭시 비밀번호의 문자열이 보이기도 하고, 가려지기도 합니다.
  • 비밀번호의 문자열이 가려질 때는 눈 모양 아이콘에는 사선이 그어져있고, 비밀번호의 문자열이 보일 때는 사선이 없는 눈 모양 아이콘이 보이도록 합니다.

스크린샷

panda-market-sanginjeong netlify app_pages_loginandsignuppage_loginpage_login (1) panda-market-sanginjeong netlify app_pages_loginandsignuppage_loginpage_login (2) panda-market-sanginjeong netlify app_pages_loginandsignuppage_signuppage_signup (2) panda-market-sanginjeong netlify app_pages_loginandsignuppage_signuppage_signup (3)

멘토에게

  • 중복되는 코드가 많아서 리팩토링을 계속 시도하는 중이지만 아직 실패입니다 ㅠㅠ.
  • 버튼 활성화에 대해서 "focusout" 이 아닌 "input" 이벤트를 사용하면 좀 간단해질 것 같은데 input이벤트를 사용해도 되나요?
  • 셀프 코드 리뷰를 통해 질문 이어가겠습니다.

@SanginJeong SanginJeong added the 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. label Jul 22, 2025
@kiJu2
Copy link
Collaborator

kiJu2 commented Jul 23, 2025

스프리트 미션 하시느라 수고 많으셨어요.
상인님 학습에 도움 되실 수 있게 꼼꼼히 리뷰 하도록 해보겠습니다. 😊

@kiJu2
Copy link
Collaborator

kiJu2 commented Jul 23, 2025

크으 ~ 커밋 정말 깔-끔하네요 👍

@kiJu2
Copy link
Collaborator

kiJu2 commented Jul 23, 2025

중복되는 코드가 많아서 리팩토링을 계속 시도하는 중이지만 아직 실패입니다 ㅠㅠ.

오오 굿굿. 리팩토링을 고려하시는 것 자체가 긍정신호입니다 👍
리뷰하다가 도움 될만한 코멘트가 있으면 달아보도록 할게요 ! 😉

@kiJu2
Copy link
Collaborator

kiJu2 commented Jul 23, 2025

버튼 활성화에 대해서 "focusout" 이 아닌 "input" 이벤트를 사용하면 좀 간단해질 것 같은데 input이벤트를 사용해도 되나요?

"사용자 경험" 측면에서 "더욱 간단해진다"라는 의미라면 강사가 아닌 유저로서 공감이 됩니다. 😉
"코드 설계 상(혹은 난이도가) 더욱 간단해진다" 라면 개발자는 기획과 디자인을 기반으로 작성된 요구사항 명세를 개발하는 직무이며 미션 취지가 학습을 목적으로 수행하는 것이기에 요구사항 기반으로 기능을 완성시켜보신 후 input으로 바꿔보셔도 될 것 같아요 ! 😊

결론: 넵. input 그대로 하셔도 큰 문제 없어보입니다 😉

<div class="landing-area">
<div class="landing-area-left">
<h2 class="description">
<h1 class="description">
Copy link
Collaborator

Choose a reason for hiding this comment

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

<h1> 태그는 문서에 하나만 넣는게 어떨까요?

이하 MDN 발췌

페이지 당 하나의 <h1>만 사용하세요. 여러 개를 써도 오류는 나지 않겠지만, 단일 <h1>이 모범 사례로 꼽힙니다. 논리적으로 생각했을 때도, <h1>은 가장 중요한 제목이므로 전체 페이지의 목적을 설명해야 할 것입니다. 두 개의 제목을 가진 책이나, 여러 개의 이름을 가진 영화는 볼 수 없죠! 또한 스크린 리더 사용자와 SEO에도 더 적합합니다.

MDN <h1>-<h6>: HTML 구획 제목 요소

@@ -1,4 +1,4 @@
.login-btn {
.go-login-btn {
Copy link
Collaborator

Choose a reason for hiding this comment

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

(심화/생각해보기/제안) login은 '기능'을 의미해요. 스타일 이름은 "어떤 스타일인지"를 목표로 네이밍을 작성해보면 어떨까요?

Suggested change
.go-login-btn {
<a href="/login.html" class="button button-primary">로그인 </a>

만약, 현재 button-login과 같은 스타일의 "장바구니에 담기" 라는 버튼이 존재한다면 클래스 이름이 어떻게 될까요?

button-login 클래스로 작성한다면 login이라는 "기능"을 목적으로 하는 클래스 이름을 넣게 될거예요. 혹은 중복된 스타일과 다른 클래스 이름인 button-add-wish와 같은 클래스 이름을 가지게 돼요. 이는 재사용성을 저하시킬거예요.
차라리 해당 클래스가 "어떤 스타일을 포함하는가?"에 목적을 두어 네이밍을 한다면 더욱 재사용하기 용이할거라고 생각해서 제안드립니다 😊

priamry: 주로 브랜드의 주요 컬러를 의미합니다 ! 😊 판다마켓의 경우 파란색이죠 !

Comment on lines +14 to +33
export const clearErrorTag = (element) => {
const errorTag = element.nextElementSibling;
if (errorTag && errorTag.classList.contains("error-message")) {
element.classList.remove("error-status");
errorTag.remove();
}
};

export const createErrorTag = (element, message) => {
const tag = document.createElement("p");
tag.classList.add(`error-message`);
tag.textContent = message;
element.classList.add("error-status");
return element.after(tag);
};

export const isValidEmail = (email) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

크으 ~ 함수들이 하나같이 외부 환경에 영향을 주지 않는군요 !

'인자로 받은 것들만을 처리' 하며, 외부에 무언가 영향을 주는 함수가 없네요 👍
상인님께서 작성하신 이러한 함수를 “순수 함수(Pure Function)” 라고 부릅니다.

이러한 구조는 테스트하기도 쉽고, 예측 가능한 코드 작성에 도움이 되는 좋은 패턴입니다.
지금처럼 유틸리티 함수를 순수하게 분리해 작성하는 습관, 정말 잘 하고 계세요! 🔥

@@ -0,0 +1,33 @@
export const isValidValue = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

(권장) is~는 통상적으로 boolean 변수명을 작성할 때 쓰입니다 !

Suggested change
export const isValidValue = {
export const formValidState = {

하지만 값은 객체로 작성되어있군요 !

Comment on lines +1 to +12
export const isValidValue = {
login: {
loginEmail: false,
loginPassword: false,
},
signup: {
signupEmail: false,
signupNickname: false,
signupPassword: false,
signupCheckPassword: false,
},
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

(심화/생각해보기) 구조가 정말 좋아요. 스키마로 거듭날 수도 있겠군요 !

문제 해결 방법에 대한 접근이 정말 좋아요 !
다음과 같이 스키마 형태로 발전시킬 수도 있겠네요 !:

Suggested change
export const isValidValue = {
login: {
loginEmail: false,
loginPassword: false,
},
signup: {
signupEmail: false,
signupNickname: false,
signupPassword: false,
signupCheckPassword: false,
},
};
export const signupSchema = {
email: {
isValid: false,
validate: (value) => /\S+@\S+\.\S+/.test(value),
message: {
void: "이메일을 입력해주세요.",
invalid: "잘못된 이메일 형식입니다.",
},
},
nickname: {
isValid: false,
validate: (value) => value.trim().length > 0,
message: {
void: "닉네임을 입력해주세요.",
},
},
password: {
isValid: false,
validate: (value) => value.length >= 8,
message: {
void: "비밀번호를 입력해주세요.",
invalid: "8자 이상 입력해주세요.",
},
},
checkPassword: {
isValid: false,
validate: (value, original) => value === original,
message: {
invalid: "비밀번호가 일치하지 않습니다.",
},
},
};

상인님께서는 제가 알기로 리액트도 어느 정도 해보셨다고 알고 있어서 조금은 심화된 피드백을 드려봅니다. 😉
나중에는 zodjoi같은 유효성 검사 라이브러리도 사용해보실 수도 있습니다 ! 😊

Copy link
Collaborator

Choose a reason for hiding this comment

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

재사용성을 고려하신 설계가 정~말 좋습니다 👍

</button>
</div>
<button class="form-submit-btn disabled" disabled>로그인</button>
<button type="submit" class="button form-btn" id="login-btn" disabled>
Copy link
Collaborator

Choose a reason for hiding this comment

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

굿굿 ~! type까지 명시해두셨군요 ! 👍

buttontypesubmit으로 기본값이긴 하나, 의도가 명확하네요 ~!

Comment on lines +42 to +55
if (!value) {
const errorTag = createErrorTag(e.target, "비밀번호를 입력해주세요");
$loginBtn.disabled = true;
return errorTag;
}

if (value.length < 8) {
const errorTag = createErrorTag(
e.target,
"비밀번호를 8자 이상 입력해주세요."
);
$loginBtn.disabled = true;
return errorTag;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

굿굿 ! Guard Clause 패턴으로 가독성을 향상시켰군요 ! 👍👍

Guard Clause 패턴을 사용하고 계시군요 ! 멋집니다 상인님.
조건부를 조기에 처리할 수 있게 되어 핵심 로직을 구분할 수 있다는 장점이 있습니다. 따라서 가독성을 향상시킬 수 있어요.

또한, 미리 조건에 따라서 데이터의 범위를 좁힐 수 있기에 핵심 로직에서는 보장받은 데이터를 편리하게 사용할 수 있다는 장점도 있어요 😊

Guard Clause ?

다음과 같이 조기에 함수를 끝내는 기법을 의미합니다:

function calculateDiscount(price, discountRate) {
  // Guard Clause: 가격이나 할인율이 유효하지 않으면 함수 종료
  if (price <= 0 || discountRate <= 0 || discountRate > 1) {
    console.error("Invalid price or discount rate");
    return;
  }

  // 할인된 가격 계산
  const discountedPrice = price * (1 - discountRate);
  return discountedPrice;
}

@kiJu2
Copy link
Collaborator

kiJu2 commented Jul 23, 2025

수고하셨습니다 상인님~!!
순수 함수 구조나 Guard Clause 패턴, 스키마화에 대한 고민까지… 정말 훌륭했어요! 😎
학습에 열정이 뛰어나신 것을 알기에, 약간은 욕심내서 리뷰했던 것 같아요. 🤣🤣

유효성 검증 로직의 정리와 재사용성도 인상 깊었습니다. 앞으로도 지금처럼 탄탄한 설계와 세심한 시도들 기대해봅니다 😊
미션 수고 많으셨습니다! 🙌

@kiJu2 kiJu2 merged commit 48f176f into codeit-bootcamp-frontend:Basic-정상인 Jul 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants