Skip to content

Commit

Permalink
Route guard (#5)
Browse files Browse the repository at this point in the history
* user store 생성

* 로그인 페이지 라우트 가드

* 로그인 페이지 input 수정

* typescript

* 홈화면 로그인 상태에 따라 nav 변경

* 로그인 라우터 가드

* 라우트 가드 함수 생성
  • Loading branch information
jch1223 authored Dec 18, 2024
1 parent caeb4dd commit f730785
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 59 deletions.
5 changes: 2 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/__tests__/advanced.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ beforeAll(async () => {
// DOM 초기화
window.alert = vi.fn();
document.body.innerHTML = '<div id="root"></div>';
await import("../main.js");
await import("../main.ts");
});

afterAll(() => {
Expand Down
19 changes: 16 additions & 3 deletions src/components/Navigator.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import { User } from "@/store/userStore";

export const LOGIN_ID = "login";
export const LOGOUT_ID = "logout";

export const Navigator = () => `
export const Navigator = (user: User) => {
document.querySelector("#root")?.addEventListener("click", (e) => {
if (e.target instanceof HTMLAnchorElement) {
if (e.target.id === LOGOUT_ID) {
localStorage.removeItem("user");
}
}
});

return `
<nav class="bg-white shadow-md p-2 sticky top-14">
<ul class="flex justify-around">
<li><a href="/" class="text-blue-600">홈</a></li>
<li><a href="/" class="text-blue-600 font-bold">홈</a></li>
<li><a href="/profile" class="text-gray-600">프로필</a></li>
<li><a id=${LOGOUT_ID} href="/login" class="text-gray-600">로그아웃</a></li>
<li><a id=${user?.username ? LOGOUT_ID : LOGIN_ID} href="/login" class="text-gray-600">${user?.username ? "로그아웃" : "로그인"}</a></li>
</ul>
</nav>
`;
};
19 changes: 17 additions & 2 deletions src/core/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { MainPage } from "@/pages/Main";
import { ErrorPage } from "@/pages/Error";
import { LoginPage } from "@/pages/Login";
import { ProfilePage } from "@/pages/Profile";
import { userStore } from "@/store/userStore";

const createRouter = (routes: { [key: string]: () => void }) => {
return {
Expand All @@ -16,10 +17,24 @@ const createRouter = (routes: { [key: string]: () => void }) => {
};
};

const routeGuard = (render: () => void) => () => {
if (window.location.pathname !== "/login" && !userStore.getUser()) {
router.navigateTo("/login");
return;
}

if (window.location.pathname === "/login" && userStore.getUser()) {
router.navigateTo("/");
return;
}

render();
};

const routes = {
"/": MainPage.render,
"/login": LoginPage.render,
"/profile": ProfilePage.render,
"/login": routeGuard(LoginPage.render),
"/profile": routeGuard(ProfilePage.render),
"/error": ErrorPage.render,
};

Expand Down
27 changes: 10 additions & 17 deletions src/pages/Login.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { router } from "@/core/router";
import { userStore } from "@/store/userStore";

const LOGIN_FORM_ID = "login-form";

Expand All @@ -8,14 +9,11 @@ export const LoginPage = () => {
<div class="bg-white p-8 rounded-lg shadow-md w-full max-w-md">
<h1 class="text-2xl font-bold text-center text-blue-600 mb-8">항해플러스</h1>
<form id=${LOGIN_FORM_ID}>
<div class="mb-6">
<input id="username" type="username" name="username" placeholder="유저이름" class="w-full p-2 border rounded">
</div>
<div class="mb-4">
<input type="text" name="email" placeholder="이메일 또는 전화번호" class="w-full p-2 border rounded">
<input id="username" name="username" type="text" placeholder="사용자 이름" class="w-full p-2 border rounded">
</div>
<div class="mb-4">
<input type="text" name="bio" placeholder="bio" class="w-full p-2 border rounded">
<div class="mb-6">
<input type="password" name="password" placeholder="비밀번호" class="w-full p-2 border rounded">
</div>
<button type="submit" class="w-full bg-blue-600 text-white p-2 rounded font-bold">로그인</button>
</form>
Expand Down Expand Up @@ -43,23 +41,18 @@ LoginPage.render = () => {
const $form = e.target as HTMLFormElement;
const formData = new FormData($form);

const email = formData.get("email");
const username = formData.get("username");
const bio = formData.get("bio");
const username = formData.get("username")?.toString();

if (!username) {
alert("유저이름을 입력해주세요");
return;
}

localStorage.setItem(
"user",
JSON.stringify({
username,
email,
bio,
}),
);
userStore.setUser({
username,
email: "",
bio: "",
});

router.navigateTo("/");
});
Expand Down
13 changes: 6 additions & 7 deletions src/pages/Main.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Footer } from "@/components/Footer";
import { Header } from "@/components/Header";
import { LOGOUT_ID, Navigator } from "@/components/Navigator";
import { Navigator } from "@/components/Navigator";
import { User, userStore } from "@/store/userStore";

export const MainPage = () => `
export const MainPage = (user: User) => `
<div class="bg-gray-100 min-h-screen flex justify-center">
<div class="max-w-md w-full">
${Header()}
${Navigator()}
${Navigator(user)}
<main class="p-4">
<div class="mb-4 bg-white rounded-lg shadow p-4">
Expand Down Expand Up @@ -108,9 +109,7 @@ MainPage.render = () => {

if (!$root) return;

$root.innerHTML = MainPage();
const user = userStore.getUser();

document.querySelector(`#${LOGOUT_ID}`)?.addEventListener("click", () => {
localStorage.removeItem("user");
});
$root.innerHTML = MainPage(user);
};
38 changes: 12 additions & 26 deletions src/pages/Profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,16 @@ import { Footer } from "@/components/Footer";
import { Header } from "@/components/Header";
import { Navigator } from "@/components/Navigator";
import { router } from "@/core/router";
import { User, userStore } from "@/store/userStore";

const PROFILE_FORM_ID = "profile-form";

export const ProfilePage = ({
username,
email,
bio,
}: {
[key: string]: string;
}) => `
export const ProfilePage = ({ username, email, bio }: User) => `
<div id="root">
<div class="bg-gray-100 min-h-screen flex justify-center">
<div class="max-w-md w-full">
${Header()}
${Navigator()}
${Navigator({ username })}
<main class="p-4">
<div class="bg-white p-8 rounded-lg shadow-md">
Expand Down Expand Up @@ -88,13 +83,7 @@ ProfilePage.render = () => {

if (!$root) return;

const localStorageUser = localStorage.getItem("user");
const user = localStorageUser ? JSON.parse(localStorageUser) : null;

if (!user) {
router.navigateTo("/login");
return;
}
const user = userStore.getUser();

$root.innerHTML = ProfilePage(user);

Expand All @@ -104,22 +93,19 @@ ProfilePage.render = () => {
const $form = e.target as HTMLFormElement;
const formData = new FormData($form);

const email = formData.get("email");
const username = formData.get("username");
const bio = formData.get("bio");
const email = formData.get("email")?.toString();
const username = formData.get("username")?.toString();
const bio = formData.get("bio")?.toString();

if (!username) {
alert("유저이름을 입력해주세요");
return;
}

localStorage.setItem(
"user",
JSON.stringify({
username,
email,
bio,
}),
);
userStore.setUser({
username,
email,
bio,
});
});
};
21 changes: 21 additions & 0 deletions src/store/userStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export interface User {
username?: string;
email?: string;
bio?: string;
}

const createUserStore = () => {
return {
getUser() {
const localStorageUser = localStorage.getItem("user");
const user = localStorageUser ? JSON.parse(localStorageUser) : null;

return user;
},
setUser(user: User) {
localStorage.setItem("user", JSON.stringify(user));
},
};
};

export const userStore = createUserStore();

0 comments on commit f730785

Please sign in to comment.