Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 7 additions & 2 deletions sign-in.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@ <h1>판다마켓</h1>
<form>
<div class="group">
<label for="email">이메일</label>
<input type="email" id="email" name="email" placeholder="이메일을 입력해주세요.">
<input type="email" id="email" name="email" placeholder="이메일을 입력해주세요."
class="error-input">
<p id="emailErr" class="errMsg">잘못된 이메일 형식입니다</p>
Copy link
Collaborator

Choose a reason for hiding this comment

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

💊 제안
미리 에러 메시지가 나타날 태그를 만들어 주셔서 DOM 조작을 최소화하신 점은 좋습니다!
다만 에러 메시지는 에러 상황에 따라 추가되도록 하는 것이 더 명확할 것 같아요!
지금처럼 미리 메시지가 들어가 있는 경우는 에러 나는 경우가 하나인 경우에 적절할 것 같습니다.


</div>
<div class="group">
<label for="password">비밀번호</label>
<div class="password-input">
<input type="password" id="password" name="password" placeholder="비밀번호를 입력해주세요.">

<img src="./image/invisible_icon.png" class="password-icon" alt="비밀번호 보기">
<p id="passwordErr" class="errMsg">비밀번호를 8자 이상 입력해주세요.</p>
</div>
</div>
<button type="submit">로그인</button>
Copy link
Collaborator

Choose a reason for hiding this comment

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

❗️ 수정요청
지금은 디자인상 버튼이 회색일 뿐 제출이 되네요.
해당 버튼에 disabled 속성을 추가하셔서 input이 비어있을 때는 버튼이 비활성화되고 클릭되지 않도록 해주세요!

Expand All @@ -57,6 +62,6 @@ <h1>간편 로그인하기</h1>


</div>

<script src="./sign-in.js"></script>
Copy link
Collaborator

Choose a reason for hiding this comment

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

💊 제안

아마 script 태그를 HTML의 하단에 배치하신 이유가 script가 문서의 렌더링을 막지 않도록 하기 위해서이실 것 같아요.
하지만, script 태그에 defer나 async 속성을 사용하면 이런 문제를 해결할 수 있기 때문에 반드시 하단에 배치할 필요는 없습니다!
또한 script 태그는 상단에 있는게 구조 파악에서도 유리하기 때문에 상단 head 태그에 두시는 것을 추천드려요~

script async
script defer

지금과 같은 경우 DOM을 조작하는 JS 이니 defer 속성을 추가하시면 되겠습니다~

</body>
</html>
85 changes: 85 additions & 0 deletions sign-in.js
Copy link
Collaborator

Choose a reason for hiding this comment

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

💊 제안
로그인에서 사용하는 js 파일과 에러메시지나 로직 측면에서 동일한 것이 많습니다~
이런 경우 중복을 줄이기 위해 반복 사용되는 함수, 정규식, 에러메시지들은 다른 파일로 분리하시고 각 js 파일에서 가져와서 사용하시는 것을 추천드려요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/* login, signup 공통 */

// 이메일 유효성 검사 함수
function emailValidation(email) {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
return emailRegex.test(email);
}
Comment on lines +4 to +7
Copy link
Collaborator

Choose a reason for hiding this comment

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

💊 제안
sign-up.js 파일에서도 동일한 정규식을 사용하고 있는데 그때마다 선언해서 쓰면 문제가 있을 것 같아요.
정규식을 반복해서 선언하면 유지보수가 어려워지고, 코드의 일관성이 떨어질 수 있습니다. 만약 정규식을 수정해야 할 때 여러 곳에서 변경해야 하고 실수로 서로 다른 정규식을 사용할 위험도 커집니다.
이렇게 두개의 파일에서 사용하고 있으니 해당 정규식과 test 함수를 따른 파일로 분리해 사용하시는 것을 추천드려요!


// 요소 가져오기
const emailInput = document.getElementById("email");
const passwordInput = document.getElementById("password");
const emailErr = document.getElementById("emailErr");
const passwordErr = document.getElementById("passwordErr");
const passwordVisibility = document.getElementById("passwordVisibility");
Copy link
Collaborator

Choose a reason for hiding this comment

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

💊 제안
변수명은 해당 변수의 값의 타입을 유추할 수 있는 이름이 좋습니다. isError는 boolean값이라는 것을, emailInput은 input 태그라는 것을 알 수 있습니다. 해당 변수도 emailInput처럼 태그라는 것을 알 수 있게 변경하시는 것을 추천드려요!


// 초기 오류 메시지 숨김
emailErr.textContent = "";
passwordErr.textContent = "";

// 이메일 검증
function validateEmail() {
const emailValue = emailInput.value.trim();
if (emailValue === "") {
emailErr.textContent = "이메일을 입력해주세요.";
emailInput.classList.add("error-input");
emailInput.classList.remove("correct-input");
} else if (!emailValidation(emailValue)) {
emailErr.textContent = "잘못된 이메일 형식입니다.";
emailInput.classList.add("error-input");
emailInput.classList.remove("correct-input");
} else {
emailErr.textContent = "";
emailInput.classList.remove("error-input");
emailInput.classList.add("correct-input");
}
toggleButton();
}

// 비밀번호 검증
function validatePassword() {
const passwordValue = passwordInput.value.trim();
if (passwordValue === "") {
passwordErr.textContent = "비밀번호를 입력해주세요.";
passwordInput.classList.add("error-input");
passwordInput.classList.remove("correct-input");
} else if (passwordValue.length < 8) {
passwordErr.textContent = "비밀번호를 8자 이상 입력해주세요.";
passwordInput.classList.add("error-input");
passwordInput.classList.remove("correct-input");
} else {
passwordErr.textContent = "";
passwordInput.classList.remove("error-input");
passwordInput.classList.add("correct-input");
}
toggleButton();
}

// 비밀번호 보이기/숨기기 기능
function togglePasswordVisibility(input, button) {
if (input.type === "password") {
input.type = "text";
button.innerHTML = '<img src="/images/eye-icon.png" class="eye-icon" alt="eye-off">';
} else {
input.type = "password";
button.innerHTML = '<img src="/images/invisible-eye-icon.png" class="eye-icon" alt="eye-on">';
}
}

// 이벤트 리스너 추가
emailInput.addEventListener("focusout", validateEmail);
passwordInput.addEventListener("focusout", validatePassword);
passwordVisibility.addEventListener("click", () => togglePasswordVisibility(passwordInput, passwordVisibility));

// 엔터 키 입력 시 검증 함수 실행
emailInput.addEventListener("keydown", function(event) {
if (event.key === "Enter") {
validateEmail();
}
});

passwordInput.addEventListener("keydown", function(event) {
if (event.key === "Enter") {
validatePassword();
}
});
133 changes: 133 additions & 0 deletions sign-up.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/* login, signup 공통 */

// 이메일 유효성 검사 함수
function emailValidation(email) {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
return emailRegex.test(email);
}

// 요소 가져오기
const emailInput = document.getElementById("email");
const passwordInput = document.getElementById("password");
const passwordRepeatInput = document.getElementById("password-repeat");
const emailErr = document.getElementById("emailErr");
const passwordErr = document.getElementById("passwordErr");
const passwordCheckErr = document.getElementById("passwordCheckErr");
const passwordVisibility = document.getElementById("passwordVisibility");

let isPasswordCheckTouched = false; // 비밀번호 확인 입력 여부 추적

// 초기 오류 메시지 숨김
emailErr.style.display = "none";
passwordErr.style.display = "none";
passwordCheckErr.style.display = "none";

// 이메일 검증
function validateEmail() {
const emailValue = emailInput.value.trim();
if (emailValue === "") {
emailErr.textContent = "이메일을 입력해주세요.";
emailErr.style.display = "block";
emailInput.classList.add("error-input");
emailInput.classList.remove("correct-input");
} else if (!emailValidation(emailValue)) {
emailErr.textContent = "잘못된 이메일 형식입니다.";
emailErr.style.display = "block";
emailInput.classList.add("error-input");
emailInput.classList.remove("correct-input");
} else {
emailErr.style.display = "none";
emailInput.classList.remove("error-input");
emailInput.classList.add("correct-input");
}
toggleButton();
}

// 비밀번호 검증
function validatePassword() {
const passwordValue = passwordInput.value.trim();
if (passwordValue === "") {
passwordErr.textContent = "비밀번호를 입력해주세요.";
passwordErr.style.display = "block";
passwordInput.classList.add("error-input");
passwordInput.classList.remove("correct-input");
} else if (passwordValue.length < 8) {
passwordErr.textContent = "비밀번호를 8자 이상 입력해주세요.";
passwordErr.style.display = "block";
passwordInput.classList.add("error-input");
passwordInput.classList.remove("correct-input");
} else {
passwordErr.style.display = "none";
passwordInput.classList.remove("error-input");
passwordInput.classList.add("correct-input");
}
toggleButton();
}

// 비밀번호 확인 검증
function validatePasswordCheck() {
const passwordValue = passwordInput.value.trim();
const passwordCheckValue = passwordRepeatInput.value.trim();

if (!isPasswordCheckTouched) {
passwordCheckErr.style.display = "none"; // 입력 전에는 오류 문구 숨김
return;
}

if (passwordCheckValue === "") {
passwordCheckErr.style.display = "none"; // 비밀번호 확인 필드가 비었을 때도 오류 메시지 숨김
} else if (passwordValue !== passwordCheckValue) {
passwordCheckErr.textContent = "비밀번호가 일치하지 않습니다.";
passwordCheckErr.style.display = "block";
passwordRepeatInput.classList.add("error-input");
} else {
passwordCheckErr.style.display = "none";
passwordRepeatInput.classList.remove("error-input");
}
toggleButton();
}

// 비밀번호 보이기/숨기기 기능
function togglePasswordVisibility(input, button) {
if (input.type === "password") {
input.type = "text";
button.innerHTML = '<img src="/images/eye-icon.png" class="eye-icon" alt="eye-off">';
} else {
input.type = "password";
button.innerHTML = '<img src="/images/invisible-eye-icon.png" class="eye-icon" alt="eye-on">';
}
}

// 회원가입 버튼 활성화
function toggleButton() {
const isFormValid =
emailErr.style.display === "none" &&
passwordErr.style.display === "none" &&
passwordCheckErr.style.display === "none" &&
emailInput.value.trim() !== "" &&
passwordInput.value.trim() !== "" &&
passwordRepeatInput.value.trim() !== "";

const signupButton = document.querySelector(".signup");
if (isFormValid) {
signupButton.disabled = false;
signupButton.classList.add("active");
} else {
signupButton.disabled = true;
signupButton.classList.remove("active");
}
Comment on lines +111 to +118
Copy link
Collaborator

Choose a reason for hiding this comment

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

💊 제안
위의 조건같은 경우 아래처럼 작성하셔도 됩니다.

    const signupButton = document.querySelector(".signup");

    signupButton.disabled = !isFormValid;
    signupButton.classList.toggle("active", isFormValid);

}

// 이벤트 리스너 추가
emailInput.addEventListener("focusout", validateEmail);
passwordInput.addEventListener("focusout", validatePassword);
passwordRepeatInput.addEventListener("input", () => {
isPasswordCheckTouched = true; // 사용자가 입력 시작했음을 추적
validatePasswordCheck(); // 입력 시에도 검증 함수 실행
});
passwordRepeatInput.addEventListener("keydown", function(event) {
if (event.key === "Enter") {
validatePasswordCheck();
}
});
passwordVisibility.addEventListener("click", () => togglePasswordVisibility(passwordInput, passwordVisibility));
14 changes: 10 additions & 4 deletions signup.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,30 @@ <h1>판다마켓</h1>
<form>
<div class="group">
<label for="email">이메일</label>
<input type="email" id="email" name="email" placeholder="이메일을 입력해주세요.">
<input type="email" id="email" name="email" placeholder="이메일을 입력해주세요."
class="error-input">
<p id="emailErr" class="errMsg">이메일을 입력해주세요.</p>
</div>
<div class="group">
<label for="username">닉네임</label>
<input type="username" id="username" name="username" placeholder="닉네임을 입력해주세요.">
<p id="nicknameErr" class="errMsg"></p>
</div>
<div class="group">
<label for="password">비밀번호</label>
<div class="password-input">
<input type="password" id="password" name="password" placeholder="비밀번호를 입력해주세요.">
<img src="./image/invisible_icon.png" class="password-icon" alt="비밀번호 보기">
<p id="passwordErr" class="errMsg">비밀번호를 8자 이상 입력해주세요.</p>
</div>
</div>
<div class="group">
<label for="password-repeat">비밀번호 확인</label>
<div class="password-input">
<input id="password-repeat" name="password-repeat" placeholder="비밀번호를 다시 한 번 입력해주세요.">
<img src="./image/eye_icon.png" class="password-icon" alt="비밀번호 보기">
<input id="password-repeat" name="password-repeat" placeholder="비밀번호를 다시 한 번 입력해주세요."
class="error-input">
<img src="./image/eye_icon.png" class="password-icon1" alt="비밀번호 보기">
<p id="passwordCheckErr" class="errMsg">비밀번호가 일치하지 않습니다.</p>
</div>
</div>
<button type="submit">회원가입</button>
Expand All @@ -67,6 +73,6 @@ <h1>간편 로그인하기</h1>


</div>

<script src='./sign-up.js'></script>
</body>
</html>
9 changes: 7 additions & 2 deletions style/sign-in.css
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
.group {
width: 100%;
height: 6.125rem;
margin-bottom: 1rem;
margin-bottom: 3em;
}

.group label {
Expand Down Expand Up @@ -95,7 +95,12 @@
.password-input input {
margin-right: 1.875rem;
}

.errMsg {
display: block;
color: red;
font-size: 1rem;
font-weight: 600;
}
.password-icon {
position: absolute;
top: 50%;
Expand Down
22 changes: 19 additions & 3 deletions style/signup.css
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
width: 100%;
height: 6.125rem;
gap: 10rem;
margin-bottom: 1rem;
margin-bottom: 4em;
}

.group input {
Expand All @@ -76,6 +76,7 @@
letter-spacing: 0%;
color: #9CA3AF;
text-indent: 1.5rem;

}

.group label {
Expand All @@ -87,7 +88,15 @@
line-height: 1.625rem;
letter-spacing: 0%;
}

.errMsg{
display: none;
display: block;
color: red;
font-size: 1rem;
font-weight: 600;

}

.password-input {
position: relative;
}
Expand All @@ -104,7 +113,14 @@
width: 1.5rem;
cursor: pointer;
}

.password-icon1{
position: absolute;
top: 30%;
right: 0.625rem;
transform: translateY(-50%);
width: 1.5rem;
cursor: pointer;
}
button {
width: 40rem;
height: 3.5rem;
Expand Down
Loading