-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from khoaxuantu/dev
Add guestbook
- Loading branch information
Showing
46 changed files
with
916 additions
and
281 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# For fetching backend API | ||
REACT_APP_BACKEND_DOMAIN= | ||
|
||
# For oauth | ||
REACT_APP_GOOGLE_CLIENT_ID= | ||
REACT_APP_GITHUB_CLIENT_ID= |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} | ||
{"name":"","short_name":"","icons":[{"src":"/logo/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/logo/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { Link } from "react-router-dom"; | ||
|
||
export default function AboutHeaderGrp () { | ||
return ( | ||
<div className='header-grp'> | ||
<div className="header-txt"> | ||
<b>Hi there! I'm Tu</b> | ||
</div> | ||
<div className='description-txt mt-2'> | ||
<b>Xuan Khoa Tu Nguyen | 阮春科秀 | Tu | Nguyễn Xuân Khoa Tú</b> | ||
</div> | ||
<div className="description-txt mt-3"> | ||
~ You can call me by any name ~ | ||
</div> | ||
<div className='description-txt mt-3'> | ||
<Link to="/">Menu</Link> | {" "} | ||
<a href="https://drive.google.com/file/d/1UdFJgT35HysZGTpfk86I3E8Mcg2vrfv3/view?usp=share_link" target='_blank' rel="noreferrer">Resume</a> | {" "} | ||
<a href="https://drive.google.com/file/d/1XxdNzIyDktPseomnn0HszhgMyfEW8TtV/view?usp=share_link" target='_blank' rel='noreferrer'>CV</a> | ||
</div> | ||
<hr></hr> | ||
</div> | ||
); | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { motion as m } from "framer-motion"; | ||
import AboutHeaderGrp from "./header"; | ||
import AboutIntro from "./introduction"; | ||
import Works from "./works"; | ||
import Education from "./edu"; | ||
import { AboutProject } from "../projects/projects"; | ||
import Copyright from "../copyright"; | ||
|
||
export default function AboutPage() { | ||
return ( | ||
<m.div | ||
transition={{ duration: 0.8 }} | ||
exit={{ opacity: 0 }} | ||
className="container page-wrapper transition-page"> | ||
<AboutHeaderGrp /> | ||
<div className="content-grp"> | ||
<AboutIntro /> | ||
<Education /> | ||
<Works /> | ||
<AboutProject /> | ||
</div> | ||
<Copyright copyright_class="page-copyright pb-3" /> | ||
</m.div> | ||
); | ||
} |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { blogInfoList } from "../../lib/general_info"; | ||
import { BlogsList, SingleBlog } from "./blogs"; | ||
|
||
export function BlogsContent() { | ||
/* blogInfoList needs sorting first */ | ||
blogInfoList.sort((a, b) => { | ||
const dateA = new Date(a.date); | ||
const dateB = new Date(b.date); | ||
if (dateA < dateB) return 1; | ||
else if (dateA > dateB) return -1; | ||
else return 0; | ||
}); | ||
|
||
return ( | ||
<div className="blog-wrapper"> | ||
<BlogsList blogInfoList={blogInfoList} /> | ||
</div> | ||
); | ||
} | ||
|
||
export function SingleBlogContent(props: {id: string}) { | ||
return ( | ||
<article className="single-blog-wrapper transition-blog"> | ||
<SingleBlog id={props.id} /> | ||
</article> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { blogInfoDict } from "../../lib/general_info"; | ||
|
||
export function BlogsPageHeaderGrp() { | ||
return ( | ||
<div className='header-grp'> | ||
<div className='header-txt'> | ||
<b>Blogs</b> | ||
</div> | ||
<div className='description-txt mt-2'> | ||
Some notes, some ideas, some opinions | ||
</div> | ||
<hr /> | ||
</div> | ||
); | ||
} | ||
|
||
export function SingleBlogPageHeaderGrp(props: {id: string}) { | ||
return ( | ||
<div className='header-grp'> | ||
<div className='header-txt'> | ||
<b>{blogInfoDict[props.id].title}</b> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { BlogsPageHeaderGrp } from "./header"; | ||
import { BlogsContent } from "./contents"; | ||
|
||
export default function BlogsPage() { | ||
return ( | ||
<> | ||
<BlogsPageHeaderGrp /> | ||
<BlogsContent /> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { useParams } from "react-router-dom"; | ||
import { SingleBlogPageHeaderGrp } from "./header"; | ||
import { SingleBlogContent } from "./contents"; | ||
|
||
export default function SingleBlogPage() { | ||
const { blogId } = useParams(); | ||
|
||
return ( | ||
<> | ||
<SingleBlogPageHeaderGrp id={blogId as string} /> | ||
<hr></hr> | ||
<SingleBlogContent id={blogId as string} /> | ||
</> | ||
); | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { LoginButton } from "../../lib/factory/buttonBase"; | ||
import { useNavigate } from "react-router-dom"; | ||
import { oauthInfoList } from "../../lib/general_info"; | ||
import { useGoogleLogin } from "@react-oauth/google"; | ||
|
||
const { | ||
REACT_APP_BACKEND_DOMAIN, | ||
REACT_APP_GITHUB_CLIENT_ID } = process.env; | ||
|
||
export function SignIn() { | ||
|
||
/** | ||
* Login with Github will redirect user to an authorization callback URL | ||
* so I redirect to a new route "/oauth" instead of back to this route "/guestbook" | ||
* | ||
* At route "/oauth", the received authorization code will be fetched to | ||
* the backend api to process authentication. After backend responses | ||
* a access_token successfully, users will be redirected back to "/guestbook" | ||
*/ | ||
function loginWithGithub() { | ||
window.location.assign("https://github.com/login/oauth/authorize?client_id=" + REACT_APP_GITHUB_CLIENT_ID); | ||
} | ||
|
||
/** | ||
* Login with Google uses @react-oauth/google library, which authorizes | ||
* in popup mode. The code is returned to in-browser's app callback handler, | ||
* without users needing to leave the website | ||
* | ||
* https://developers.google.com/identity/oauth2/web/guides/how-user-authz-works#when_using_the_auth_code_flow | ||
*/ | ||
let navigate = useNavigate(); | ||
const loginWithGoogle = useGoogleLogin({ | ||
onSuccess: async ({code}) => { | ||
if (localStorage.getItem("accessToken") === null) { | ||
await fetch(`${REACT_APP_BACKEND_DOMAIN}/oauth/google/access_token?code=` + code, { | ||
method: "GET" | ||
}) | ||
.then(response => response.json()) | ||
.then(data => { | ||
if (data.access_token) { | ||
localStorage.setItem("accessToken", data.access_token); | ||
localStorage.setItem("third-party", "google"); | ||
return navigate("/guestbook"); | ||
} | ||
}); | ||
} | ||
}, | ||
flow: "auth-code", | ||
}); | ||
|
||
const onClickHandlers: any[] = [ | ||
loginWithGithub, | ||
() => loginWithGoogle() | ||
]; | ||
|
||
return ( | ||
<> | ||
{ | ||
oauthInfoList.map((oauth, index) => { | ||
return ( | ||
<div key={oauth.name} className="col-6 btn-oauth-box"> | ||
<LoginButton | ||
onClick={onClickHandlers[index]} | ||
{...oauth} /> | ||
</div> | ||
); | ||
}) | ||
} | ||
</> | ||
); | ||
} | ||
|
||
export function SignOut() { | ||
let navigate = useNavigate(); | ||
|
||
function logOut() { | ||
localStorage.removeItem("third-party"); | ||
localStorage.removeItem("data"); | ||
return navigate("/guestbook"); | ||
} | ||
|
||
return ( | ||
<button className="btn btn-rect" onClick={logOut}> | ||
Sign out | ||
</button> | ||
); | ||
} |
Oops, something went wrong.