Skip to content

Commit

Permalink
Merge pull request #1 from handong-app/#1/login-backend
Browse files Browse the repository at this point in the history
[HFEED-1] 구글 로그인 기능 (백)
  • Loading branch information
junglesub authored Sep 23, 2024
2 parents 358bd1a + 1780701 commit 075ba86
Show file tree
Hide file tree
Showing 36 changed files with 1,803 additions and 19 deletions.
38 changes: 38 additions & 0 deletions src/main/front/package-lock.json

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

2 changes: 2 additions & 0 deletions src/main/front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@react-oauth/google": "^0.12.1",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
Expand All @@ -13,6 +14,7 @@
"react-router-dom": "^6.23.1",
"react-scripts": "5.0.1",
"react-show-more-text": "git+git@github.com:junglesub/react-show-more-text.git",
"recoil": "^0.7.7",
"sass": "^1.77.8",
"web-vitals": "^2.1.4"
},
Expand Down
42 changes: 42 additions & 0 deletions src/main/front/src/components/LoginProtected.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { useEffect, useState } from "react";
import { useRecoilState, useRecoilValue } from "recoil";
import { authJwtAtom } from "../recoil/authAtom";
import { Navigate } from "react-router-dom";
import { userDetailAtom } from "../recoil/userAtom";
import { fetchBe } from "../tools/api";

function LoginProtected({ comp: Comp }) {
const jwtValue = useRecoilValue(authJwtAtom);
const [userData, setUserData] = useRecoilState(userDetailAtom);
const [userDataLoading, setUserDataLoading] = useState(true);
const [userDataError, setUserDataError] = useState();

useEffect(() => {
fetchBe(jwtValue, "/userDetail/get")
.then((json) => {
console.log("Got User Data", json);
if (json.weight) setUserData(json);
else setUserData(null);
setUserDataLoading(false);
})
.catch((e) => setUserDataError(e.message));
}, [jwtValue]);

if (jwtValue) {
if (typeof Comp === "object") return <>{Comp}</>;
// if (userDataError)
// return <div style={{ color: "pink" }}>Error: {userDataError}</div>;
// if (userDataLoading)
// return <div style={{ color: "white" }}>Loading User Data...</div>;

// if (!!userData) {
return <Comp />;
// } else {
// return <Navigate to="/" />;
// }
}

return <Navigate to="/" />;
}

export default LoginProtected;
7 changes: 7 additions & 0 deletions src/main/front/src/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const serverRootUrl =
!process.env.NODE_ENV || process.env.NODE_ENV === "development"
? "/api"
: "/api";

export const googleClientId =
"542164017545-c6tsebe44kpkpk43b7u8njouir63oqq8.apps.googleusercontent.com";
14 changes: 9 additions & 5 deletions src/main/front/src/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import NewUI from "./pages/NewUI";
import Admin from "./pages/Admin";
import { RecoilRoot } from "recoil";
import LoginProtected from "./components/LoginProtected";
import MainScreen from "./pages/MainScreen";

const router = createBrowserRouter([
{
path: "/",
element: <NewUI />,
element: <MainScreen />,
},
{
path: "/newui",
element: <App />,
path: "/feed",
element: <LoginProtected comp={NewUI} />,
},
{
path: "/admin",
Expand All @@ -24,7 +26,9 @@ const router = createBrowserRouter([
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<RouterProvider router={router} />
<RecoilRoot>
<RouterProvider router={router} />
</RecoilRoot>
</React.StrictMode>
);

Expand Down
142 changes: 142 additions & 0 deletions src/main/front/src/pages/MainScreen.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import React from "react";
import { GoogleOAuthProvider, GoogleLogin } from "@react-oauth/google";
import { googleClientId } from "../constants";
import { useRecoilValue, useResetRecoilState, useSetRecoilState } from "recoil";
import { authJwtAtom } from "../recoil/authAtom";
import { useNavigate } from "react-router-dom";

import "./MainScreen.scss";

const GoogleLoginComponent = () => {
const navigate = useNavigate();
const setJwt = useSetRecoilState(authJwtAtom);
const handleLoginSuccess = (credentialResponse) => {
console.log("Encoded JWT ID token: " + credentialResponse.credential);

// Send the Google ID token to the server
fetch("/api/tbuser/login/google", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ credential: credentialResponse.credential }),
})
.then((response) => response.json())
.then((data) => {
console.log("Response from server:", data);
if (data.token) {
localStorage.setItem("happ_feed_token", JSON.stringify(data.token)); // Incase of strictmode error
setJwt(data.token);
// navigate("/feed");
} else {
alert("Login failed: " + data.message);
}
})
.catch((error) => console.error("Error:", error));
};

const handleLoginError = () => {
console.log("Login Failed");
};

return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<GoogleLogin onSuccess={handleLoginSuccess} onError={handleLoginError} />
</div>
);
};

const MainScreen = () => {
const authData = useRecoilValue(authJwtAtom);
const logout = useResetRecoilState(authJwtAtom);
// if (authData) return <>Welcome</>;
return (
<>
<div className="MainScreen">
{/* Header */}
<header className="header">
<nav className="navbar">
<h1 className="logo">한동Feed</h1>
<ul className="nav-links">
<li>
<a href="#home">Home</a>
</li>
<li>
<a href="#features">Features</a>
</li>
<li>
<a href="#contact">Contact</a>
</li>
</ul>
</nav>
</header>

{/* Hero Section */}
<section id="home" className="hero-section">
<div className="hero-content">
<h1>한동 피드에 오신 것을 환영합니다</h1>
<p>한동의 모든 정보통을 모아두었습니다</p>
{authData ? (
<a href="/feed" className="cta-btn">
한동 피드로 이동하기
</a>
) : (
<span className="glogin">
<GoogleOAuthProvider clientId={googleClientId}>
<GoogleLoginComponent />
</GoogleOAuthProvider>
</span>
)}
</div>
</section>

{/* Features Section */}
<section id="features" className="features-section">
<h2>Features</h2>
<div className="features-grid">
<div className="feature-card">
<h3>정보가 한곳에</h3>
<p>
실명카톡방, 히즈넷 (예정) 공지사항을 한곳에서 볼 수 있습니다.
</p>
</div>
<div className="feature-card">
<h3>학생들이 직접 만드는</h3>
<p>
오픈소스로 관리가 되어 학생들이 직접 만들고 수정하는
프로젝트입니다
</p>
</div>
<div className="feature-card">
<h3>보안</h3>
<p>학교 이메일로 인증받은 사람만 이용할 수 있습니다.</p>
</div>
</div>
</section>

{/* Contact Section */}
<section id="contact" className="contact-section">
<h2>Contact Us</h2>
<p>문의사항이 있으시면 아래 메일로 보내주세요</p>
<a href="mailto:feed@handong.app" className="cta-btn">
feed@handong.app
</a>
</section>

{/* Footer */}
<footer className="footer">
<p>© 2024 Handong Feed. All rights reserved.</p>
</footer>
</div>
<div onClick={() => logout()}>Logout</div>
</>
);
};

export default MainScreen;
Loading

0 comments on commit 075ba86

Please sign in to comment.