Skip to content
Open
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
8 changes: 0 additions & 8 deletions data/users.js

This file was deleted.

6 changes: 4 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
<link rel="stylesheet" href="styles/reset.css" />
<link rel="stylesheet" href="styles/common.css" />
<link rel="stylesheet" href="index.css" />

<script defer type="module" src="index.js"></script>
</head>
<body>
<header class="bgc-blue">
Expand All @@ -54,7 +56,7 @@
src="images/icons/logo.svg"
alt="링크브러리 로고" />
</a>
<a class="cta gnb__signin" href="pages/member/signin">로그인</a>
<a class="cta gnb__signin" href="pages/auth/signin">로그인</a>
</div>
</nav>

Expand All @@ -65,7 +67,7 @@ <h1 class="hero__heading">
>를<br />
쉽게 저장하고 관리해 보세요
</h1>
<a class="cta hero__signup" href="pages/member/signup">링크 추가하기</a>
<a class="cta hero__signup" href="pages/auth/signup">링크 추가하기</a>
<div class="hero__img">
<img
class="hero__img--img"
Expand Down
21 changes: 21 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const signInAnchor = document.querySelector(".gnb__signin");
const signUpAnchor = document.querySelector(".hero__signup");

signInAnchor.addEventListener("click", (e) => {
e.preventDefault();
navigateFolderPage("/pages/auth/signin/");
});

signUpAnchor.addEventListener("click", (e) => {
e.preventDefault();
navigateFolderPage("/pages/auth/signup/");
});

function navigateFolderPage(href) {
if (localStorage.getItem("accessToken")) {
location.href = "/pages/folder/";
return;
}

location.href = href;
}
Comment on lines +14 to +21
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

오 이런 방법도 생각해 볼 수 있겠군요! 좋습니다 ㅎㅎ

나중 얘기지만 도움이 될 수 있을 부분일거 같아 미리 말씀드리면
통신 과정에서 사용자의 인증을 위해 헤더에 토큰을 넣어서 함께 보내는 경우가 많이 있습니다.
이 과정에서 axios를 이용한 인터셉터를 적용할 수 있는데,
인터셉터는 통신 전 해당 요청을 가로채서 어떠한 작업을 거친 후 다시 통신을 보내는 방식을 뜻합니다.

지금 구현한 기능과는 조금 방식이 다르지만, 어쨋든 지금도 페이지 이동 전 토큰 유무를 확인한 뒤
그에 따라 페이지를 이동하는 것이라서 어떻게 보면 작은 인터셉터라고도 할 수 있겠네요 ㅎㅎㅎ
갑자기 생각나서 해당 내용에 대해 전달드려봅니다..ㅎㅎ

인터셉터와 관련된 글도 링크로 전달드릴테니, 차후에 한번 적용해보세요!
https://www.timegambit.com/blog/digging/axios/01

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

오 좀 더 확실한 방법이겠네요!
제가 한 방식은 직접 url을 입력해서 접근하는 방식에는 통하지 않아서..ㅋㅋㅋ
지식 전수 감사합니다!:smile:

12 changes: 12 additions & 0 deletions pages/auth/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { fetchApi } from "/scripts/fetchApi.js";

const postSignIn = (email, password) =>
fetchApi.post("/sign-in", { body: { email, password } });

const postCheckEmail = (email) =>
fetchApi.post("/check-email", { body: { email } });

const postSignUp = (email, password) =>
fetchApi.post("/sign-up", { body: { email, password } });

export { postCheckEmail, postSignIn, postSignUp };
File renamed without changes.
58 changes: 40 additions & 18 deletions pages/member/sign.js → pages/auth/sign.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import users from "/data/users.js";
import { postCheckEmail } from "./api.js";
import { isEmptyString } from "/scripts/utils.js";

const errorMessage = {
Expand All @@ -18,38 +18,54 @@ const errorMessage = {
},
};

function handleErrorMessage(element, addOrRemoveHide, errorMessage = "") {
const parent = element.parentElement;
const errorMessageSpan = parent.querySelector(".input-error__message");
function handleErrorMessage(target, errorMessage = "") {
const parent = target.parentElement;
let errorMessageSpan = parent.querySelector(".input-error__message");

if (isEmptyString(errorMessage) && !errorMessageSpan) {
return;
}

if (!errorMessageSpan) {
errorMessageSpan = document.createElement("span");
errorMessageSpan.classList.add("input-error__message");
target.after(errorMessageSpan);
errorMessageSpan.textContent = errorMessage;
return;
}

if (isEmptyString(errorMessage)) {
errorMessageSpan.remove();
return;
}

errorMessageSpan.textContent = errorMessage;
errorMessageSpan.classList[addOrRemoveHide]("hide");
}

function inputValidationFailed(target, errorMessage, eyeIcon) {
target.classList.add("input-error");
handleErrorMessage(target, "remove", errorMessage);
handleErrorMessage(target, errorMessage);
if (eyeIcon) {
eyeIcon.classList.add("eye-icon__error");
}
}

function inputValidationSucceeded(target, eyeIcon) {
target.classList.remove("input-error");
handleErrorMessage(target, "add");
handleErrorMessage(target);
if (eyeIcon) {
eyeIcon.classList.remove("eye-icon__error");
}
}

function checkEmailValid(element, checkExist = true) {
async function checkEmailValid(element, checkExist = true) {
if (isEmptyString(element.value)) {
return errorMessage.email.empty;
}
if (!isEmailValid(element.value)) {
return errorMessage.email.valid;
}
if (checkExist && isEmailExist(element.value)) {
if (checkExist && (await isEmailExist(element.value))) {
return errorMessage.email.exist;
}
return "";
Expand Down Expand Up @@ -82,14 +98,16 @@ function isPasswordValid(password) {
return password.trim().length >= 8 && regex.test(password);
}

function isEmailExist(email) {
return users.some((user) => user.email === email);
}

function isMemberExist(member) {
return users.some(
(user) => user.email === member.email && user.password === member.password
);
async function isEmailExist(email) {
let emailExist = true;
try {
await postCheckEmail(email);
emailExist = false;
} catch (error) {
console.error(`${error.name}: ${error.message}`);
} finally {
return emailExist;
}
}

function changePasswordVisibility(passwordInput) {
Expand All @@ -104,6 +122,10 @@ function changePasswordVisibility(passwordInput) {
};
}

function setUserAccessToken({ data }) {
localStorage.setItem("accessToken", data.accessToken);
}

export {
changePasswordVisibility,
checkEmailValid,
Expand All @@ -112,5 +134,5 @@ export {
errorMessage,
inputValidationFailed,
inputValidationSucceeded,
isMemberExist,
setUserAccessToken,
};
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@
name="email"
required
placeholder="이메일을 입력해주세요." />
<span class="input-error__message hide"></span>
</div>
<div class="form__password">
<label class="form__label" for="input-password">비밀번호</label>
Expand All @@ -83,7 +82,6 @@
class="form__input--eye-off eye-icon"
type="button"
aria-label="패스워드 보이기"></button>
<span class="input-error__message hide"></span>
</div>

<button class="cta form__submit" type="submit">로그인</button>
Expand Down
96 changes: 96 additions & 0 deletions pages/auth/signin/signin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import {
changePasswordVisibility,
checkEmailValid,
checkPasswordValid,
errorMessage,
inputValidationFailed,
inputValidationSucceeded,
setUserAccessToken,
} from "../sign.js";

import { postSignIn } from "../api.js";
import { isEmptyString } from "/scripts/utils.js";

navigateFolderPage("pages/auth/signin/");

/**
* email input
*/
const emailInput = document.querySelector("#input-email");
emailInput.addEventListener("focusout", onEmailFocusout);

async function onEmailFocusout({ target }) {
const errorMessage = await checkEmailValid(target, false);
if (!isEmptyString(errorMessage)) {
inputValidationFailed(target, errorMessage);
return false;
}

inputValidationSucceeded(target);
return true;
}

/**
* password input
*/
const passwordInput = document.querySelector("#input-password");
const passwordEyeIcon = document.querySelector(
".form__password .form__input--eye-off"
);

passwordInput.addEventListener("focusout", onPasswordFocusout);

function onPasswordFocusout({ target }) {
const errorMessage = checkPasswordValid(target);
if (!isEmptyString(errorMessage)) {
inputValidationFailed(target, errorMessage, passwordEyeIcon);
return false;
}

inputValidationSucceeded(target, passwordEyeIcon);
return true;
}

passwordEyeIcon.addEventListener(
"click",
changePasswordVisibility(passwordInput)
);

/**
* form
*/
const form = document.querySelector(".form");

form.addEventListener("submit", onSubmit);

function onSubmit(e) {
e.preventDefault();

const validResult =
onEmailFocusout({ target: emailInput }) &&
onPasswordFocusout({ target: passwordInput });

if (!validResult) {
return;
}

doSignIn(emailInput.value, passwordInput.value);
}

async function doSignIn(email, password) {
try {
const signInResponse = await postSignIn(email, password);
setUserAccessToken(signInResponse);
location.href = "/pages/folder";
} catch (error) {
console.error(`${error.name}: ${error.message}`);
if (error.name === "AuthApiError") {
inputValidationFailed(emailInput, errorMessage.email.loginFailed);
inputValidationFailed(
passwordInput,
errorMessage.password.loginFailed,
passwordEyeIcon
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
name="email"
required
placeholder="이메일을 입력해주세요." />
<span class="input-error__message hide"></span>
</div>
<div class="form__password">
<label class="form__label" for="input-password">비밀번호</label>
Expand All @@ -84,7 +83,6 @@
class="form__input--eye-off eye-icon"
type="button"
aria-label="패스워드 감추기"></button>
<span class="input-error__message hide"></span>
</div>
<div class="form__password-chk">
<label class="form__label" for="input-password-chk">
Expand All @@ -103,7 +101,6 @@
class="form__input--eye-off eye-icon"
type="button"
aria-label="패스워드 감추기"></button>
<span class="input-error__message hide"></span>
</div>

<button class="cta form__submit" type="submit">회원가입</button>
Expand Down
Loading