Skip to content
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
106 changes: 106 additions & 0 deletions error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
export function ErrorCheck(code, data = "") {
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 function ErrorCheck(code, data = "") {
export function checkError(code, data = "") {

아래 아티클 참고해보시면 도움이 되실것같아요!
참고

const messageStyle = {
color: "red",
fontSize: "20px",
marginTop: "1px",
display: "block",
}

const inputBorder = "2px solid red"

if (code == "email") {
Copy link
Collaborator

Choose a reason for hiding this comment

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

if문 중첩이 있어서 가독성이 많이 떨어지고, 하나의 함수가 관여하는일이 너무 많아서 유지보수가 어려워보입니다.

이 두가지를 해결하기위해서는 함수가 단일 책임을 가질수있도록 분리해보시는게 좋습니다.

우선 이런 방식은 어떨까요?

// 공통 스타일 정의
const errorStyle = {
  color: "red",
  fontSize: "20px",
  marginTop: "1px",
  display: "block",
};

const successStyle = {
  color: "",
  fontSize: "",
  marginTop: "",
};

const errorBorder = "2px solid red";
const successBorder = "";

// 유효성 검사 함수들
const validateEmail = (email) => {
  if (!email) {
    return {
      error: true,
      message: "이메일을 입력해주세요",
    };
  }

  const regex = /^((?!\.)[\w\-_.]*[^.])(@\w+)(\.\w+(\.\w+)?[^.\W])$/;
  const isValid = regex.test(email);

  return {
    error: !isValid,
    message: isValid ? "" : "잘못된 이메일 형식 입니다.",
  };
};

const validatePassword = (password) => {
  if (!password) {
    return {
      error: true,
      message: "비밀번호를 입력해주세요.",
    };
  }

  const isValid = password.length > 8;
  return {
    error: !isValid,
    message: isValid ? "" : "비밀번호를 8자 이상 입력해주세요.",
  };
};

const validateNickname = (nickname) => {
  const isValid = nickname.length >= 1;
  return {
    error: !isValid,
    message: isValid ? "" : "닉네임을 입력해주세요.",
  };
};

const validatePasswordCheck = (passwords) => {
  const isValid = passwords.password1 === passwords.password2;
  return {
    error: !isValid,
    message: isValid ? "" : "비밀번호가 일치하지 않습니다",
  };
};

// 메인 함수
export function checkError(code, data = "") {
  let validationResult;

  switch (code) {
    case "email":
      validationResult = validateEmail(data);
      break;
    case "password":
      validationResult = validatePassword(data);
      break;
    case "nickname":
      validationResult = validateNickname(data);
      break;
    case "passwordCheck":
      validationResult = validatePasswordCheck(data);
      break;
    default:
      return {
        error: false,
        message: "",
        messageStyle: successStyle,
        inputBorder: successBorder,
      };
  }

  return {
    error: validationResult.error,
    message: validationResult.message,
    messageStyle: validationResult.error ? errorStyle : successStyle,
    inputBorder: validationResult.error ? errorBorder : successBorder,
  };
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

이렇게 함수가 한번에 하나의 일을 할 수 있게끔 쪼개고 보니,
유효성 검사를 수행할때도 각각 따로 함수를 만들 필요가 없어보이고, 재사용 가능한 단위로 분리하는것이 가능해보입니다.

그렇다면 유효성 검사를 수행할때 재사용을 고려해 좀 더 통합적으로 관리될수있도록 만들어볼까요?

코드 예시를 들어드릴게요!

  • 유효성 검사를 담당하는 validation.js
// validation.js - 검증 로직
export const validators = {
  email: (value) => {
    if (!value) return { isValid: false, message: '이메일을 입력해주세요' };
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
      return { isValid: false, message: '올바른 이메일 형식이 아닙니다' };
    }
    return { isValid: true, message: '' };
  },
  
  nickname: (value) => {
    if (!value) return { isValid: false, message: '닉네임을 입력해주세요' };
    return { isValid: true, message: '' };
  },
  
  password: (value) => {
    if (!value) return { isValid: false, message: '비밀번호를 입력해주세요' };
    if (value.length < 8) {
      return { isValid: false, message: '비밀번호는 8자 이상이어야 합니다' };
    }
    return { isValid: true, message: '' };
  },
  
  passwordCheck: (value, formValues) => {
    if (!value) return { isValid: true, message: '' }; // 빈 값은 허용
    if (value !== formValues.password) {
      return { isValid: false, message: '비밀번호가 일치하지 않습니다' };
    }
    return { isValid: true, message: '' };
  }
};

Copy link
Collaborator

Choose a reason for hiding this comment

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

이 방식은

이렇게 validation을 통합적으로 담당하는 객체를 만들고, checkError 함수에서는 이런식으로 사용해준다면

export function checkError(type, data = "") {
  const validator = validators[type];
  if (!validator) {
    return {
      error: false,
      message: "",
      messageStyle: successStyle,
      inputBorder: successBorder,
    };
  }

  const result = validator(data);
  return {
    error: !result.isValid,
    message: result.message,
    messageStyle: !result.isValid ? errorStyle : successStyle,
    inputBorder: !result.isValid ? errorBorder : successBorder,
  };
}

개별적으로 다른 유효성 검사를 수행하던 함수들을 없애주고, switch case문도 사용하지않게 되니까 코드양이 훨씬 줄어들고, 읽기 수월해지고, 수정 및 확장에 용이해지고, 코드가 간결해지겠죠?

if (data.length <= 0) {
return {
error: true,
message: "이메일을 입력해주세요",
messageStyle,
inputBorder,
}
} else {
const regex = /^((?!\.)[\w\-_.]*[^.])(@\w+)(\.\w+(\.\w+)?[^.\W])$/
const check = regex.test(data)
return check
? {
error: false,
message: "",
messageStyle: {
color: "",
funtSize: "",
marginTop: "",
},
inputBorder: "",
}
: {
error: true,
message: "잘못된 이메일 형식 입니다.",
messageStyle,
inputBorder,
}
}
} else if (code == "password") {
if (data.length <= 0) {
return {
error: true,
message: "비밀번호를 입력해주세요.",
messageStyle,
inputBorder,
}
} else {
return data.length > 8
? {
error: false,
message: "",
messageStyle: {
color: "",
funtSize: "",
marginTop: "",
},
inputBorder: "",
}
: {
error: true,
message: "비밀번호를 8자 이상 입력해주세요.",
messageStyle,
inputBorder,
}
}
} else if (code == "nickname") {
return data.length >= 1
? {
error: false,
message: "",
messageStyle: {
color: "",
funtSize: "",
marginTop: "",
},
inputBorder: "",
}
: {
error: true,
message: "닉네임을 입력해주세요.",
messageStyle,
inputBorder,
}
} else if (code == "passwordCheck") {
console.log(data)

return data["password1"] === data["password2"]
? {
error: false,
message: "",
messageStyle: {
color: "",
funtSize: "",
marginTop: "",
},
inputBorder: "",
}
: {
error: true,
message: "비밀번호가 일치하지 않습니다",
messageStyle,
inputBorder,
}
}
}
11 changes: 11 additions & 0 deletions item.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>item</title>
</head>
<body>
<h1>item page</h1>
</body>
</html>
18 changes: 13 additions & 5 deletions login.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@
<form action="post" method="post" class="form-signup">
<label for="email" class="label">이메일</label>
<input
id="email-field"
type="email"
class="input email"
name="email"
autocomplete="email"
/>
<label for="password" class="label">비밀번호</label>
<div class="input-wrapper">
<input
<input
id="password-field"
type="password"
class="input password"
Expand Down Expand Up @@ -60,14 +61,19 @@
11.05 0 0 1-1.67 2.6"
></path>
</svg>
<!-- <span class="toggle-password" onclick="togglePasswordVisibility()">
<span class="toggle-password" onclick="togglePasswordVisibility()">
👁️
</span> -->
</span>
</div>
</div>


<button class="signup-button">로그인</button>
<button
type="button"
onclick="location.href='/item.html'"
class="signup-button"
>
로그인
</button>
</form>
</section>
<section class="social-section">
Expand All @@ -93,4 +99,6 @@
</p>
</section>
</body>
<script type="module" src="./error.js"></script>
<script type="module" src="./login.js"></script>
</html>
104 changes: 104 additions & 0 deletions login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { ErrorCheck } from "./error.js"
const loginButton = document.querySelector(".signup-button")
loginButton.disabled = true
loginButton.style.backgroundColor = "#9CA3AF"
let loginOk = false
let passwordOk = false

const emailInput = document.querySelector("#email-field")
const passwordLabel = document.querySelector('label[for="password"]')

const warningMessage1 = document.createElement("span")

passwordLabel.parentNode.insertBefore(warningMessage1, passwordLabel)

emailInput.addEventListener("focusout", (e) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

이 함수도 위에서 얘기했던것처럼 하나의 함수가 너무 많은 일을 담당하고있어요.

  • validation 상태에 따른 UI 업데이트하기
  • 입력 필드 초기 상태 설정하기
  • 이벤트 핸들러 연결하기

세가지 함수로 작업을 쪼개서 리팩토링해볼까요?

const result = ErrorCheck("email", e.target.value)
console.log("passwordInput result : ", result)

if (result.error) {
warningMessage1.style.color = result.messageStyle.color
warningMessage1.style.fontSize = result.messageStyle.fontSize
warningMessage1.style.marginTop = result.messageStyle.marginTop
warningMessage1.style.display = result.messageStyle.display
emailInput.style.border = result.inputBorder
emailInput.style.marginBottom = 0
warningMessage1.textContent = result.message
loginOk = false
loginButton.disabled = true
loginButton.style.backgroundColor = "#9CA3AF"
} else {
warningMessage1.style.color = result.messageStyle.color
warningMessage1.style.fontSize = result.messageStyle.fontSize
warningMessage1.style.marginTop = result.messageStyle.marginTop
warningMessage1.style.display = result.messageStyle.display
emailInput.style.border = result.inputBorder
warningMessage1.textContent = result.message
loginOk = true

if (loginOk && passwordOk) {
loginButton.disabled = false
loginButton.style.backgroundColor = "#3692FF"
}
}
})

const passwordInput = document.querySelector("#password-field")
const inputWrapper = document.querySelector(".input-wrapper")

const warningMessage2 = document.createElement("span")

inputWrapper.appendChild(warningMessage2, passwordLabel)

passwordInput.addEventListener("focusout", (e) => {
const result = ErrorCheck("password", e.target.value)
console.log("passwordInput result : ", result)

if (result.error) {
warningMessage2.style.color = result.messageStyle.color
warningMessage2.style.fontSize = result.messageStyle.fontSize
warningMessage2.style.marginTop = result.messageStyle.marginTop
warningMessage2.style.display = result.messageStyle.display
passwordInput.style.border = result.inputBorder
passwordInput.style.marginBottom = 0
warningMessage2.textContent = result.message
passwordOk = false
loginButton.disabled = true
loginButton.style.backgroundColor = "#9CA3AF"
} else {
warningMessage2.style.color = result.messageStyle.color
warningMessage2.style.fontSize = result.messageStyle.fontSize
warningMessage2.style.marginTop = result.messageStyle.marginTop
warningMessage2.style.display = result.messageStyle.display
passwordInput.style.border = result.inputBorder
warningMessage2.textContent = result.message
passwordOk = true

if (loginOk && passwordOk) {
loginButton.disabled = false
loginButton.style.backgroundColor = "#3692FF"
}
}
})

const passwordEyeInput = document.querySelector("#password-field")
const eyeIconWrapper = document.querySelector(".icon-eye")
const eyeIcon = document.querySelector("#eye-icon")
const togglePasswordSpan = document.querySelector(".toggle-password")
togglePasswordSpan.style.display = "none"

eyeIconWrapper.addEventListener("click", () => {
const isPasswordVisible = passwordEyeInput.type === "text"

if (isPasswordVisible) {
// 비밀번호 감추기
passwordEyeInput.type = "password"
eyeIcon.style.display = "block"
togglePasswordSpan.style.display = "none"
} else {
// 비밀번호 보이기
passwordEyeInput.type = "text"
eyeIcon.style.display = "none"
togglePasswordSpan.style.display = "inline" // span은 inline
}
})
43 changes: 32 additions & 11 deletions signup.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
<html lang="kr">
<head>
<meta charset="UTF-8" />
<meta property="og:imge" content="https://pub-bf130692c499474c8e98eecfee92a734.r2.dev/panda_market_img.png" />
<meta
property="og:imge"
content="https://pub-bf130692c499474c8e98eecfee92a734.r2.dev/panda_market_img.png"
/>
<meta property="og:title" content="판다마켓" />
<meta property="og:description" content="일상의 모든 물건을 거래해보세요" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
Expand All @@ -23,9 +26,14 @@
<section class="form-section">
<form action="post" method="post" class="form-signup">
<label for="email" class="label">이메일</label>
<input type="email" class="input email" name="email" />
<input id="email-field" type="email" class="input email" name="email" />
<label for="nickname" class="label">닉네임</label>
<input type="nickname" class="input nickname" name="nickname" />
<input
id="nickname-field"
type="nickname"
class="input nickname"
name="nickname"
/>
<label for="password" class="label">비밀번호</label>
<input
id="password-field"
Expand Down Expand Up @@ -58,20 +66,22 @@
11.05 0 0 1-1.67 2.6"
></path>
</svg>
<!-- <span class="toggle-password" onclick="togglePasswordVisibility()">
<span class="toggle-password" onclick="togglePasswordVisibility()">
👁️
</span> -->
</span>
</div>
<label for="password-check" class="label">비밀번호 확인</label>
<label for="password" id="password-check" class="label"
>비밀번호 확인</label
>
<input
id="password-check-field"
type="password-check"
type="password"
class="input password-check"
name="password-check"
/>
<div class="icon-eye2 btn--click">
<svg
id="eye-icon"
id="eye-icon2"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
Expand All @@ -94,11 +104,20 @@
11.05 0 0 1-1.67 2.6"
></path>
</svg>
<!-- <span class="toggle-password" onclick="togglePasswordVisibility()">
<span
class="toggle-check-password"
onclick="togglePasswordVisibility()"
>
👁️
</span> -->
</span>
</div>
<button class="signup-button">회원가입</button>
<button
type="button"
onclick="location.href='/index.html'"
class="signup-button"
>
회원가입
</button>
</form>
</section>
<section class="social-section">
Expand All @@ -122,4 +141,6 @@
<p class="signup">이미 회원이신가요? <a href="./login.html">로그인</a></p>
</section>
</body>
<script type="module" src="./error.js"></script>
<script type="module" src="./signup.js"></script>
</html>
Loading
Loading