From 34b435549064df97683dd32ee4775a2a3eb24e20 Mon Sep 17 00:00:00 2001 From: DevJayve Date: Sun, 15 Dec 2024 19:03:32 +0900 Subject: [PATCH 01/22] =?UTF-8?q?feat:=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=84=B0=20=EA=B8=B0=EB=B0=98=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 +- src/main.js | 244 ++----------------------------------------- src/pages/Error.js | 20 ++++ src/pages/Login.js | 28 +++++ src/pages/Main.js | 117 +++++++++++++++++++++ src/pages/Profile.js | 88 ++++++++++++++++ src/router/router.js | 38 +++++++ 7 files changed, 298 insertions(+), 239 deletions(-) create mode 100644 src/pages/Error.js create mode 100644 src/pages/Login.js create mode 100644 src/pages/Main.js create mode 100644 src/pages/Profile.js create mode 100644 src/router/router.js diff --git a/index.html b/index.html index 0005b871..38bafb8a 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ -
+
diff --git a/src/main.js b/src/main.js index 036c2a38..cdeff45f 100644 --- a/src/main.js +++ b/src/main.js @@ -1,241 +1,9 @@ -const MainPage = () => ` -
-
-
-

항해플러스

-
+import { initRouter, routes } from "./router/router"; - +document.addEventListener("DOMContentLoaded", () => { + initRouter(); +}); -
-
- - -
+const $app = document.querySelector(".App"); -
- -
-
- 프로필 -
-

홍길동

-

5분 전

-
-
-

오늘 날씨가 정말 좋네요. 다들 좋은 하루 보내세요!

-
- - - -
-
- -
-
- 프로필 -
-

김철수

-

15분 전

-
-
-

새로운 프로젝트를 시작했어요. 열심히 코딩 중입니다!

-
- - - -
-
- -
-
- 프로필 -
-

이영희

-

30분 전

-
-
-

오늘 점심 메뉴 추천 받습니다. 뭐가 좋을까요?

-
- - - -
-
- -
-
- 프로필 -
-

박민수

-

1시간 전

-
-
-

주말에 등산 가실 분 계신가요? 함께 가요!

-
- - - -
-
- -
-
- 프로필 -
-

정수연

-

2시간 전

-
-
-

새로 나온 영화 재미있대요. 같이 보러 갈 사람?

-
- - - -
-
-
-
- -
-

© 2024 항해플러스. All rights reserved.

-
-
-
-`; - -const ErrorPage = () => ` -
-
-

항해플러스

-

404

-

페이지를 찾을 수 없습니다

-

- 요청하신 페이지가 존재하지 않거나 이동되었을 수 있습니다. -

- - 홈으로 돌아가기 - -
-
-`; - -const LoginPage = () => ` -
-
-

항해플러스

-
-
- -
-
- -
- -
- -
-
- -
-
-
-`; - -const ProfilePage = () => ` -
-
-
-
-

항해플러스

-
- - - -
-
-

- 내 프로필 -

-
-
- - -
-
- - -
-
- - -
- -
-
-
- -
-

© 2024 항해플러스. All rights reserved.

-
-
-
-
-`; - -document.body.innerHTML = ` - ${MainPage()} - ${ProfilePage()} - ${LoginPage()} - ${ErrorPage()} -`; +$app.innerHTML = routes["/"].template(); diff --git a/src/pages/Error.js b/src/pages/Error.js new file mode 100644 index 00000000..211e5e78 --- /dev/null +++ b/src/pages/Error.js @@ -0,0 +1,20 @@ +class ErrorPage { + template() { + return `
+
+

항해플러스

+

404

+

페이지를 찾을 수 없습니다

+

+ 요청하신 페이지가 존재하지 않거나 이동되었을 수 있습니다. +

+ + 홈으로 돌아가기 + +
+
+ `; + } +} + +export default new ErrorPage(); diff --git a/src/pages/Login.js b/src/pages/Login.js new file mode 100644 index 00000000..d75302f6 --- /dev/null +++ b/src/pages/Login.js @@ -0,0 +1,28 @@ +class LoginPage { + template() { + return ` +
+
+

항해플러스

+
+
+ +
+
+ +
+ +
+ +
+
+ +
+
+
`; + } +} + +export default new LoginPage(); diff --git a/src/pages/Main.js b/src/pages/Main.js new file mode 100644 index 00000000..1e7b40ca --- /dev/null +++ b/src/pages/Main.js @@ -0,0 +1,117 @@ +class MainPage { + template() { + return ` +
+
+
+

항해플러스

+
+ + + +
+
+ + +
+ +
+ +
+
+ 프로필 +
+

홍길동

+

5분 전

+
+
+

오늘 날씨가 정말 좋네요. 다들 좋은 하루 보내세요!

+
+ + + +
+
+ +
+
+ 프로필 +
+

김철수

+

15분 전

+
+
+

새로운 프로젝트를 시작했어요. 열심히 코딩 중입니다!

+
+ + + +
+
+ +
+
+ 프로필 +
+

이영희

+

30분 전

+
+
+

오늘 점심 메뉴 추천 받습니다. 뭐가 좋을까요?

+
+ + + +
+
+ +
+
+ 프로필 +
+

박민수

+

1시간 전

+
+
+

주말에 등산 가실 분 계신가요? 함께 가요!

+
+ + + +
+
+ +
+
+ 프로필 +
+

정수연

+

2시간 전

+
+
+

새로 나온 영화 재미있대요. 같이 보러 갈 사람?

+
+ + + +
+
+
+
+ +
+

© 2024 항해플러스. All rights reserved.

+
+
+
+ `; + } +} + +export default new MainPage(); diff --git a/src/pages/Profile.js b/src/pages/Profile.js new file mode 100644 index 00000000..c87dd443 --- /dev/null +++ b/src/pages/Profile.js @@ -0,0 +1,88 @@ +class ProfilePage { + template() { + return ` +
+
+
+
+

항해플러스

+
+ + + +
+
+

+ 내 프로필 +

+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+ +
+

© 2024 항해플러스. All rights reserved.

+
+
+
+
+ `; + } +} + +export default new ProfilePage(); diff --git a/src/router/router.js b/src/router/router.js new file mode 100644 index 00000000..7f8efd41 --- /dev/null +++ b/src/router/router.js @@ -0,0 +1,38 @@ +import LoginPage from "../pages/Login"; +import MainPage from "../pages/Main"; +import ProfilePage from "../pages/Profile"; +import ErrorPage from "../pages/Error"; + +export const routes = { + "/": MainPage, + "/profile": ProfilePage, + "/login": LoginPage, + "*": ErrorPage, +}; + +export function initRouter() { + window.addEventListener("popstate", handleLocation); + document.body.addEventListener("click", onClickLink); +} + +function handleLocation() { + const path = window.location.pathname; + const page = routes[path] || ErrorPage; + + const $app = document.querySelector(".App"); + if ($app) { + $app.innerHTML = page.template(); + } +} + +function onClickLink(e) { + if (e.target.matches("[data-link]")) { + e.preventDefault(); + navigate(e.target.href); + } +} + +export function navigate(url) { + history.pushState(null, null, url); + handleLocation(); +} From 4a6040d4a0abecc2e57039d3f4d846b3562c5f11 Mon Sep 17 00:00:00 2001 From: DevJayve Date: Sun, 15 Dec 2024 21:52:30 +0900 Subject: [PATCH 02/22] =?UTF-8?q?feat:=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EC=83=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/auth/auth.js | 11 +++++++++++ src/core/Component.js | 27 +++++++++++++++++++++++++++ src/main.js | 10 +++++----- src/pages/Error.js | 4 +++- src/pages/Login.js | 12 +++++++----- src/pages/Main.js | 6 ++++-- src/pages/Profile.js | 8 +++++--- src/router/router.js | 14 ++++++++++---- src/router/routes.js | 4 ++++ src/util/storage.js | 11 +++++++++++ 10 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 src/auth/auth.js create mode 100644 src/core/Component.js create mode 100644 src/router/routes.js create mode 100644 src/util/storage.js diff --git a/src/auth/auth.js b/src/auth/auth.js new file mode 100644 index 00000000..462d373a --- /dev/null +++ b/src/auth/auth.js @@ -0,0 +1,11 @@ +export function login(id) { + localStorage.setItem("user", id); +} + +export function logout() { + localStorage.removeItem("user"); +} + +export function getAuth() { + return localStorage.getItem("user"); +} diff --git a/src/core/Component.js b/src/core/Component.js new file mode 100644 index 00000000..d0840d55 --- /dev/null +++ b/src/core/Component.js @@ -0,0 +1,27 @@ +class Component { + $target; + state; + + constructor($target) { + this.$target = $target; + this.init(); + this.render(); + } + + init() {} + + template() { + return ``; + } + + render() { + this.$target.innerHTML = this.template(); + } + + setState(newState) { + this.state = { ...this.state, ...newState }; + this.render; + } +} + +export default Component; diff --git a/src/main.js b/src/main.js index cdeff45f..965d5cb1 100644 --- a/src/main.js +++ b/src/main.js @@ -1,9 +1,9 @@ -import { initRouter, routes } from "./router/router"; +import { initRouter } from "./router/router"; +import MainPage from "./pages/Main"; document.addEventListener("DOMContentLoaded", () => { initRouter(); -}); - -const $app = document.querySelector(".App"); -$app.innerHTML = routes["/"].template(); + const $app = document.querySelector(".App"); + new MainPage($app); +}); diff --git a/src/pages/Error.js b/src/pages/Error.js index 211e5e78..f27fcb26 100644 --- a/src/pages/Error.js +++ b/src/pages/Error.js @@ -1,4 +1,6 @@ -class ErrorPage { +import Component from "../core/component"; + +class ErrorPage extends Component { template() { return `
diff --git a/src/pages/Login.js b/src/pages/Login.js index d75302f6..a318d919 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -1,15 +1,17 @@ -class LoginPage { +import Component from "../core/component"; + +class LoginPage extends Component { template() { return `

항해플러스

-
+
- +
- +
@@ -25,4 +27,4 @@ class LoginPage { } } -export default new LoginPage(); +export default LoginPage; diff --git a/src/pages/Main.js b/src/pages/Main.js index 1e7b40ca..90c13e4f 100644 --- a/src/pages/Main.js +++ b/src/pages/Main.js @@ -1,4 +1,6 @@ -class MainPage { +import Component from "../core/component"; + +class MainPage extends Component { template() { return `
@@ -114,4 +116,4 @@ class MainPage { } } -export default new MainPage(); +export default MainPage; diff --git a/src/pages/Profile.js b/src/pages/Profile.js index c87dd443..b218b66e 100644 --- a/src/pages/Profile.js +++ b/src/pages/Profile.js @@ -1,4 +1,6 @@ -class ProfilePage { +import Component from "../core/component"; + +class ProfilePage extends Component { template() { return `
@@ -10,8 +12,8 @@ class ProfilePage { diff --git a/src/router/router.js b/src/router/router.js index 7f8efd41..100f4de7 100644 --- a/src/router/router.js +++ b/src/router/router.js @@ -2,12 +2,18 @@ import LoginPage from "../pages/Login"; import MainPage from "../pages/Main"; import ProfilePage from "../pages/Profile"; import ErrorPage from "../pages/Error"; +import { + LOGIN_ROUTE, + MAIN_ROUTE, + NOT_FOUND_ROUTE, + PROFILE_ROUTE, +} from "./routes"; export const routes = { - "/": MainPage, - "/profile": ProfilePage, - "/login": LoginPage, - "*": ErrorPage, + [MAIN_ROUTE]: MainPage, + [PROFILE_ROUTE]: ProfilePage, + [LOGIN_ROUTE]: LoginPage, + [NOT_FOUND_ROUTE]: ErrorPage, }; export function initRouter() { diff --git a/src/router/routes.js b/src/router/routes.js new file mode 100644 index 00000000..48f1ff9b --- /dev/null +++ b/src/router/routes.js @@ -0,0 +1,4 @@ +export const LOGIN_ROUTE = "/login"; +export const MAIN_ROUTE = "/main"; +export const PROFILE_ROUTE = "/profile"; +export const NOT_FOUND_ROUTE = "*"; diff --git a/src/util/storage.js b/src/util/storage.js new file mode 100644 index 00000000..3946011d --- /dev/null +++ b/src/util/storage.js @@ -0,0 +1,11 @@ +export function setItem(key, value) { + localStorage.setItem(key, JSON.stringify(value)); +} + +export function getItem(key) { + return JSON.parse(localStorage.getItem(key)); +} + +export function removeItem(key) { + localStorage.removeItem(key); +} From 67815e3b28f1db553d7841e2f127713dce7cd009 Mon Sep 17 00:00:00 2001 From: DevJayve Date: Sun, 15 Dec 2024 22:00:54 +0900 Subject: [PATCH 03/22] =?UTF-8?q?refactor:=20=ED=8C=A9=ED=86=A0=EB=A6=AC?= =?UTF-8?q?=20=ED=8C=A8=ED=84=B4=20=EA=B8=B0=EB=B0=98=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EB=A1=9C=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.js | 6 ++++-- src/pages/Error.js | 2 +- src/pages/Profile.js | 2 +- src/pages/index.js | 20 ++++++++++++++++++++ 4 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 src/pages/index.js diff --git a/src/main.js b/src/main.js index 965d5cb1..2d530182 100644 --- a/src/main.js +++ b/src/main.js @@ -1,9 +1,11 @@ import { initRouter } from "./router/router"; -import MainPage from "./pages/Main"; +import createPageFactory from "./pages"; document.addEventListener("DOMContentLoaded", () => { initRouter(); const $app = document.querySelector(".App"); - new MainPage($app); + const pages = createPageFactory($app); + + pages.main(); }); diff --git a/src/pages/Error.js b/src/pages/Error.js index f27fcb26..40c80215 100644 --- a/src/pages/Error.js +++ b/src/pages/Error.js @@ -19,4 +19,4 @@ class ErrorPage extends Component { } } -export default new ErrorPage(); +export default ErrorPage; diff --git a/src/pages/Profile.js b/src/pages/Profile.js index b218b66e..172649fc 100644 --- a/src/pages/Profile.js +++ b/src/pages/Profile.js @@ -87,4 +87,4 @@ class ProfilePage extends Component { } } -export default new ProfilePage(); +export default ProfilePage; diff --git a/src/pages/index.js b/src/pages/index.js new file mode 100644 index 00000000..4e568943 --- /dev/null +++ b/src/pages/index.js @@ -0,0 +1,20 @@ +import ErrorPage from "./Error"; +import LoginPage from "./Login"; +import MainPage from "./Main"; +import ProfilePage from "./Profile"; + +const createPageFactory = ($target) => { + const main = () => new MainPage($target); + const error = () => new ErrorPage($target); + const login = () => new LoginPage($target); + const profile = () => new ProfilePage($target); + + return { + main, + error, + login, + profile, + }; +}; + +export default createPageFactory; From c5d94939cdfd3bef97b34cb566bd67affc189f54 Mon Sep 17 00:00:00 2001 From: DevJayve Date: Sun, 15 Dec 2024 22:32:38 +0900 Subject: [PATCH 04/22] =?UTF-8?q?refactor:=20=EB=9D=BC=EC=9A=B0=ED=8A=B8?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.js | 11 ++++-- src/router/router.js | 87 +++++++++++++++++++++++++------------------- src/router/routes.js | 4 -- 3 files changed, 57 insertions(+), 45 deletions(-) delete mode 100644 src/router/routes.js diff --git a/src/main.js b/src/main.js index 2d530182..25cb8811 100644 --- a/src/main.js +++ b/src/main.js @@ -1,11 +1,14 @@ -import { initRouter } from "./router/router"; +import Router from "./router/Router"; import createPageFactory from "./pages"; document.addEventListener("DOMContentLoaded", () => { - initRouter(); - const $app = document.querySelector(".App"); const pages = createPageFactory($app); - pages.main(); + const router = new Router($app); + router.addRoute("/", pages.main); + router.addRoute("/profile", pages.profile); + router.addRoute("/login", pages.login); + router.addRoute("*", pages.error); + router.handleRoute(); }); diff --git a/src/router/router.js b/src/router/router.js index 100f4de7..d1378758 100644 --- a/src/router/router.js +++ b/src/router/router.js @@ -1,44 +1,57 @@ -import LoginPage from "../pages/Login"; -import MainPage from "../pages/Main"; -import ProfilePage from "../pages/Profile"; -import ErrorPage from "../pages/Error"; -import { - LOGIN_ROUTE, - MAIN_ROUTE, - NOT_FOUND_ROUTE, - PROFILE_ROUTE, -} from "./routes"; - -export const routes = { - [MAIN_ROUTE]: MainPage, - [PROFILE_ROUTE]: ProfilePage, - [LOGIN_ROUTE]: LoginPage, - [NOT_FOUND_ROUTE]: ErrorPage, -}; - -export function initRouter() { - window.addEventListener("popstate", handleLocation); - document.body.addEventListener("click", onClickLink); -} +import Component from "../core/component"; + +class Router extends Component { + init() { + this.state = { + routes: [], + }; + document.body.addEventListener("click", this.onClickLink.bind(this)); + window.addEventListener("popstate", this.handleRoute.bind(this)); + } -function handleLocation() { - const path = window.location.pathname; - const page = routes[path] || ErrorPage; + // 라우트 추가 + addRoute(fragment, page) { + // 기존 라우트와 중복되는 라우트 무시 처리 + if (this.state.routes.some((route) => route.fragment === fragment)) { + return; + } - const $app = document.querySelector(".App"); - if ($app) { - $app.innerHTML = page.template(); + this.state.routes.push({ fragment, page }); } -} -function onClickLink(e) { - if (e.target.matches("[data-link]")) { - e.preventDefault(); - navigate(e.target.href); + navigate(url) { + history.pushState(null, null, url); + this.handleRoute(); } -} -export function navigate(url) { - history.pushState(null, null, url); - handleLocation(); + handleRoute() { + const fragment = window.location.pathname; + const currentRoute = this.state.routes.find( + (route) => route.fragment === fragment, + ); + + if (!currentRoute) { + this.handleError(); + return; + } + + currentRoute.page(); + } + + handleError() { + const errorRoute = this.state.routes.find( + (route) => route.fragment === "/error", + ); + + errorRoute.page(); + } + + onClickLink(e) { + if (e.target.matches("[data-link]")) { + e.preventDefault(); + this.navigate(e.target.href); + } + } } + +export default Router; diff --git a/src/router/routes.js b/src/router/routes.js deleted file mode 100644 index 48f1ff9b..00000000 --- a/src/router/routes.js +++ /dev/null @@ -1,4 +0,0 @@ -export const LOGIN_ROUTE = "/login"; -export const MAIN_ROUTE = "/main"; -export const PROFILE_ROUTE = "/profile"; -export const NOT_FOUND_ROUTE = "*"; From c379efd9b9bc7139f57e06ca4c2c2a2807612689 Mon Sep 17 00:00:00 2001 From: DevJayve Date: Sun, 15 Dec 2024 23:02:21 +0900 Subject: [PATCH 05/22] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/auth/auth.js | 4 ++-- src/core/Component.js | 3 +++ src/main.js | 7 ++++++- src/pages/Login.js | 24 ++++++++++++++++++++++-- src/router/router.js | 4 ++-- 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/auth/auth.js b/src/auth/auth.js index 462d373a..3224fcb6 100644 --- a/src/auth/auth.js +++ b/src/auth/auth.js @@ -1,5 +1,5 @@ -export function login(id) { - localStorage.setItem("user", id); +export function login(username) { + localStorage.setItem("user", username); } export function logout() { diff --git a/src/core/Component.js b/src/core/Component.js index d0840d55..e46c00bd 100644 --- a/src/core/Component.js +++ b/src/core/Component.js @@ -5,6 +5,7 @@ class Component { constructor($target) { this.$target = $target; this.init(); + this.setEvent(); this.render(); } @@ -22,6 +23,8 @@ class Component { this.state = { ...this.state, ...newState }; this.render; } + + setEvent() {} } export default Component; diff --git a/src/main.js b/src/main.js index 25cb8811..aa3a05ce 100644 --- a/src/main.js +++ b/src/main.js @@ -1,5 +1,6 @@ import Router from "./router/Router"; import createPageFactory from "./pages"; +import { getAuth } from "./auth/auth"; document.addEventListener("DOMContentLoaded", () => { const $app = document.querySelector(".App"); @@ -10,5 +11,9 @@ document.addEventListener("DOMContentLoaded", () => { router.addRoute("/profile", pages.profile); router.addRoute("/login", pages.login); router.addRoute("*", pages.error); - router.handleRoute(); + if (!getAuth()) { + router.navigateTo("/login"); + } else { + router.navigateTo("/"); + } }); diff --git a/src/pages/Login.js b/src/pages/Login.js index a318d919..71dcead8 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -1,6 +1,26 @@ import Component from "../core/component"; +import { login } from "../auth/auth"; +import Router from "../router/Router"; class LoginPage extends Component { + setEvent() { + this.$target.addEventListener("click", (e) => { + if (e.target.type === "submit") { + e.preventDefault(); + const username = this.$target.querySelector(".username").value.trim(); + const password = this.$target.querySelector(".password").value.trim(); + + if (!username || !password) { + return; + } + + login(username); + const router = new Router(); + router.navigateTo("/"); + } + }); + } + template() { return `
@@ -8,10 +28,10 @@ class LoginPage extends Component {

항해플러스

- +
- +
diff --git a/src/router/router.js b/src/router/router.js index d1378758..aadab241 100644 --- a/src/router/router.js +++ b/src/router/router.js @@ -19,7 +19,7 @@ class Router extends Component { this.state.routes.push({ fragment, page }); } - navigate(url) { + navigateTo(url) { history.pushState(null, null, url); this.handleRoute(); } @@ -49,7 +49,7 @@ class Router extends Component { onClickLink(e) { if (e.target.matches("[data-link]")) { e.preventDefault(); - this.navigate(e.target.href); + this.navigateTo(e.target.href); } } } From a68d83bbf7dcddd50d22a6e5d8eccb60a3053498 Mon Sep 17 00:00:00 2001 From: DevJayve Date: Mon, 16 Dec 2024 21:10:58 +0900 Subject: [PATCH 06/22] =?UTF-8?q?feat:=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EA=B8=B0=EB=B0=98=20=EB=9D=BC?= =?UTF-8?q?=EC=9A=B0=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/Component.js | 13 +++++++++- src/main.js | 14 +++++------ src/pages/Login.js | 28 +++++++++++----------- src/pages/Main.js | 31 ++++++++++++++++++++---- src/pages/Profile.js | 49 ++++++++++++++++++++++++++------------ src/pages/index.js | 16 ++++++------- src/router/router.js | 55 +++++++++++++++++++++++++++++++++---------- 7 files changed, 143 insertions(+), 63 deletions(-) diff --git a/src/core/Component.js b/src/core/Component.js index e46c00bd..d366e547 100644 --- a/src/core/Component.js +++ b/src/core/Component.js @@ -21,7 +21,18 @@ class Component { setState(newState) { this.state = { ...this.state, ...newState }; - this.render; + this.render(); + } + + addEvent(eventType, selector, callback) { + const boundCallback = (event) => { + if (!event.target.closest(selector)) return false; + callback(event); + }; + + // 기존에 동일한 이벤트 리스너가 있는지 확인 후 제거 + this.$target.removeEventListener(eventType, boundCallback); + this.$target.addEventListener(eventType, boundCallback); } setEvent() {} diff --git a/src/main.js b/src/main.js index aa3a05ce..ebc76ee4 100644 --- a/src/main.js +++ b/src/main.js @@ -1,19 +1,17 @@ -import Router from "./router/Router"; import createPageFactory from "./pages"; -import { getAuth } from "./auth/auth"; +import Router from "./router/router"; document.addEventListener("DOMContentLoaded", () => { const $app = document.querySelector(".App"); + + // 페이지 인스턴스 생성 const pages = createPageFactory($app); + // 라우터 초기화 const router = new Router($app); router.addRoute("/", pages.main); router.addRoute("/profile", pages.profile); router.addRoute("/login", pages.login); - router.addRoute("*", pages.error); - if (!getAuth()) { - router.navigateTo("/login"); - } else { - router.navigateTo("/"); - } + router.addRoute("/error", pages.error); + router.navigate("/"); }); diff --git a/src/pages/Login.js b/src/pages/Login.js index 71dcead8..c18b0de5 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -1,23 +1,23 @@ import Component from "../core/component"; import { login } from "../auth/auth"; -import Router from "../router/Router"; +import Router from "../router/router"; class LoginPage extends Component { setEvent() { - this.$target.addEventListener("click", (e) => { - if (e.target.type === "submit") { - e.preventDefault(); - const username = this.$target.querySelector(".username").value.trim(); - const password = this.$target.querySelector(".password").value.trim(); + this.addEvent("click", ".loginSubmitBtn", (e) => { + e.preventDefault(); + console.log("Login Page addEvent : loginSubmit"); + const username = this.$target.querySelector(".username").value.trim(); + const password = this.$target.querySelector(".password").value.trim(); - if (!username || !password) { - return; - } - - login(username); - const router = new Router(); - router.navigateTo("/"); + if (!username || !password) { + return; } + + login(username); + + const router = Router.instance; + router.navigate("/"); }); } @@ -33,7 +33,7 @@ class LoginPage extends Component {
- +
비밀번호를 잊으셨나요? diff --git a/src/pages/Main.js b/src/pages/Main.js index 90c13e4f..9acdbf31 100644 --- a/src/pages/Main.js +++ b/src/pages/Main.js @@ -1,7 +1,24 @@ import Component from "../core/component"; +import { getAuth } from "../auth/auth"; +import Router from "../router/router"; class MainPage extends Component { + setEvent() { + this.addEvent("click", ".nav-link", (e) => { + const target = e.target.closest("a"); + if (!(target instanceof HTMLAnchorElement)) return; + + e.preventDefault(); + const targetURL = e.target.getAttribute("href"); + const router = Router.instance; + router.navigate(targetURL); + }); + } + template() { + const currentPath = window.location.pathname; + const auth = getAuth(); + return `
@@ -9,11 +26,15 @@ class MainPage extends Component {

항해플러스

-
diff --git a/src/pages/Profile.js b/src/pages/Profile.js index 172649fc..05f66160 100644 --- a/src/pages/Profile.js +++ b/src/pages/Profile.js @@ -1,25 +1,45 @@ import Component from "../core/component"; +import { getAuth } from "../auth/auth"; +import Router from "../router/router"; class ProfilePage extends Component { + setEvent() { + this.addEvent("click", ".nav-link", (e) => { + const target = e.target.closest("a"); + if (!(target instanceof HTMLAnchorElement)) return; + + e.preventDefault(); + const targetURL = e.target.getAttribute("href"); + const router = Router.instance; + router.navigate(targetURL); + }); + } + template() { + const currentPath = window.location.pathname; + const auth = getAuth(); + return ` -
-
-
-

항해플러스

-
+
+
+

항해플러스

+
- + -
-
+
+

내 프로필

@@ -82,7 +102,6 @@ class ProfilePage extends Component {
-
`; } } diff --git a/src/pages/index.js b/src/pages/index.js index 4e568943..f31058cc 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -4,16 +4,16 @@ import MainPage from "./Main"; import ProfilePage from "./Profile"; const createPageFactory = ($target) => { - const main = () => new MainPage($target); - const error = () => new ErrorPage($target); - const login = () => new LoginPage($target); - const profile = () => new ProfilePage($target); + const mainInstance = new MainPage($target); + const errorInstance = new ErrorPage($target); + const loginInstance = new LoginPage($target); + const profileInstance = new ProfilePage($target); return { - main, - error, - login, - profile, + main: () => mainInstance, + error: () => errorInstance, + login: () => loginInstance, + profile: () => profileInstance, }; }; diff --git a/src/router/router.js b/src/router/router.js index aadab241..6ca454f1 100644 --- a/src/router/router.js +++ b/src/router/router.js @@ -1,11 +1,38 @@ import Component from "../core/component"; class Router extends Component { + static instance = null; + + constructor($target) { + // 라우터 싱글톤(Singleton) 인스턴스 + if (Router.instance) { + return Router.instance; + } + super($target); + Router.instance = this; + } + + // 페이지 이동 함수 + navigate = (to, isReplace = false) => { + // URL 변경에 대한 커스텀 이벤트 정의 + const historyChangeEvent = new CustomEvent("historychange", { + detail: { + to, + isReplace, + }, + }); + + dispatchEvent(historyChangeEvent); + }; + init() { this.state = { routes: [], }; - document.body.addEventListener("click", this.onClickLink.bind(this)); + + // URL 변경에 따른 커스텀 이벤트 리스너 + window.addEventListener("historychange", this.handleHistory.bind(this)); + // 뒤로가기 이벤트에 대한 리스너 window.addEventListener("popstate", this.handleRoute.bind(this)); } @@ -19,12 +46,21 @@ class Router extends Component { this.state.routes.push({ fragment, page }); } - navigateTo(url) { - history.pushState(null, null, url); + // 히스토리 관리 + handleHistory({ detail }) { + const { to, isReplace } = detail; + + // 페이지 교체 혹은 중복 페이지 방지 + if (isReplace || to === location.pathname) + history.replaceState(null, "", to); + else history.pushState(null, "", to); + this.handleRoute(); } + // 라우트 예외처리 및 렌더링 handleRoute() { + // 현재 라우트를 기준으로 페이지 추출 const fragment = window.location.pathname; const currentRoute = this.state.routes.find( (route) => route.fragment === fragment, @@ -35,22 +71,17 @@ class Router extends Component { return; } - currentRoute.page(); + // 추출된 페이지 렌더링 + currentRoute.page().render(); } + // 에러 핸들링 handleError() { const errorRoute = this.state.routes.find( (route) => route.fragment === "/error", ); - errorRoute.page(); - } - - onClickLink(e) { - if (e.target.matches("[data-link]")) { - e.preventDefault(); - this.navigateTo(e.target.href); - } + errorRoute.page().render(); } } From 9f49657a32886a993e0486567804ed8806e523c5 Mon Sep 17 00:00:00 2001 From: DevJayve Date: Mon, 16 Dec 2024 21:42:48 +0900 Subject: [PATCH 07/22] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/auth/auth.js | 20 +++++++++++++++++--- src/pages/Login.js | 1 - src/pages/Main.js | 13 +++++++++++-- src/pages/Profile.js | 41 ++++++++++++++++++++++++++++++++++------- 4 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/auth/auth.js b/src/auth/auth.js index 3224fcb6..6f8a81a2 100644 --- a/src/auth/auth.js +++ b/src/auth/auth.js @@ -1,11 +1,25 @@ export function login(username) { - localStorage.setItem("user", username); + console.log(`save name : ${username}`); + localStorage.setItem("username", username); } export function logout() { - localStorage.removeItem("user"); + localStorage.removeItem("username"); } export function getAuth() { - return localStorage.getItem("user"); + return localStorage.getItem("username"); +} + +export function getUser() { + const user = JSON.parse(localStorage.getItem("user")); + + return user; +} + +export function saveUser(name, email, introduction) { + localStorage.setItem( + "user", + JSON.stringify({ name: name, email: email, introduction: introduction }), + ); } diff --git a/src/pages/Login.js b/src/pages/Login.js index c18b0de5..bf8731e3 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -6,7 +6,6 @@ class LoginPage extends Component { setEvent() { this.addEvent("click", ".loginSubmitBtn", (e) => { e.preventDefault(); - console.log("Login Page addEvent : loginSubmit"); const username = this.$target.querySelector(".username").value.trim(); const password = this.$target.querySelector(".password").value.trim(); diff --git a/src/pages/Main.js b/src/pages/Main.js index 9acdbf31..5c90d03f 100644 --- a/src/pages/Main.js +++ b/src/pages/Main.js @@ -1,5 +1,5 @@ import Component from "../core/component"; -import { getAuth } from "../auth/auth"; +import { getAuth, logout } from "../auth/auth"; import Router from "../router/router"; class MainPage extends Component { @@ -9,12 +9,21 @@ class MainPage extends Component { if (!(target instanceof HTMLAnchorElement)) return; e.preventDefault(); + + if (target.id === "logoutBtn") { + this.handleLogout(); + } + const targetURL = e.target.getAttribute("href"); const router = Router.instance; router.navigate(targetURL); }); } + handleLogout() { + logout(); + } + template() { const currentPath = window.location.pathname; const auth = getAuth(); @@ -32,7 +41,7 @@ class MainPage extends Component { ${ auth ? `
  • 프로필
  • -
  • 로그아웃
  • ` +
  • 로그아웃
  • ` : `
  • 로그인
  • ` } diff --git a/src/pages/Profile.js b/src/pages/Profile.js index 05f66160..767428bb 100644 --- a/src/pages/Profile.js +++ b/src/pages/Profile.js @@ -1,8 +1,18 @@ import Component from "../core/component"; -import { getAuth } from "../auth/auth"; +import { getAuth, getUser, saveUser } from "../auth/auth"; import Router from "../router/router"; class ProfilePage extends Component { + init() { + const user = getUser(); + console.log(user); + this.state = { + name: user.name || "", + email: user.email || "", + introduction: user.introduction || "", + }; + } + setEvent() { this.addEvent("click", ".nav-link", (e) => { const target = e.target.closest("a"); @@ -13,6 +23,25 @@ class ProfilePage extends Component { const router = Router.instance; router.navigate(targetURL); }); + + this.addEvent("click", ".profile-submit", (e) => { + e.preventDefault(); + + const form = e.target.closest("form"); + const name = form.querySelector("#username").value; + const email = form.querySelector("#email").value; + const introduction = form.querySelector("#bio").value; + + saveUser(name, email, introduction); + + this.setState({ + name, + email, + introduction, + }); + + alert("프로필이 업데이트 되었습니다"); + }); } template() { @@ -54,7 +83,7 @@ class ProfilePage extends Component { type="text" id="username" name="username" - value="홍길동" + value="${this.state.name}" class="w-full p-2 border rounded" />
    @@ -68,7 +97,7 @@ class ProfilePage extends Component { type="email" id="email" name="email" - value="hong@example.com" + value="${this.state.email}" class="w-full p-2 border rounded" />
    @@ -83,13 +112,11 @@ class ProfilePage extends Component { name="bio" rows="4" class="w-full p-2 border rounded" - > -안녕하세요, 항해플러스에서 열심히 공부하고 있는 홍길동입니다. + >${this.state.introduction}
    From 1564f43628fa9a775f32173a90d193d060e9ef57 Mon Sep 17 00:00:00 2001 From: DevJayve Date: Tue, 17 Dec 2024 20:57:28 +0900 Subject: [PATCH 08/22] =?UTF-8?q?feat:=20=EB=B8=8C=EB=9D=BC=EC=9A=B0?= =?UTF-8?q?=EC=A0=80=20URL=20=EC=88=98=EB=8F=99=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=8C=85=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/NavBar.js | 56 +++++++++++++++++++++++++++++++++ src/core/Component.js | 3 ++ src/main.js | 4 ++- src/pages/Login.js | 4 +-- src/pages/Profile.js | 26 ++++++++-------- src/router/router.js | 67 ++++++++++++++++++++++++---------------- 6 files changed, 118 insertions(+), 42 deletions(-) create mode 100644 src/components/NavBar.js diff --git a/src/components/NavBar.js b/src/components/NavBar.js new file mode 100644 index 00000000..d42ddf23 --- /dev/null +++ b/src/components/NavBar.js @@ -0,0 +1,56 @@ +import Component from "../core/component"; +import { getAuth, logout } from "../auth/auth"; +import Router from "../router/router"; + +class Navbar extends Component { + constructor($target) { + super($target); + this.router = Router.instance; + } + + setEvent() { + this.addEvent("click", ".nav-link", (e) => { + const target = e.target.closest("a"); + if (!(target instanceof HTMLAnchorElement)) return; + + e.preventDefault(); + + if (target.id === "logoutBtn") { + this.handleLogout(); + return; // 로그아웃 후 추가 네비게이션을 막기 위해 return 추가 + } + + const targetURL = target.getAttribute("href"); + this.router.navigate(targetURL); + }); + } + + handleLogout() { + logout(); + // 로그아웃 후 홈으로 이동하거나 다른 페이지로 리디렉션할 수 있습니다. + this.router.navigate("/"); + } + + template() { + const currentPath = window.location.pathname; + const auth = getAuth(); + + return ` + + `; + } +} + +export default Navbar; diff --git a/src/core/Component.js b/src/core/Component.js index d366e547..af37b91f 100644 --- a/src/core/Component.js +++ b/src/core/Component.js @@ -17,8 +17,11 @@ class Component { render() { this.$target.innerHTML = this.template(); + this.mount(); } + mount() {} + setState(newState) { this.state = { ...this.state, ...newState }; this.render(); diff --git a/src/main.js b/src/main.js index ebc76ee4..24b23482 100644 --- a/src/main.js +++ b/src/main.js @@ -7,11 +7,13 @@ document.addEventListener("DOMContentLoaded", () => { // 페이지 인스턴스 생성 const pages = createPageFactory($app); + console.log("init"); + // 라우터 초기화 const router = new Router($app); router.addRoute("/", pages.main); router.addRoute("/profile", pages.profile); router.addRoute("/login", pages.login); router.addRoute("/error", pages.error); - router.navigate("/"); + router.handleRoute(); }); diff --git a/src/pages/Login.js b/src/pages/Login.js index bf8731e3..c3db7df5 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -27,10 +27,10 @@ class LoginPage extends Component {

    항해플러스

    - +
    - +
    diff --git a/src/pages/Profile.js b/src/pages/Profile.js index 767428bb..fd0ea0cf 100644 --- a/src/pages/Profile.js +++ b/src/pages/Profile.js @@ -1,28 +1,28 @@ import Component from "../core/component"; import { getAuth, getUser, saveUser } from "../auth/auth"; -import Router from "../router/router"; class ProfilePage extends Component { init() { const user = getUser(); - console.log(user); + this.state = { - name: user.name || "", - email: user.email || "", - introduction: user.introduction || "", + name: user?.name || "", + email: user?.email || "", + introduction: user?.introduction || "", }; } setEvent() { - this.addEvent("click", ".nav-link", (e) => { - const target = e.target.closest("a"); - if (!(target instanceof HTMLAnchorElement)) return; + // this.addEvent("click", ".nav-link", (e) => { + // const target = e.target.closest("a"); + // if (!(target instanceof HTMLAnchorElement)) return; - e.preventDefault(); - const targetURL = e.target.getAttribute("href"); - const router = Router.instance; - router.navigate(targetURL); - }); + // e.preventDefault(); + // const targetURL = e.target.getAttribute("href"); + // const router = Router.instance; + // console.log("navigate : profile"); + // router.navigate(targetURL); + // }); this.addEvent("click", ".profile-submit", (e) => { e.preventDefault(); diff --git a/src/router/router.js b/src/router/router.js index 6ca454f1..a664ba69 100644 --- a/src/router/router.js +++ b/src/router/router.js @@ -4,6 +4,7 @@ class Router extends Component { static instance = null; constructor($target) { + console.log("router init"); // 라우터 싱글톤(Singleton) 인스턴스 if (Router.instance) { return Router.instance; @@ -12,17 +13,10 @@ class Router extends Component { Router.instance = this; } - // 페이지 이동 함수 navigate = (to, isReplace = false) => { - // URL 변경에 대한 커스텀 이벤트 정의 - const historyChangeEvent = new CustomEvent("historychange", { - detail: { - to, - isReplace, - }, - }); - - dispatchEvent(historyChangeEvent); + // 페이지 교체 혹은 중복 페이지 방지 + if (isReplace || to === location.pathname) history.replaceState({}, "", to); + else history.pushState({}, "", to); }; init() { @@ -30,10 +24,41 @@ class Router extends Component { routes: [], }; - // URL 변경에 따른 커스텀 이벤트 리스너 - window.addEventListener("historychange", this.handleHistory.bind(this)); - // 뒤로가기 이벤트에 대한 리스너 - window.addEventListener("popstate", this.handleRoute.bind(this)); + this.trackRouteState(); + } + + // 페이지 URL 변경 추적 이벤트 생성 및 리스너 등록 + trackRouteState() { + window.addEventListener("popstate", () => { + this.handleRoute(); + }); + + const originalPushState = window.history.pushState; + window.history.pushState = function (state, title, url) { + originalPushState.apply(this, arguments); + const event = new CustomEvent("pushState", { + detail: { state, title, url }, + }); + window.dispatchEvent(event); + }; + + window.addEventListener("pushState", () => { + this.handleRoute(); + }); + + const originalReplaceState = window.history.replaceState; + window.history.replaceState = function (state, title, url) { + console.log(`replace : ${url}`); + originalReplaceState.apply(this, arguments); + const event = new CustomEvent("replaceState", { + detail: { state, title, url }, + }); + window.dispatchEvent(event); + }; + + window.addEventListener("replaceState", () => { + this.handleRoute(); + }); } // 라우트 추가 @@ -46,20 +71,10 @@ class Router extends Component { this.state.routes.push({ fragment, page }); } - // 히스토리 관리 - handleHistory({ detail }) { - const { to, isReplace } = detail; - - // 페이지 교체 혹은 중복 페이지 방지 - if (isReplace || to === location.pathname) - history.replaceState(null, "", to); - else history.pushState(null, "", to); - - this.handleRoute(); - } - // 라우트 예외처리 및 렌더링 handleRoute() { + console.log(`route : ${window.location.pathname}`); + // 현재 라우트를 기준으로 페이지 추출 const fragment = window.location.pathname; const currentRoute = this.state.routes.find( From 76b07b8f59b74932ec9a7004da75b16830ad0918 Mon Sep 17 00:00:00 2001 From: DevJayve Date: Tue, 17 Dec 2024 22:07:53 +0900 Subject: [PATCH 09/22] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9A=94=EA=B5=AC=20=EA=B8=B0=EB=B0=98=20=20=EC=97=98=EB=A6=AC?= =?UTF-8?q?=EB=A8=BC=ED=8A=B8=20=EC=86=8D=EC=84=B1=20=EB=93=B1=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 +- src/auth/auth.js | 15 ++-- src/main.js | 47 +++++++----- src/pages/Login.js | 11 ++- src/pages/Main.js | 6 +- src/pages/Profile.js | 168 ++++++++++++++++++++++--------------------- 6 files changed, 134 insertions(+), 115 deletions(-) diff --git a/index.html b/index.html index 38bafb8a..0005b871 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ -
    +
    diff --git a/src/auth/auth.js b/src/auth/auth.js index 6f8a81a2..4cc7a417 100644 --- a/src/auth/auth.js +++ b/src/auth/auth.js @@ -1,14 +1,13 @@ export function login(username) { - console.log(`save name : ${username}`); - localStorage.setItem("username", username); + saveUser(username, "", ""); } export function logout() { - localStorage.removeItem("username"); + localStorage.removeItem("user"); } export function getAuth() { - return localStorage.getItem("username"); + return localStorage.getItem("user"); } export function getUser() { @@ -17,9 +16,13 @@ export function getUser() { return user; } -export function saveUser(name, email, introduction) { +export function saveUser(username, email, bio) { localStorage.setItem( "user", - JSON.stringify({ name: name, email: email, introduction: introduction }), + JSON.stringify({ + username: username, + email: email, + bio: bio, + }), ); } diff --git a/src/main.js b/src/main.js index 24b23482..308f63a1 100644 --- a/src/main.js +++ b/src/main.js @@ -1,19 +1,34 @@ import createPageFactory from "./pages"; import Router from "./router/router"; -document.addEventListener("DOMContentLoaded", () => { - const $app = document.querySelector(".App"); - - // 페이지 인스턴스 생성 - const pages = createPageFactory($app); - - console.log("init"); - - // 라우터 초기화 - const router = new Router($app); - router.addRoute("/", pages.main); - router.addRoute("/profile", pages.profile); - router.addRoute("/login", pages.login); - router.addRoute("/error", pages.error); - router.handleRoute(); -}); +// document.addEventListener("DOMContentLoaded", () => { +// const $app = document.querySelector("#root"); + +// // 페이지 인스턴스 생성 +// const pages = createPageFactory($app); + +// console.log("init"); + +// // 라우터 초기화 +// const router = new Router($app); +// router.addRoute("/", pages.main); +// router.addRoute("/profile", pages.profile); +// router.addRoute("/login", pages.login); +// router.addRoute("/error", pages.error); +// router.handleRoute(); +// }); + +const $app = document.querySelector("#root"); + +// 페이지 인스턴스 생성 +const pages = createPageFactory($app); + +console.log("init"); + +// 라우터 초기화 +const router = new Router($app); +router.addRoute("/", pages.main); +router.addRoute("/profile", pages.profile); +router.addRoute("/login", pages.login); +router.addRoute("/error", pages.error); +router.handleRoute(); diff --git a/src/pages/Login.js b/src/pages/Login.js index c3db7df5..335c0812 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -4,17 +4,16 @@ import Router from "../router/router"; class LoginPage extends Component { setEvent() { - this.addEvent("click", ".loginSubmitBtn", (e) => { + this.addEvent("submit", "#login-form", (e) => { e.preventDefault(); const username = this.$target.querySelector(".username").value.trim(); - const password = this.$target.querySelector(".password").value.trim(); + // const password = this.$target.querySelector(".password").value.trim(); - if (!username || !password) { + if (!username) { return; } login(username); - const router = Router.instance; router.navigate("/"); }); @@ -25,14 +24,14 @@ class LoginPage extends Component {

    항해플러스

    -
    +
    - +
    비밀번호를 잊으셨나요? diff --git a/src/pages/Main.js b/src/pages/Main.js index 5c90d03f..4f1f3f7a 100644 --- a/src/pages/Main.js +++ b/src/pages/Main.js @@ -10,7 +10,7 @@ class MainPage extends Component { e.preventDefault(); - if (target.id === "logoutBtn") { + if (target.id === "logout") { this.handleLogout(); } @@ -41,8 +41,8 @@ class MainPage extends Component { ${ auth ? `
  • 프로필
  • -
  • 로그아웃
  • ` - : `
  • 로그인
  • ` +
  • 로그아웃
  • ` + : `
  • 로그인
  • ` } diff --git a/src/pages/Profile.js b/src/pages/Profile.js index fd0ea0cf..370b5589 100644 --- a/src/pages/Profile.js +++ b/src/pages/Profile.js @@ -4,11 +4,10 @@ import { getAuth, getUser, saveUser } from "../auth/auth"; class ProfilePage extends Component { init() { const user = getUser(); - this.state = { - name: user?.name || "", + username: user?.username || "", email: user?.email || "", - introduction: user?.introduction || "", + bio: user?.bio || "", }; } @@ -24,20 +23,20 @@ class ProfilePage extends Component { // router.navigate(targetURL); // }); - this.addEvent("click", ".profile-submit", (e) => { + this.addEvent("submit", "#profile-form", (e) => { e.preventDefault(); const form = e.target.closest("form"); - const name = form.querySelector("#username").value; + const username = form.querySelector("#username").value; const email = form.querySelector("#email").value; - const introduction = form.querySelector("#bio").value; + const bio = form.querySelector("#bio").value; - saveUser(name, email, introduction); + saveUser(username, email, bio); this.setState({ - name, + username, email, - introduction, + bio, }); alert("프로필이 업데이트 되었습니다"); @@ -49,84 +48,87 @@ class ProfilePage extends Component { const auth = getAuth(); return ` -
    -
    -
    -

    항해플러스

    -
    +
    +
    +
    +
    +

    항해플러스

    +
    - + -
    -
    -

    - 내 프로필 -

    -
    -
    - - -
    -
    - - -
    -
    - +
    +

    + 내 프로필 +

    + +
    + + +
    +
    + + +
    +
    + + +
    +
    - - -
    -
    + 프로필 업데이트 + + +
    +
    -
    -

    © 2024 항해플러스. All rights reserved.

    -
    +
    +

    © 2024 항해플러스. All rights reserved.

    +
    +
    `; From 4210f37023c7a7525b7fba8139b9a6d110621f55 Mon Sep 17 00:00:00 2001 From: DevJayve Date: Tue, 17 Dec 2024 23:01:35 +0900 Subject: [PATCH 10/22] =?UTF-8?q?fix:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=8B=9C=20=EC=A0=95=EB=B3=B4=20=EC=A6=89=EC=8B=9C=20=EA=B0=B1?= =?UTF-8?q?=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/Component.js | 1 + src/main.js | 2 -- src/pages/Login.js | 5 ++++- src/pages/Main.js | 2 +- src/router/router.js | 8 +++++--- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/core/Component.js b/src/core/Component.js index af37b91f..84df2daf 100644 --- a/src/core/Component.js +++ b/src/core/Component.js @@ -24,6 +24,7 @@ class Component { setState(newState) { this.state = { ...this.state, ...newState }; + console.log(`setstate : ${this.state.username}`); this.render(); } diff --git a/src/main.js b/src/main.js index 308f63a1..dafce5f0 100644 --- a/src/main.js +++ b/src/main.js @@ -23,8 +23,6 @@ const $app = document.querySelector("#root"); // 페이지 인스턴스 생성 const pages = createPageFactory($app); -console.log("init"); - // 라우터 초기화 const router = new Router($app); router.addRoute("/", pages.main); diff --git a/src/pages/Login.js b/src/pages/Login.js index 335c0812..1cbd7b64 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -1,6 +1,7 @@ import Component from "../core/component"; import { login } from "../auth/auth"; import Router from "../router/router"; +import ProfilePage from "./Profile"; class LoginPage extends Component { setEvent() { @@ -14,7 +15,9 @@ class LoginPage extends Component { } login(username); - const router = Router.instance; + const router = new Router(); + const profileInstnace = new ProfilePage(this.$target); + router.addRoute("/profile", () => profileInstnace); router.navigate("/"); }); } diff --git a/src/pages/Main.js b/src/pages/Main.js index 4f1f3f7a..d0d3dceb 100644 --- a/src/pages/Main.js +++ b/src/pages/Main.js @@ -15,7 +15,7 @@ class MainPage extends Component { } const targetURL = e.target.getAttribute("href"); - const router = Router.instance; + const router = new Router(); router.navigate(targetURL); }); } diff --git a/src/router/router.js b/src/router/router.js index a664ba69..5cfe6fdf 100644 --- a/src/router/router.js +++ b/src/router/router.js @@ -4,7 +4,6 @@ class Router extends Component { static instance = null; constructor($target) { - console.log("router init"); // 라우터 싱글톤(Singleton) 인스턴스 if (Router.instance) { return Router.instance; @@ -63,9 +62,12 @@ class Router extends Component { // 라우트 추가 addRoute(fragment, page) { - // 기존 라우트와 중복되는 라우트 무시 처리 + // 기존 라우트와 중복되는 라우트는 신규 라우트로 대체 if (this.state.routes.some((route) => route.fragment === fragment)) { - return; + this.state.routes = this.state.routes.filter( + (routeObj) => routeObj.fragment !== fragment, + ); + console.log("remove route", this.state.routes); } this.state.routes.push({ fragment, page }); From 1813a8f15a01479d200249c4ed9da5e26090f3d9 Mon Sep 17 00:00:00 2001 From: DevJayve Date: Tue, 17 Dec 2024 23:10:23 +0900 Subject: [PATCH 11/22] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EC=83=81=ED=83=9C=EB=A1=9C=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=A0=91=EA=B7=BC=EC=8B=9C=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EB=A6=AC=EB=8B=A4=EC=9D=B4=EB=A0=89=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/Component.js | 1 - src/pages/Profile.js | 11 +++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/core/Component.js b/src/core/Component.js index 84df2daf..a9ea3567 100644 --- a/src/core/Component.js +++ b/src/core/Component.js @@ -6,7 +6,6 @@ class Component { this.$target = $target; this.init(); this.setEvent(); - this.render(); } init() {} diff --git a/src/pages/Profile.js b/src/pages/Profile.js index 370b5589..9321c619 100644 --- a/src/pages/Profile.js +++ b/src/pages/Profile.js @@ -1,5 +1,6 @@ import Component from "../core/component"; import { getAuth, getUser, saveUser } from "../auth/auth"; +import Router from "../router/router"; class ProfilePage extends Component { init() { @@ -11,6 +12,16 @@ class ProfilePage extends Component { }; } + render() { + const user = getUser(); + if (!user) { + const router = new Router(); + router.navigate("/login"); + return; + } + super.render(); + } + setEvent() { // this.addEvent("click", ".nav-link", (e) => { // const target = e.target.closest("a"); From c245e3af1acac693f5f99d84544b0863eb659abe Mon Sep 17 00:00:00 2001 From: DevJayve Date: Tue, 17 Dec 2024 23:28:47 +0900 Subject: [PATCH 12/22] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=EB=A1=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A0=91=EA=B7=BC=20=EC=8B=9C=20?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EB=A6=AC=EB=8B=A4=EC=9D=B4=EB=A0=89?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Login.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/pages/Login.js b/src/pages/Login.js index 1cbd7b64..798da15c 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -1,5 +1,5 @@ import Component from "../core/component"; -import { login } from "../auth/auth"; +import { getUser, login } from "../auth/auth"; import Router from "../router/router"; import ProfilePage from "./Profile"; @@ -15,6 +15,7 @@ class LoginPage extends Component { } login(username); + const router = new Router(); const profileInstnace = new ProfilePage(this.$target); router.addRoute("/profile", () => profileInstnace); @@ -22,6 +23,16 @@ class LoginPage extends Component { }); } + render() { + const user = getUser(); + if (user) { + const router = new Router(); + router.navigate("/"); + return; + } + super.render(); + } + template() { return `
    From eaf8f1cdc1b01bfc7e90da6c0a985edd03821c41 Mon Sep 17 00:00:00 2001 From: DevJayve Date: Wed, 18 Dec 2024 00:00:31 +0900 Subject: [PATCH 13/22] =?UTF-8?q?feat:=20hash=20=EA=B8=B0=EB=B0=98=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=8A=B8=20=EB=8F=99=EC=9E=91=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.js | 24 +++++++----------------- src/pages/Main.js | 20 +++++++++++++++----- src/pages/Profile.js | 35 +++++++++++++++++++++++------------ src/router/router.js | 18 ++++++++++++++---- 4 files changed, 59 insertions(+), 38 deletions(-) diff --git a/src/main.js b/src/main.js index dafce5f0..874ba2bc 100644 --- a/src/main.js +++ b/src/main.js @@ -1,23 +1,6 @@ import createPageFactory from "./pages"; import Router from "./router/router"; -// document.addEventListener("DOMContentLoaded", () => { -// const $app = document.querySelector("#root"); - -// // 페이지 인스턴스 생성 -// const pages = createPageFactory($app); - -// console.log("init"); - -// // 라우터 초기화 -// const router = new Router($app); -// router.addRoute("/", pages.main); -// router.addRoute("/profile", pages.profile); -// router.addRoute("/login", pages.login); -// router.addRoute("/error", pages.error); -// router.handleRoute(); -// }); - const $app = document.querySelector("#root"); // 페이지 인스턴스 생성 @@ -25,8 +8,15 @@ const pages = createPageFactory($app); // 라우터 초기화 const router = new Router($app); + +// 히스토리 기반 라우트 등록 router.addRoute("/", pages.main); router.addRoute("/profile", pages.profile); router.addRoute("/login", pages.login); router.addRoute("/error", pages.error); +// 해시 기반 라우트 등록 +router.addRoute("#/", pages.main); +router.addRoute("#/profile", pages.profile); +router.addRoute("#/login", pages.login); +router.addRoute("#/error", pages.error); router.handleRoute(); diff --git a/src/pages/Main.js b/src/pages/Main.js index d0d3dceb..43602d6f 100644 --- a/src/pages/Main.js +++ b/src/pages/Main.js @@ -24,10 +24,20 @@ class MainPage extends Component { logout(); } - template() { + isMainPage() { const currentPath = window.location.pathname; - const auth = getAuth(); + const currentHash = window.location.hash; + // 현재 경로가 "/"이고 해시가 없거나 "#"인 경우 + if (currentPath === "/" || currentHash === "#/") { + return true; + } + + return false; + } + + template() { + const auth = getAuth(); return `
    @@ -35,12 +45,12 @@ class MainPage extends Component {

    항해플러스

    -