From 634bebca0070eed442e668a87bd5cc6dda38216c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Sat, 7 Dec 2024 16:14:16 +0900
Subject: [PATCH 1/5] =?UTF-8?q?chore:=20user=20=EC=83=81=ED=83=9C=EA=B4=80?=
 =?UTF-8?q?=EB=A6=AC=20justand=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=84=A4?=
 =?UTF-8?q?=EC=B9=98=20(#10)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 package-lock.json | 31 ++++++++++++++++++++++++++++++-
 package.json      |  3 ++-
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index d9e2f70..671b138 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -30,7 +30,8 @@
         "workbox-range-requests": "^6.6.0",
         "workbox-routing": "^6.6.0",
         "workbox-strategies": "^6.6.0",
-        "workbox-streams": "^6.6.0"
+        "workbox-streams": "^6.6.0",
+        "zustand": "^5.0.2"
       },
       "devDependencies": {
         "tailwindcss": "^3.4.15"
@@ -16441,6 +16442,34 @@
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
+    },
+    "node_modules/zustand": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.2.tgz",
+      "integrity": "sha512-8qNdnJVJlHlrKXi50LDqqUNmUbuBjoKLrYQBnoChIbVph7vni+sY+YpvdjXG9YLd/Bxr6scMcR+rm5H3aSqPaw==",
+      "engines": {
+        "node": ">=12.20.0"
+      },
+      "peerDependencies": {
+        "@types/react": ">=18.0.0",
+        "immer": ">=9.0.6",
+        "react": ">=18.0.0",
+        "use-sync-external-store": ">=1.2.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "immer": {
+          "optional": true
+        },
+        "react": {
+          "optional": true
+        },
+        "use-sync-external-store": {
+          "optional": true
+        }
+      }
     }
   }
 }
diff --git a/package.json b/package.json
index 032f68f..a8aeba3 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,8 @@
     "workbox-range-requests": "^6.6.0",
     "workbox-routing": "^6.6.0",
     "workbox-strategies": "^6.6.0",
-    "workbox-streams": "^6.6.0"
+    "workbox-streams": "^6.6.0",
+    "zustand": "^5.0.2"
   },
   "scripts": {
     "start": "react-scripts start",
-- 
GitLab


From 39016ad6a8d53acc95b7ac37acc4eea23d9da234 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Sat, 7 Dec 2024 16:15:19 +0900
Subject: [PATCH 2/5] =?UTF-8?q?remove:=20=EC=9E=90=EC=B2=B4=EB=A1=9C?=
 =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=82=AD=EC=A0=9C,=20=EC=86=8C=EC=85=9C?=
 =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=EC=9C=BC=EB=A1=9C=20=ED=86=B5?=
 =?UTF-8?q?=ED=95=A9=20(#10)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/App.js               | 2 --
 src/pages/SignUpPage.jsx | 7 -------
 2 files changed, 9 deletions(-)
 delete mode 100644 src/pages/SignUpPage.jsx

diff --git a/src/App.js b/src/App.js
index 43a9c0d..af5e2cb 100644
--- a/src/App.js
+++ b/src/App.js
@@ -2,7 +2,6 @@ import React from "react";
 import "./styles/globals.css";
 import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
 import LoginPage from "./pages/LoginPage";
-import SignupPage from "./pages/SignUpPage";
 import HomePage from "./pages/HomePage";
 import ChattingListPage from "./pages/Chatting/ChattingListPage";
 import MyPage from "./pages/Mypage";
@@ -25,7 +24,6 @@ const App = () => {
             <Route path="/chattinglist" element={<ChattingListPage />} />
             <Route path="/mypage" element={<MyPage />} />
             <Route path="/login" element={<LoginPage />} />
-            <Route path="/signup" element={<SignupPage />} />
           </Routes>
         </BodyLayout>
         <Footer />
diff --git a/src/pages/SignUpPage.jsx b/src/pages/SignUpPage.jsx
deleted file mode 100644
index 4a4bbb5..0000000
--- a/src/pages/SignUpPage.jsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import React from "react";
-
-const SignupPage = () => {
-  return <></>;
-};
-
-export default SignupPage;
-- 
GitLab


From 64aa439bc7eeca7a40d038f2168ebc3ee5f06a0c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Sat, 7 Dec 2024 16:15:46 +0900
Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?=
 =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B0=9C=EB=B0=9C=20(#10)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/api/auth.js                         | 54 +++++++++++++++
 src/components/icons/GoogleLogoIcon.jsx | 28 ++++++++
 src/pages/LoginPage.jsx                 | 89 ++++++++++++++++++++++++-
 src/store/authStore.js                  | 29 ++++++++
 4 files changed, 198 insertions(+), 2 deletions(-)
 create mode 100644 src/api/auth.js
 create mode 100644 src/components/icons/GoogleLogoIcon.jsx
 create mode 100644 src/store/authStore.js

diff --git a/src/api/auth.js b/src/api/auth.js
new file mode 100644
index 0000000..df4042f
--- /dev/null
+++ b/src/api/auth.js
@@ -0,0 +1,54 @@
+// src/api/auth.js
+
+/**
+ * Google 로그인 URL 반환
+ * @returns {string} 로그인 엔드포인트 URL
+ */
+export const getLoginUrl = () => {
+  return `${process.env.REACT_APP_BASE_URL}/api/auth/login`;
+};
+
+/**
+ * 로그아웃 API 호출
+ * @returns {Promise<void>}
+ */
+export const logout = async () => {
+  try {
+    const response = await fetch(
+      `${process.env.REACT_APP_BASE_URL}/api/auth/logout`,
+      {
+        method: "GET",
+        credentials: "include", // 세션 쿠키 포함
+      }
+    );
+    if (!response.ok) {
+      throw new Error("Failed to logout");
+    }
+  } catch (error) {
+    console.error("Error during logout:", error);
+    throw error;
+  }
+};
+
+/**
+ * 세션 정보 확인 API 호출
+ * @returns {Promise<Object|null>} 세션이 있으면 사용자 정보 반환, 없으면 null 반환
+ */
+export const getSessionInfo = async () => {
+  try {
+    const response = await fetch(
+      `${process.env.REACT_APP_BASE_URL}/api/session/info`,
+      {
+        method: "GET",
+        credentials: "include", // 세션 쿠키 포함
+      }
+    );
+    if (response.ok) {
+      return await response.json(); // 사용자 정보 반환
+    }
+    return null; // 세션 없음
+  } catch (error) {
+    console.error("Error checking session info:", error);
+    throw error;
+  }
+};
diff --git a/src/components/icons/GoogleLogoIcon.jsx b/src/components/icons/GoogleLogoIcon.jsx
new file mode 100644
index 0000000..a28ef03
--- /dev/null
+++ b/src/components/icons/GoogleLogoIcon.jsx
@@ -0,0 +1,28 @@
+export default function GoogleLogo({ className, ...props }) {
+  return (
+    <svg
+      xmlns="http://www.w3.org/2000/svg"
+      width="20"
+      height="20"
+      viewBox="0 0 20 20"
+      fill="none"
+    >
+      <path
+        d="M16.5883 17.58C18.951 15.3748 20.0011 11.6995 19.371 8.18164H9.97266V12.067H15.3281C15.1181 13.3271 14.3831 14.3772 13.333 15.0598L16.5883 17.58Z"
+        fill="#4285F4"
+      />
+      <path
+        d="M1.04688 14.4824C1.73758 15.843 2.72813 17.0291 3.94387 17.9512C5.15962 18.8733 6.56882 19.5074 8.06526 19.8056C9.5617 20.1039 11.1063 20.0586 12.5827 19.6731C14.0591 19.2876 15.4287 18.572 16.5883 17.5802L13.333 15.06C10.5502 16.8976 5.92982 16.2151 4.35467 11.9097L1.04688 14.4824Z"
+        fill="#34A853"
+      />
+      <path
+        d="M4.35584 11.9095C3.93581 10.5969 3.93581 9.38926 4.35584 8.07664L1.04804 5.50391C-0.159565 7.91912 -0.527099 11.3319 1.04804 14.4822L4.35584 11.9095Z"
+        fill="#FBBC02"
+      />
+      <path
+        d="M4.35467 8.07674C5.50978 4.45391 10.4452 2.35372 13.753 5.4515L16.6408 2.61624C12.5454 -1.32161 4.56469 -1.1641 1.04688 5.50401L4.35467 8.07674Z"
+        fill="#EA4335"
+      />
+    </svg>
+  );
+}
diff --git a/src/pages/LoginPage.jsx b/src/pages/LoginPage.jsx
index f93bbc0..00aa883 100644
--- a/src/pages/LoginPage.jsx
+++ b/src/pages/LoginPage.jsx
@@ -1,7 +1,92 @@
-import React from "react";
+import React, { useEffect, useState } from "react";
+import GoogleLogo from "../components/icons/GoogleLogoIcon";
+import Button from "../components/Button";
+import { getLoginUrl } from "../api/auth";
+import useAuthStore from "../store/authStore";
 
 const LoginPage = () => {
-  return <></>;
+  const { user, fetchSession, logoutUser } = useAuthStore();
+  const [loading, setLoading] = useState(true);
+
+  // 페이지 로드 시 세션 확인
+  useEffect(() => {
+    const fetchSessionInfo = async () => {
+      setLoading(true);
+      try {
+        await fetchSession(); // 세션 정보 가져오기
+      } catch (error) {
+        console.error("Failed to fetch session info:", error);
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchSessionInfo();
+  }, [fetchSession]);
+
+  // Google 로그인 처리
+  const handleGoogleLogin = () => {
+    const loginUrl = getLoginUrl(); // 로그인 URL 가져오기
+    window.location.href = loginUrl; // 리다이렉트
+  };
+
+  // 로그아웃 처리
+  const handleLogout = async () => {
+    try {
+      setLoading(true);
+      await logoutUser();
+    } catch (error) {
+      console.error("Failed to logout:", error);
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  if (loading) {
+    return (
+      <div className="flex items-center justify-center min-h-screen">
+        <p>Loading...</p>
+      </div>
+    );
+  }
+
+  if (user) {
+    return (
+      <div className="flex items-center justify-center min-h-screen p-4 bg-gray-100">
+        <div className="flex flex-col items-center justify-center min-w-[260px] w-1/2 max-w-md p-8 space-y-4 bg-white rounded-lg shadow-lg">
+          <div>
+            <h2 className="text-center heading-2">환영합니다!</h2>
+            <h2 className="text-center heading-1">
+              <span className="text-primary-500">{user.name}</span>님
+            </h2>
+          </div>
+          <p className="text-center text-gray-700">
+            <span className="text-primary-500 title-1">번개모임</span>을 생성해
+            보세요!
+          </p>
+          <Button size="md" theme="black" onClick={handleLogout}>
+            로그아웃
+          </Button>
+        </div>
+      </div>
+    );
+  }
+
+  return (
+    <div className="flex items-center justify-center min-h-screen p-4 bg-gray-100">
+      <div className="flex flex-col items-center min-w-[260px] justify-center w-1/2 max-w-md p-8 space-y-6 bg-white rounded-lg shadow-lg">
+        <h2 className="text-2xl font-bold text-center text-gray-900">로그인</h2>
+        <Button
+          size="md"
+          theme="white"
+          icon={<GoogleLogo />}
+          onClick={handleGoogleLogin}
+        >
+          구글로 로그인
+        </Button>
+      </div>
+    </div>
+  );
 };
 
 export default LoginPage;
diff --git a/src/store/authStore.js b/src/store/authStore.js
new file mode 100644
index 0000000..2bf688c
--- /dev/null
+++ b/src/store/authStore.js
@@ -0,0 +1,29 @@
+import { create } from "zustand";
+import { getSessionInfo, logout } from "../api/auth";
+
+const useAuthStore = create((set) => ({
+  user: null, // 사용자 정보
+
+  // 세션 정보 가져오기
+  fetchSession: async () => {
+    try {
+      const userInfo = await getSessionInfo();
+      set({ user: userInfo });
+    } catch (error) {
+      console.error("Failed to fetch session info:", error);
+      set({ user: null });
+    }
+  },
+
+  // 로그아웃 처리
+  logoutUser: async () => {
+    try {
+      await logout();
+      set({ user: null });
+    } catch (error) {
+      console.error("Failed to logout:", error);
+    }
+  },
+}));
+
+export default useAuthStore;
-- 
GitLab


From 628a44e123dac335135d38e65da0134b51791473 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Sat, 7 Dec 2024 16:16:15 +0900
Subject: [PATCH 4/5] =?UTF-8?q?fix:=20=EB=B0=B1=EC=97=94=EB=93=9C=20?=
 =?UTF-8?q?=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EC=A3=BC?=
 =?UTF-8?q?=EC=86=8C=20=EC=88=98=EC=A0=95=20(#10)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/api/schedule.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/api/schedule.js b/src/api/schedule.js
index bb36ad4..c59a852 100644
--- a/src/api/schedule.js
+++ b/src/api/schedule.js
@@ -1,5 +1,5 @@
 // api.js
-const baseURL = process.env.REACT_APP_BACKEND_BASE_URL;
+const baseURL = process.env.REACT_APP_BASE_URL;
 
 // Fetch all schedules
 export const fetchAllSchedules = async () => {
-- 
GitLab


From 3f31ecafeb5addd0be340448ca0344c120ad46a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=84=9D=EC=B0=AC=20=EC=9C=A4?= <ysc0731@ajou.ac.kr>
Date: Sat, 7 Dec 2024 16:29:49 +0900
Subject: [PATCH 5/5] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?=
 =?UTF-8?q?=EC=83=81=ED=83=9C=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=97=A4?=
 =?UTF-8?q?=EB=94=A9=EB=B0=94=20=EB=B3=80=ED=98=95=20(#10)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/components/layout/HeaderLogoBar.jsx | 14 ++++++++-
 src/components/layout/HeaderNav.jsx     | 42 +++++++++++++++----------
 src/store/authStore.js                  |  1 +
 3 files changed, 39 insertions(+), 18 deletions(-)

diff --git a/src/components/layout/HeaderLogoBar.jsx b/src/components/layout/HeaderLogoBar.jsx
index 0b8aef8..4e08f2d 100644
--- a/src/components/layout/HeaderLogoBar.jsx
+++ b/src/components/layout/HeaderLogoBar.jsx
@@ -1,12 +1,24 @@
+import React from "react";
 import LogoIcon from "../icons/LogoIcon";
+import useAuthStore from "../../store/authStore";
 
 const HeaderLogoBar = () => {
+  const { user } = useAuthStore(); // Zustand에서 user 상태 가져오기
+
   return (
-    <div className="flex items-center justify-start w-full h-16 px-4 bg-white">
+    <div className="flex items-center justify-between w-full h-16 px-4 bg-white">
+      {/* 왼쪽: 로고와 앱 이름 */}
       <div className="flex items-center">
         <LogoIcon width={32} height={32} />
         <span className="title-1">YANAWA</span>
       </div>
+
+      {/* 오른쪽: 사용자 이름 */}
+      <div className="flex items-center">
+        <span className="text-gray-600 label-1">
+          {user ? `${user.name}` : "guest"} 님
+        </span>
+      </div>
     </div>
   );
 };
diff --git a/src/components/layout/HeaderNav.jsx b/src/components/layout/HeaderNav.jsx
index e1d5d5d..2dba5ad 100644
--- a/src/components/layout/HeaderNav.jsx
+++ b/src/components/layout/HeaderNav.jsx
@@ -2,10 +2,12 @@ import React, { useState, useEffect } from "react";
 import { useNavigate } from "react-router-dom";
 import Button from "../Button";
 import LogoIcon from "../icons/LogoIcon";
+import useAuthStore from "../../store/authStore";
 
 export default function HeaderNav() {
   const navigate = useNavigate();
   const [isMobile, setIsMobile] = useState(false);
+  const { user } = useAuthStore(); // Zustand에서 user 상태 가져오기
 
   useEffect(() => {
     const checkMobile = () => setIsMobile(window.innerWidth <= 768);
@@ -18,6 +20,7 @@ export default function HeaderNav() {
   const navigateToHome = () => navigate("/");
   const navigateToChattingList = () => navigate("/chattinglist");
   const navigateToLogin = () => navigate("/login");
+  const navigateToMyPage = () => navigate("/mypage");
 
   return (
     <header className="bg-white shadow-md">
@@ -47,20 +50,14 @@ export default function HeaderNav() {
                 size="icon"
                 theme="black"
                 icon={<LogoIcon fillColor="#ffffff" />}
-                onClick={navigateToLogin}
+                onClick={user ? navigateToMyPage : navigateToLogin} // 조건부 이동
               />
             </>
           ) : (
             <>
-              <Button
-                size="icon"
-                theme="pink"
-                icon={<LogoIcon fillColor="#ffffff" />}
-                onClick={navigateToHome}
-              />
               <Button
                 size="lg"
-                theme="purple"
+                theme="pink"
                 icon={<LogoIcon fillColor="#ffffff" />}
                 onClick={navigateToHome}
               >
@@ -68,7 +65,7 @@ export default function HeaderNav() {
               </Button>
               <Button
                 size="lg"
-                theme="indigo"
+                theme="purple"
                 icon={<LogoIcon fillColor="#ffffff" />}
                 onClick={navigateToTimeTable}
               >
@@ -82,14 +79,25 @@ export default function HeaderNav() {
               >
                 번개채팅방
               </Button>
-              <Button
-                size="lg"
-                theme="black"
-                icon={<LogoIcon fillColor="#ffffff" />}
-                onClick={navigateToLogin}
-              >
-                로그인
-              </Button>
+              {user ? (
+                <Button
+                  size="lg"
+                  theme="black"
+                  icon={<LogoIcon fillColor="#ffffff" />}
+                  onClick={navigateToMyPage}
+                >
+                  마이페이지
+                </Button>
+              ) : (
+                <Button
+                  size="lg"
+                  theme="black"
+                  icon={<LogoIcon fillColor="#ffffff" />}
+                  onClick={navigateToLogin}
+                >
+                  로그인
+                </Button>
+              )}
             </>
           )}
         </div>
diff --git a/src/store/authStore.js b/src/store/authStore.js
index 2bf688c..1d1223b 100644
--- a/src/store/authStore.js
+++ b/src/store/authStore.js
@@ -3,6 +3,7 @@ import { getSessionInfo, logout } from "../api/auth";
 
 const useAuthStore = create((set) => ({
   user: null, // 사용자 정보
+  // user: { name: "윤석찬", email: "ysc0731@ajou.ac.kr" }, // 사용자 정보
 
   // 세션 정보 가져오기
   fetchSession: async () => {
-- 
GitLab