Skip to content

Commit

Permalink
refactor: 상수 적용, 로컬스토리지 핸들러 분리 등 리팩토링 진행
Browse files Browse the repository at this point in the history
  • Loading branch information
9yurilee committed Dec 18, 2024
1 parent ac4e194 commit 461a27f
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 51 deletions.
9 changes: 5 additions & 4 deletions src/components/common/Header.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { ROUTES } from "../../constants/routes";
import { state } from "../../store/store";

const Header = () => {
const LoginMenu = (isLoggedIn) => {
return isLoggedIn
? `
<li><a href="/profile" class="text-gray-600">프로필</a></li>
<li><a href="/login" id="logout" class="text-gray-600">로그아웃</a></li>
<li><a href=${ROUTES.PROFILE} class="text-gray-600">프로필</a></li>
<li><a href=${ROUTES.LOGIN} id="logout" class="text-gray-600">로그아웃</a></li>
`
: `
<li><a href="/login" class="text-gray-600">로그인</a></li>
<li><a href=${ROUTES.LOGIN} class="text-gray-600">로그인</a></li>
`;
};

Expand All @@ -19,7 +20,7 @@ const Header = () => {
<nav class="bg-white shadow-md p-2 sticky top-14">
<ul class="flex justify-around">
<li><a href="/" class="text-blue-600 font-bold">홈</a></li>
<li><a href=${ROUTES.HOME} class="text-blue-600 font-bold">홈</a></li>
${LoginMenu(state.user)}
</ul>
</nav>
Expand Down
4 changes: 3 additions & 1 deletion src/components/pages/ErrorPage.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ROUTES } from "../../constants/routes";

export const ErrorPage = () => `
<main class="bg-gray-100 flex items-center justify-center min-h-screen">
<div class="bg-white p-8 rounded-lg shadow-md w-full text-center" style="max-width: 480px">
Expand All @@ -7,7 +9,7 @@ export const ErrorPage = () => `
<p class="text-gray-600 mb-8">
요청하신 페이지가 존재하지 않거나 이동되었을 수 있습니다.
</p>
<a href="/" class="bg-blue-600 text-white px-4 py-2 rounded font-bold">
<a href=${ROUTES.HOME} class="bg-blue-600 text-white px-4 py-2 rounded font-bold">
홈으로 돌아가기
</a>
</div>
Expand Down
5 changes: 5 additions & 0 deletions src/constants/routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const ROUTES = {
HOME: "/",
LOGIN: "/login",
PROFILE: "/profile",
};
10 changes: 6 additions & 4 deletions src/events/login.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { router } from "../router/router.js";
import { ROUTES } from "../constants/routes.js";
import { navigateTo } from "../router/router.js";
import { setState } from "../store/store.js";
import { setStorage } from "../utils/storageHandler.js";

export const handleLogin = () => {
const username = document.getElementById("username").value;

Check failure on line 7 in src/events/login.js

View workflow job for this annotation

GitHub Actions / basic

Unhandled error

TypeError: Cannot read properties of null (reading 'value') ❯ handleLogin src/events/login.js:7:55 ❯ HTMLBodyElement.<anonymous> src/events/login.js:30:5 ❯ HTMLBodyElement.callTheUserObjectsOperation node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30 ❯ innerInvokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25 ❯ invokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3 ❯ HTMLFormElementImpl._dispatch node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9 ❯ HTMLFormElementImpl.dispatchEvent node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17 ❯ HTMLFormElement.dispatchEvent node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34 ❯ src/__tests__/basic.test.js:82:17 ❯ node_modules/@vitest/runner/dist/index.js:533:5 This error originated in "src/__tests__/basic.test.js" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "로그인 폼에서 사용자 이름을 입력하고 제출하면 로그인 되고, 로그아웃 버튼 클릭시 로그아웃 된다.". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.

Check failure on line 7 in src/events/login.js

View workflow job for this annotation

GitHub Actions / basic

Unhandled error

TypeError: Cannot read properties of null (reading 'value') ❯ handleLogin src/events/login.js:7:55 ❯ HTMLBodyElement.<anonymous> src/events/login.js:30:5 ❯ HTMLBodyElement.callTheUserObjectsOperation node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30 ❯ innerInvokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25 ❯ invokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3 ❯ HTMLFormElementImpl._dispatch node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9 ❯ HTMLFormElementImpl.dispatchEvent node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17 ❯ HTMLFormElement.dispatchEvent node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34 ❯ src/__tests__/basic.test.js:105:17 ❯ callSuiteHook node_modules/@vitest/runner/dist/index.js:964:22 This error originated in "src/__tests__/basic.test.js" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "로그인한 사용자의 이름과 소개가 표시된다". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.

Check failure on line 7 in src/events/login.js

View workflow job for this annotation

GitHub Actions / basic

Unhandled error

TypeError: Cannot read properties of null (reading 'value') ❯ handleLogin src/events/login.js:7:55 ❯ HTMLBodyElement.<anonymous> src/events/login.js:30:5 ❯ HTMLBodyElement.callTheUserObjectsOperation node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30 ❯ innerInvokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25 ❯ invokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3 ❯ HTMLFormElementImpl._dispatch node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9 ❯ HTMLFormElementImpl.dispatchEvent node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17 ❯ HTMLFormElement.dispatchEvent node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34 ❯ src/__tests__/basic.test.js:105:17 ❯ callSuiteHook node_modules/@vitest/runner/dist/index.js:964:22 This error originated in "src/__tests__/basic.test.js" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "로그인한 사용자의 이름과 소개가 표시된다". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.

Check failure on line 7 in src/events/login.js

View workflow job for this annotation

GitHub Actions / basic

Unhandled error

TypeError: Cannot read properties of null (reading 'value') ❯ handleLogin src/events/login.js:7:55 ❯ HTMLBodyElement.<anonymous> src/events/login.js:30:5 ❯ HTMLBodyElement.callTheUserObjectsOperation node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30 ❯ innerInvokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25 ❯ invokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3 ❯ HTMLFormElementImpl._dispatch node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9 ❯ HTMLFormElementImpl.dispatchEvent node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17 ❯ HTMLFormElement.dispatchEvent node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34 ❯ src/__tests__/basic.test.js:105:17 ❯ callSuiteHook node_modules/@vitest/runner/dist/index.js:964:22 This error originated in "src/__tests__/basic.test.js" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "로그인한 사용자의 이름과 소개가 표시된다". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.

Check failure on line 7 in src/events/login.js

View workflow job for this annotation

GitHub Actions / basic

Unhandled error

TypeError: Cannot read properties of null (reading 'value') ❯ handleLogin src/events/login.js:7:55 ❯ HTMLBodyElement.<anonymous> src/events/login.js:30:5 ❯ HTMLBodyElement.callTheUserObjectsOperation node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30 ❯ innerInvokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25 ❯ invokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3 ❯ HTMLFormElementImpl._dispatch node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9 ❯ HTMLFormElementImpl.dispatchEvent node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17 ❯ HTMLFormElement.dispatchEvent node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34 ❯ src/__tests__/basic.test.js:105:17 ❯ callSuiteHook node_modules/@vitest/runner/dist/index.js:964:22 This error originated in "src/__tests__/basic.test.js" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "프로필 수정 기능이 동작한다". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.

Check failure on line 7 in src/events/login.js

View workflow job for this annotation

GitHub Actions / basic

Unhandled error

TypeError: Cannot read properties of null (reading 'value') ❯ handleLogin src/events/login.js:7:55 ❯ HTMLBodyElement.<anonymous> src/events/login.js:30:5 ❯ HTMLBodyElement.callTheUserObjectsOperation node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30 ❯ innerInvokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25 ❯ invokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3 ❯ HTMLFormElementImpl._dispatch node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9 ❯ HTMLFormElementImpl.dispatchEvent node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17 ❯ HTMLFormElement.dispatchEvent node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34 ❯ src/__tests__/basic.test.js:105:17 ❯ callSuiteHook node_modules/@vitest/runner/dist/index.js:964:22 This error originated in "src/__tests__/basic.test.js" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "프로필 수정 기능이 동작한다". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.

Check failure on line 7 in src/events/login.js

View workflow job for this annotation

GitHub Actions / basic

Unhandled error

TypeError: Cannot read properties of null (reading 'value') ❯ handleLogin src/events/login.js:7:55 ❯ HTMLBodyElement.<anonymous> src/events/login.js:30:5 ❯ HTMLBodyElement.callTheUserObjectsOperation node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30 ❯ innerInvokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25 ❯ invokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3 ❯ HTMLFormElementImpl._dispatch node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9 ❯ HTMLFormElementImpl.dispatchEvent node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17 ❯ HTMLFormElement.dispatchEvent node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34 ❯ src/__tests__/basic.test.js:105:17 ❯ callSuiteHook node_modules/@vitest/runner/dist/index.js:964:22 This error originated in "src/__tests__/basic.test.js" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "프로필 수정 기능이 동작한다". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.

Check failure on line 7 in src/events/login.js

View workflow job for this annotation

GitHub Actions / basic

Unhandled error

TypeError: Cannot read properties of null (reading 'value') ❯ handleLogin src/events/login.js:7:55 ❯ HTMLBodyElement.<anonymous> src/events/login.js:30:5 ❯ HTMLBodyElement.callTheUserObjectsOperation node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30 ❯ innerInvokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25 ❯ invokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3 ❯ HTMLFormElementImpl._dispatch node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9 ❯ HTMLFormElementImpl.dispatchEvent node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17 ❯ HTMLFormElement.dispatchEvent node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34 ❯ src/__tests__/basic.test.js:105:17 ❯ callSuiteHook node_modules/@vitest/runner/dist/index.js:964:22 This error originated in "src/__tests__/basic.test.js" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "프로필 수정 기능이 동작한다". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.

Check failure on line 7 in src/events/login.js

View workflow job for this annotation

GitHub Actions / basic

Unhandled error

TypeError: Cannot read properties of null (reading 'value') ❯ handleLogin src/events/login.js:7:55 ❯ HTMLBodyElement.<anonymous> src/events/login.js:30:5 ❯ HTMLBodyElement.callTheUserObjectsOperation node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30 ❯ innerInvokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25 ❯ invokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3 ❯ HTMLFormElementImpl._dispatch node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9 ❯ HTMLFormElementImpl.dispatchEvent node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17 ❯ HTMLFormElement.dispatchEvent node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34 ❯ src/__tests__/basic.test.js:105:17 ❯ callSuiteHook node_modules/@vitest/runner/dist/index.js:964:22 This error originated in "src/__tests__/basic.test.js" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "프로필 수정 기능이 동작한다". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.

Check failure on line 7 in src/events/login.js

View workflow job for this annotation

GitHub Actions / basic

Unhandled error

TypeError: Cannot read properties of null (reading 'value') ❯ handleLogin src/events/login.js:7:55 ❯ HTMLBodyElement.<anonymous> src/events/login.js:30:5 ❯ HTMLBodyElement.callTheUserObjectsOperation node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30 ❯ innerInvokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:350:25 ❯ invokeEventListeners node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3 ❯ HTMLFormElementImpl._dispatch node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9 ❯ HTMLFormElementImpl.dispatchEvent node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17 ❯ HTMLFormElement.dispatchEvent node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34 ❯ src/__tests__/basic.test.js:145:17 ❯ callSuiteHook node_modules/@vitest/runner/dist/index.js:964:22 This error originated in "src/__tests__/basic.test.js" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. The latest test that might've caused the error is "Header, Footer 컴포넌트가 메인 페이지와 프로필 페이지에 존재하고, 로그인페이지와 에러페이지에는 존재하지 않는다.". It might mean one of the following: - The error was thrown, while Vitest was running this test. - If the error occurred after the test had been completed, this was the last documented test before it was thrown.
Expand All @@ -9,9 +11,9 @@ export const handleLogin = () => {
if (username) {
setState({ user: userInfo }); // 상태 업데이트

localStorage.setItem("user", JSON.stringify(userInfo));
history.pushState({}, "", "/");
router();
setStorage("user", userInfo);

navigateTo(ROUTES.HOME);
} else {
alert("아이디 혹은 비밀번호를 확인해주세요.");
}
Expand Down
31 changes: 12 additions & 19 deletions src/events/navigation.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
import { router } from "../router/router.js";
import { ROUTES } from "../constants/routes.js";
import { navigateTo } from "../router/router.js";
import { clearStorage } from "../utils/storageHandler.js";
import { setState } from "./../store/store";

const navigateTo = (path) => {
history.pushState({}, "", path);
router();
};

export const handleNavigation = (e) => {
e.preventDefault();

const selected = e.target.closest("a");
if (!selected) return;

if (selected) {
const isLogoutBtn = selected.hasAttribute("id") && selected.id === "logout";
const isLogoutBtn = selected.hasAttribute("id") && selected.id === "logout";

if (isLogoutBtn) {
localStorage.removeItem("user");
setState({ user: null }); // 상태 초기화
navigateTo("/login");
} else {
// 로그아웃 외 네비게이션 메뉴들
const path = selected.getAttribute("href");
navigateTo(path);
}
if (isLogoutBtn) {
clearStorage();
setState({ user: null }); // 상태 초기화
navigateTo(ROUTES.LOGIN);
} else {
const path = selected.getAttribute("href");
navigateTo(path);
}
};

Expand Down
3 changes: 2 additions & 1 deletion src/events/profile.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { setStorage } from "../utils/storageHandler";
import { setState } from "./../store/store";

const handleProfileUpdate = () => {
Expand All @@ -11,7 +12,7 @@ const handleProfileUpdate = () => {
bio: bioInput,
};

localStorage.setItem("user", JSON.stringify(updatedInfo));
setStorage("user", updatedInfo);

setState({ user: updatedInfo });
};
Expand Down
10 changes: 2 additions & 8 deletions src/main.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import { router } from "./router/router.js";
import { setState } from "./store/store.js";
import { getStorage } from "./utils/storageHandler.js";

document.addEventListener("DOMContentLoaded", () => {
// 테스트 환경에서 #root 보장
if (!document.getElementById("root")) {
const rootDiv = document.createElement("div");
rootDiv.id = "root";
document.body.appendChild(rootDiv);
}

const user = JSON.parse(localStorage.getItem("user"));
const user = JSON.parse(getStorage("user"));

if (user) {
setState({ user });
Expand Down
35 changes: 21 additions & 14 deletions src/router/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,48 @@ import { state, subscribe } from "../store/store";
import { initLogin } from "./../events/login";
import { initProfile } from "./../events/profile";
import { initNavigation } from "./../events/navigation";
import { ROUTES } from "../constants/routes";

const routes = {
"/": MainPage,
"/login": LoginPage,
"/profile": ProfilePage,
[ROUTES.HOME]: { page: MainPage, init: initNavigation },
[ROUTES.LOGIN]: { page: LoginPage, init: initLogin },
[ROUTES.PROFILE]: { page: ProfilePage, init: initProfile },
};

export const router = () => {
const root = document.getElementById("root");

if (!root) return;

const path = window.location.pathname;
const render = routes[path] || ErrorPage;
const route = routes[path] || { page: ErrorPage };

// 404페이지
if (!state.user && path === "/profile") {
// 비로그인 사용자는 프로필 접근 불가 → 로그인 페이지로 이동
if (!state.user && path === ROUTES.PROFILE) {
root.innerHTML = LoginPage();
return;
}

// 로그인한 사용자가 로그인 페이지 접근
if ((state.user || localStorage.getItem("user")) && path === "/login") {
// 로그인 사용자는 로그인 페이지 접근 불가 → 메인 페이지로 이동
if (state.user && path === ROUTES.LOGIN) {
root.innerHTML = MainPage();
alert("이미 로그인이 되어 있습니다.");
return;
}

root.innerHTML = render(render === LoginPage ? null : state.user);
// 페이지 렌더링
root.innerHTML = route.page(state.user);

if (path === "/login") initLogin();
else if (path === "/profile") initProfile();
else if (path === "/") initNavigation();
// 페이지 초기화 함수 실행
if (route.init) {
route.init();
}
};

export const navigateTo = (path) => {
history.pushState({}, "", path);
router();
};

// 상태 변경 시 라우터 재실행
subscribe(() => {
router();
});
9 changes: 9 additions & 0 deletions src/utils/storageHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// 로컬 스토리지에서 데이터 가져오기
export const getStorage = (key) => localStorage.getItem(key);

// 로컬 스토리지에 데이터 저장
export const setStorage = (key, value) =>
localStorage.setItem(key, JSON.stringify(value));

// 로컬 스토리지 초기화
export const clearStorage = () => localStorage.clear();

0 comments on commit 461a27f

Please sign in to comment.