Skip to content

Commit

Permalink
Merge pull request #94 from codesquad-memeber-2020/feature/fe/validate
Browse files Browse the repository at this point in the history
[#21] Feat: 유효성 검증 중간 PR
  • Loading branch information
sungik-choi authored Mar 26, 2020
2 parents 85d91ae + 6e3fd44 commit 2ff5692
Show file tree
Hide file tree
Showing 22 changed files with 381 additions and 1,055 deletions.
1,033 changes: 5 additions & 1,028 deletions FE/package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion FE/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,8 @@
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3"
},
"keywords": []
"keywords": [],
"dependencies": {
"node-fetch": "^2.6.0"
}
}
1 change: 1 addition & 0 deletions FE/src/home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./scss/home.scss";
1 change: 0 additions & 1 deletion FE/src/main.js

This file was deleted.

57 changes: 57 additions & 0 deletions FE/src/modules/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
export const PATTERN = {
userId: /^[a-z0-9-_]{5,20}$/,
password: {
all: /^(?=.*[A-Za-z])(?=.*d)(?=.*[!@#$%^&*_+~])[A-Za-zd!@#$%^&*_+~]{8,16}$/,
upperCase: /(.*[A-Z])/,
number: /(.*[0-9])/,
sign: /(.*[!@#$%^&*_+~])/,
},
email: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
phoneNumber: /^(010)(\d{7,8})$/,
birthday: /^(0-9)$/,
};

export const LIMITED_LENGTH = {
userId: 20,
password_min: 8,
password_max: 16,
year: 4,
age_min: 15,
age_max: 99,
};

export const FORM_ID = {
userId: "#userId",
password: "#password",
checkPassword: "#check-password",
email: "#email",
phoneNumber: "#phoneNumber",
name: "#name",
year: "#year",
month: "#month",
day: "#day",
gender: "#gender",
interest: "#interest",
};

export const ERROR_MSG_ID = {
userId: "#error-msg-id",
password: "#error-msg-password",
checkPassword: "#error-msg-check-password",
email: "#error-msg-email",
phoneNumber: "#error-msg-phone",
birthday: "#error-msg-birthday",
interest: "#error-msg-interest",
};

export const TOGGLE_CLASS = {
pass: "pass",
error: "error",
focus: "forus",
hidden: "hidden",
disabled: "disabled",
};

export const NUM_KEY_CODE_ZERO = 48;

export const NUM_KEY_CODE_NINE = 57;
152 changes: 152 additions & 0 deletions FE/src/modules/inputFields.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { PATTERN, FORM_ID, LIMITED_LENGTH, ERROR_MSG_ID } from "./constants.js";
import app from "./server.js";
import { _q, daysInMonth } from "./util.js";

export default {
userId: {
inputElement: _q(FORM_ID.userId),
timeout: null,
selectErrorMessage() {
if (!this.isFieldValid()) return this.errorMessage.misMatch;
if (this.isDuplicate()) return this.errorMessage.duplicate;
return null;
},
isFieldValid() {
const userId = this.inputElement.value;
const userIdRegex = PATTERN.userId;
return userId !== "" && userIdRegex.test(userId);
},
isDuplicate() {
return app.checkDuplicate(this.inputElement.value);
},
errorMessage: {
misMatch: "5~20자의 영문 소문자, 숫자와 특수기호(_)(-) 만 사용 가능합니다.",
duplicate: "이미 사용중인 아이디입니다.",
},
errorMessageElement: _q(ERROR_MSG_ID.userId),
passMessage: "사용 가능한 아이디입니다.",
},

password: {
inputElement: _q(FORM_ID.password),
selectErrorMessage() {
const password = this.inputElement.value;
if (password.length < LIMITED_LENGTH.password_min || password.length > LIMITED_LENGTH.password_max) {
return this.errorMessage.range;
}
if (!PATTERN.password.upperCase.test(password)) {
return this.errorMessage.upperCase;
}
if (!PATTERN.password.number.test(password)) {
return this.errorMessage.number;
}
if (!PATTERN.password.sign.test(password)) {
return this.errorMessage.sign;
}
return null;
},
errorMessage: {
range: "8자 이상 16자 이하로 입력해주세요.",
upperCase: "영문 대문자를 최소 1자 이상 포함해주세요.",
number: "숫자를 최소 1자 이상 포함해주세요.",
sign: "특수문자를 최소 1자 이상 포함해주세요.",
},
errorMessageElement: _q(ERROR_MSG_ID.password),
passMessage: "안전한 비밀번호입니다.",
},

checkPassword: {
inputElement: _q(FORM_ID.checkPassword),
isFieldValid() {
const password = _q(FORM_ID.password).value;
const checkPassword = this.inputElement.value;
return password === checkPassword;
},
selectErrorMessage() {
if (!this.isFieldValid()) return this.errorMessage;
return null;
},
errorMessageElement: _q(ERROR_MSG_ID.checkPassword),
errorMessage: "비밀번호가 일치하지 않습니다.",
passMessage: "비밀번호가 일치합니다.",
},

birthDay: {
inputElement: {
year: _q(FORM_ID.year),
month: _q(FORM_ID.month),
day: _q(FORM_ID.day),
},
selectErrorMessage() {
const year = this.inputElement.year.value;
const month = this.inputElement.month.value;
const day = this.inputElement.day.value;
const today = new Date();
const thisYear = today.getFullYear();
const age = thisYear - year + 1;
if (!this.isValidYear(age)) return this.errorMessage.year;
if (!this.isValidAge(age, month)) return this.errorMessage.age;
if (this.isValidDayinMonth(month, day)) return this.errorMessage.day;
return null;
},
isValidYear(age) {
if (age >= LIMITED_LENGTH.age_min && age <= LIMITED_LENGTH.age_max) return true;
return false;
},
isValidAge(age, month) {
if (age >= LIMITED_LENGTH.age_min) return true;
return false;
},
isValidDayinMonth(month, day) {
const validDay = daysInMonth(month);
if (day < 1 || day > validDay) return true;
return false;
},
errorMessageElement: _q(ERROR_MSG_ID.birthday),
errorMessage: {
year: "태어난 년도 4자리를 정확하게 입력하세요.",
age: "만 14세 이상만 가입 가능합니다.",
day: "태어난 날짜를 다시 확인해주세요.",
},
passMessage: "",
},

name: {
inputElement: _q(FORM_ID.name),
selectErrorMessage() {
return null;
},
},

email: {
inputElement: _q(FORM_ID.email),
selectErrorMessage() {
if (!this.isFieldValid()) return this.errorMessage;
return null;
},
isFieldValid() {
const email = this.inputElement.value;
const emailRegexp = PATTERN.email;
return email !== "" && emailRegexp.test(email);
},
errorMessageElement: _q(ERROR_MSG_ID.email),
errorMessage: "이메일 주소를 다시 확인해주세요.",
passMessage: "",
},

phoneNumber: {
inputElement: _q(FORM_ID.phoneNumber),
selectErrorMessage() {
if (!this.isFieldValid()) return this.errorMessage;
return null;
},
isFieldValid() {
const phoneNumber = this.inputElement.value;
const phoneNumberRegexp = PATTERN.phoneNumber;
return phoneNumber !== "" && phoneNumberRegexp.test(phoneNumber);
},
errorMessageElement: _q(ERROR_MSG_ID.phoneNumber),
errorMessage: "형식에 맞지 않는 번호입니다.",
passMessage: "",
},
};
26 changes: 26 additions & 0 deletions FE/src/modules/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const fetch = require("node-fetch");

const URL = "https://test-codesquad-team1-sign-up.herokuapp.com/";

export default {
checkDuplicate: value => {
fetch(`${URL}users/duplicate/id/${value}`, {
mode: "no-cors",
})
.then(response => response.json())
.then(json => console.log(json));
},
send: userData => {
fetch(`${URL}api/users/create`, {
method: "POST",
mode: "no-cors",
body: JSON.stringify(userData),
headers: {
"Content-Type": "application/json",
},
})
.then(res => res.json())
.then(response => console.log("Success:", JSON.stringify(response)))
.catch(error => console.error("Error:", error));
},
};
15 changes: 15 additions & 0 deletions FE/src/modules/userData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export default new Map([
["userId", null],
["password", null],
["checkPassword", null],
["name", null],
["year", null],
["month", null],
["day", null],
["birthDay", null],
["gender", null],
["email", null],
["phoneNumber", null],
["interest", null],
["terms", null],
]);
29 changes: 29 additions & 0 deletions FE/src/modules/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export const _q = str => {
return document.querySelector(str);
};

export const _qa = str => {
return document.querySelectorAll(str);
};

export const pipe = (...fns) => value => fns.reduce((acc, fn) => fn(acc), value);

export const daysInMonth = num => {
switch (num) {
case "2":
return 28;
case "4":
case "6":
case "9":
case "11":
return 30;
default:
return 31;
}
};

export const toggleClass = (target = null, addClassName, removeClassName) => {
if (!target || target.classList.contains(addClassName)) return;
target.classList.add(addClassName);
target.classList.remove(removeClassName);
};
56 changes: 56 additions & 0 deletions FE/src/modules/validation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import inputFields from "./inputFields.js";
import userData from "./userData.js";
import { _q, toggleClass } from "./util.js";
import { NUM_KEY_CODE_ZERO, NUM_KEY_CODE_NINE, TOGGLE_CLASS } from "./constants.js";

const generateErrorMessage = (element = null, message) => {
if (!element) return;
element.innerHTML = message;
};

const setUserData = (key, value) => {
return userData.set(key, value);
};

const validateInputForms = event => {
Object.keys(inputFields).forEach(field => {
const currentField = inputFields[field];
if (event.target === currentField.inputElement) {
let errorMessage = currentField.selectErrorMessage();
const messageElement = currentField.errorMessageElement;
if (errorMessage === null) {
const inputValue = currentField.inputElement.value;
const { passMessage } = currentField;
errorMessage = passMessage;
setUserData(field, inputValue);
toggleClass(messageElement, TOGGLE_CLASS.pass, TOGGLE_CLASS.error);
} else {
setUserData(field, null);
toggleClass(messageElement, TOGGLE_CLASS.error, TOGGLE_CLASS.pass);
}
generateErrorMessage(messageElement, errorMessage);
}
});
};

const preventKeypressExceptNum = event => {
const { year } = inputFields.birthDay.inputElement;
const { day } = inputFields.birthDay.inputElement;
const phoneNumber = inputFields.phoneNumber.inputElement;
if (event.target === year || event.target === day || event.target === phoneNumber) {
if (event.keyCode < NUM_KEY_CODE_ZERO || event.keyCode > NUM_KEY_CODE_NINE) {
event.returnValue = false;
}
}
};

const signupForm = _q("form");
const buttons = _q(".btn-wrap");

signupForm.addEventListener("input", event => validateInputForms(event));
signupForm.addEventListener("keypress", event => preventKeypressExceptNum(event));

buttons.addEventListener("click", event => {
event.preventDefault();
if (event.target === _q(".submit-btn")) console.log(userData);
});
File renamed without changes.
2 changes: 2 additions & 0 deletions FE/scss/home.scss → FE/src/scss/home.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@import "./main.scss";

.signout-btn {
margin-top: $input-gap * 4;
}
Expand Down
2 changes: 0 additions & 2 deletions FE/scss/main.scss → FE/src/scss/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,3 @@
@import "./common.scss";
@import "./modal.scss";
@import "./toggle-class.scss";
@import "./login.scss";
@import "./home.scss";
2 changes: 0 additions & 2 deletions FE/scss/modal.scss → FE/src/scss/modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
top: 0;
left: 0;
z-index: 1;
opacity: 1;
transition: opacity 0.2s ease;
}

.modal {
Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions FE/scss/login.scss → FE/src/scss/signin.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@import "./main.scss";

.signin-btn {
margin-top: $input-gap * 4;
}
Expand Down
3 changes: 1 addition & 2 deletions FE/scss/toggle-class.scss → FE/src/scss/toggle-class.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
}

.hidden {
visibility: hidden;
opacity: 0;
display: none;
}

.disabled {
Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions FE/src/signin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./scss/signin.scss";
Loading

0 comments on commit 2ff5692

Please sign in to comment.