Skip to content

Commit eed77aa

Browse files
Merge pull request #139 from khuyjh/Basic-윤정환-sprint4
[윤정환] sprint4
2 parents 0a494be + fd06a3e commit eed77aa

9 files changed

+289
-18
lines changed

css/common.css

+5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
--color-input: #f3f4f6;
2525
--color-white: #ffffff;
2626
--color-text-login: #1f2937;
27+
--color-error-red: #f74747;
2728

2829
/* Typography */
2930
--font-primary: "Pretendard-Regular", sans-serif;
@@ -58,3 +59,7 @@ body {
5859
background-color: var(--color-disabled);
5960
}
6061
/* 비활성화시에 속성이랑 클래스 둘다 넣어야 함 */
62+
63+
.display-none {
64+
display: none;
65+
}

css/#-#-style.css

+15-1
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,31 @@ main {
4646
font-size: 16px;
4747
}
4848

49+
.form__input.invalid {
50+
border: 1px solid var(--color-error-red);
51+
}
52+
53+
.form__error-msg {
54+
position: relative;
55+
top: -12px;
56+
padding-left: 16px;
57+
color: var(--color-error-red);
58+
font-weight: 500;
59+
font-size: 14px;
60+
}
61+
4962
.input--password {
5063
position: relative;
5164
}
5265

53-
.btn--visibility-off {
66+
.btn--visibility {
5467
border: none;
5568
background-color: var(--color-input);
5669
position: absolute;
5770
top: 16px;
5871
right: 24px;
5972
bottom: 16px;
73+
padding: 0;
6074
}
6175

6276
.btn--interactions {

faq.html

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<!-- -->

index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
/>
1010
<meta property="og:title" content="판다 마켓" />
1111
<meta property="og:type" content="website" />
12-
<meta property="og:image" content="img/panda-market_thumbnail.png" />
12+
<meta property="og:image" content="assets/img/panda-market_thumbnail.png" />
1313
<meta property="og:description" content="일상의 모든 물건을 거래해보세요" />
1414
<title>판다마켓</title>
1515
<link rel="stylesheet" href="css/index-style.css" />

js/btn-functions.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//모든 input의 유효성 검사를 통과했을 때에만 누를 수 있어야하므로 validate와 작동방식이 달라야함
2+
export function toggleBtnStatus() {
3+
const btn = document.querySelector(".btn--interactions");
4+
const errorMessages = document.querySelectorAll(".form__error-msg");
5+
const inputs = document.querySelectorAll(".form__input");
6+
7+
for (const message of errorMessages) {
8+
if (message.textContent) {
9+
btn.setAttribute("disabled", "");
10+
btn.classList.add("btn--disabled");
11+
return;
12+
}
13+
}
14+
for (const input of inputs) {
15+
if (!input.value) {
16+
btn.setAttribute("disabled", "");
17+
btn.classList.add("btn--disabled");
18+
return;
19+
}
20+
}
21+
22+
btn.removeAttribute("disabled");
23+
btn.classList.remove("btn--disabled");
24+
}

js/#-#.js

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import {
2+
isEmpty,
3+
validateEmail,
4+
validatePassword,
5+
validatePasswordConfirm,
6+
validatePasswordConfirmReverse,
7+
validateNickname,
8+
} from "./validate.js";
9+
import { toggleBtnStatus } from "./btn-functions.js";
10+
11+
function toggleVisibility(event) {
12+
const btn = event.target.parentElement;
13+
const passwordInput = btn.previousElementSibling;
14+
const iconOff = btn.children[0];
15+
const iconOn = btn.children[1];
16+
17+
if (passwordInput.getAttribute("type") === "password") {
18+
passwordInput.setAttribute("type", "text");
19+
btn.setAttribute("aria-pressed", "true");
20+
} else {
21+
passwordInput.setAttribute("type", "password");
22+
btn.setAttribute("aria-pressed", "false");
23+
}
24+
iconOff.classList.toggle("display-none");
25+
iconOn.classList.toggle("display-none");
26+
}
27+
28+
function is#Page() {
29+
return window.location.pathname.search("#") === -1 ? false : true;
30+
}
31+
32+
const form = document.querySelector(".container--form");
33+
const validateMap = {
34+
email: validateEmail,
35+
password: validatePassword,
36+
"password-confirm": validatePasswordConfirm,
37+
nickname: validateNickname,
38+
};
39+
40+
form.addEventListener("focusout", (event) => {
41+
const { id } = event.target;
42+
43+
if (validateMap[id]) {
44+
validateMap[id](event);
45+
//비밀번호확인란부터 입력후 비밀번호를 변경할 시 비밀번호 확인 유효성 검사
46+
if (id === "password" && is#Page()) {
47+
const passwordConfirmInput = document.getElementById("password-confirm");
48+
const passwordConfirm = passwordConfirmInput.value;
49+
if (!isEmpty(passwordConfirm)) {
50+
validatePasswordConfirmReverse();
51+
}
52+
}
53+
toggleBtnStatus();
54+
}
55+
});
56+
form.addEventListener("click", (event) => {
57+
if (event.target.classList.contains("form__icon")) {
58+
toggleVisibility(event);
59+
}
60+
});

js/validate.js

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// common functions
2+
export function isEmpty(value) {
3+
return value ? false : true;
4+
}
5+
6+
function addInvalid(input) {
7+
input.classList.add("invalid");
8+
}
9+
10+
function removeInvalid(input) {
11+
input.classList.remove("invalid");
12+
}
13+
14+
// email functions
15+
const emailPattern = /^[A-Za-z0-9_\.\-]+@[A-Za-z0-9\-]+\.[A-Za-z0-9\-]+/;
16+
17+
function checkEmailFormat(email) {
18+
if (emailPattern.test(email)) {
19+
return true;
20+
} else {
21+
return false;
22+
}
23+
}
24+
25+
export function validateEmail(event) {
26+
const emailInput = event.target;
27+
const email = emailInput.value;
28+
let divErrorMessage = document.querySelector(".error-msg--email");
29+
30+
if (isEmpty(email)) {
31+
divErrorMessage.textContent = "이메일을 입력해주세요";
32+
addInvalid(emailInput);
33+
} else if (!checkEmailFormat(email)) {
34+
divErrorMessage.textContent = "잘못된 이메일 형식입니다";
35+
addInvalid(emailInput);
36+
} else {
37+
divErrorMessage.textContent = "";
38+
removeInvalid(emailInput);
39+
}
40+
}
41+
42+
// password functions
43+
function checkPasswordFormat(password) {
44+
if (password.length < 8) {
45+
return false;
46+
} else {
47+
return true;
48+
}
49+
}
50+
51+
function checkPassword(password, passwordConfirm) {
52+
return password === passwordConfirm ? true : false;
53+
}
54+
55+
export function validatePassword(event) {
56+
const passwordInput = event.target;
57+
const password = passwordInput.value;
58+
let divErrorMessage = document.querySelector(".error-msg--password");
59+
60+
if (isEmpty(password)) {
61+
divErrorMessage.textContent = "비밀번호를 입력해주세요";
62+
addInvalid(passwordInput);
63+
} else if (!checkPasswordFormat(password)) {
64+
divErrorMessage.textContent = "비밀번호를 8자 이상 입력해주세요";
65+
addInvalid(passwordInput);
66+
} else {
67+
divErrorMessage.textContent = "";
68+
removeInvalid(passwordInput);
69+
}
70+
}
71+
72+
export function validatePasswordConfirm(event) {
73+
const passwordInput = document.getElementById("password");
74+
const password = passwordInput.value;
75+
const passwordConfirmInput = event.target;
76+
const passwordConfirm = passwordConfirmInput.value;
77+
let divErrorMessage = document.querySelector(".error-msg--password-confirm");
78+
79+
if (!checkPassword(password, passwordConfirm)) {
80+
divErrorMessage.textContent = "비밀번호가 일치하지 않습니다";
81+
addInvalid(passwordConfirmInput);
82+
} else {
83+
divErrorMessage.textContent = "";
84+
removeInvalid(passwordConfirmInput);
85+
}
86+
}
87+
88+
//password유효성 검사를 하면서 password-confirm검사를 하기 위해 event가 아닌 고정으로 값을 가져오도록 함
89+
export function validatePasswordConfirmReverse() {
90+
const passwordInput = document.getElementById("password");
91+
const password = passwordInput.value;
92+
const passwordConfirmInput = document.getElementById("password-confirm");
93+
const passwordConfirm = passwordConfirmInput.value;
94+
let divErrorMessage = document.querySelector(".error-msg--password-confirm");
95+
96+
if (!checkPassword(password, passwordConfirm)) {
97+
divErrorMessage.textContent = "비밀번호가 일치하지 않습니다";
98+
addInvalid(passwordConfirmInput);
99+
} else {
100+
divErrorMessage.textContent = "";
101+
removeInvalid(passwordConfirmInput);
102+
}
103+
}
104+
105+
//nickname functions
106+
export function validateNickname(event) {
107+
const nicknameInput = event.target;
108+
const nickname = nicknameInput.value;
109+
let divErrorMessage = document.querySelector(".error-msg--nickname");
110+
111+
if (isEmpty(nickname)) {
112+
divErrorMessage.textContent = "닉네임을 입력해주세요";
113+
addInvalid(nicknameInput);
114+
} else {
115+
divErrorMessage.textContent = "";
116+
removeInvalid(nicknameInput);
117+
}
118+
}

login.html

+26-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717
<a href="/" class="btn btn--home">판다마켓</a>
1818
</div>
1919

20-
<form action="/" method="post" class="container container--form">
20+
<form
21+
action="/"
22+
method="post"
23+
novalidate
24+
class="container container--form"
25+
>
2126
<label for="email" class="form__label">이메일</label>
2227
<input
2328
id="email"
@@ -28,6 +33,7 @@
2833
placeholder="이메일을 입력해주세요"
2934
class="form__input"
3035
/>
36+
<div class="form__error-msg error-msg--email"></div>
3137

3238
<label for="password" class="form__label">비밀번호</label>
3339
<div class="input--password">
@@ -36,25 +42,39 @@
3642
name="password"
3743
type="password"
3844
required
39-
autocomplete="password"
45+
autocomplete="off"
4046
placeholder="비밀번호를 입력해주세요"
4147
class="form__input"
4248
/>
4349
<button
4450
type="button"
45-
class="btn btn--visibility-off"
51+
class="btn btn--visibility"
4652
aria-label="비밀번호 표시"
4753
aria-pressed="false"
4854
>
4955
<img
5056
src="assets/icons/btn_visibility_off.svg"
5157
alt="비밀번호를 보이지 않게끔 설정하는 눈에 빗금이 쳐진 아이콘입니다."
52-
class="form__img"
58+
class="form__icon"
59+
/>
60+
<img
61+
src="assets/icons/btn_visibility_on.svg"
62+
alt="비밀번호를 보이게끔 설정하는 눈 모양의 아이콘입니다."
63+
class="form__icon display-none"
5364
/>
5465
</button>
5566
</div>
67+
<div class="form__error-msg error-msg--password"></div>
5668

57-
<button type="submit" class="btn btn--interactions">로그인</button>
69+
<!-- onclick 부분은 form제출 기능이 있다면 추후 변경 -->
70+
<button
71+
type="submit"
72+
onclick="location.href='items.html'; return false;"
73+
disabled
74+
class="btn btn--interactions btn--disabled"
75+
>
76+
로그인
77+
</button>
5878
</form>
5979

6080
<div class="container container--easy-login">
@@ -84,5 +104,6 @@
84104
<a class="text--url" href="#.html">회원가입</a>
85105
</div>
86106
</main>
107+
<script type="module" defer src="js/#-#.js"></script>
87108
</body>
88109
</html>

0 commit comments

Comments
 (0)