From 4950a0663c00dbd34143ce84ea0e105b2ad09c3f Mon Sep 17 00:00:00 2001 From: Tristan Yang Date: Sun, 30 Oct 2022 22:12:25 +0800 Subject: [PATCH] feat: github login --- public/widget.html | 2 + public/widget.js | 11 ++- src/common/component/GithubLoginButton.tsx | 69 ++++++++----------- src/routes/callback/GithubCallback.tsx | 69 +++++++++++++++++++ src/routes/callback/index.tsx | 12 +++- src/widget/Popup/Header.tsx | 10 +-- src/widget/Popup/Login/index.tsx | 4 +- src/widget/Popup/MessageFeed/Message/Text.tsx | 20 +++--- src/widget/Popup/Welcome.tsx | 8 +-- src/widget/Popup/index.tsx | 7 +- src/widget/index.tsx | 12 ++-- 11 files changed, 149 insertions(+), 75 deletions(-) create mode 100644 src/routes/callback/GithubCallback.tsx diff --git a/public/widget.html b/public/widget.html index 33a95353..e21f6fd2 100644 --- a/public/widget.html +++ b/public/widget.html @@ -13,6 +13,8 @@ #root { height: 100%; background: transparent; + width: auto; + height: auto; } diff --git a/public/widget.js b/public/widget.js index 69e6d750..7c1107da 100644 --- a/public/widget.js +++ b/public/widget.js @@ -11,7 +11,8 @@ const styles = { position: "fixed", right: "15px", bottom: "15px", - border: "none" + border: "none", + zIndex: 9999 }; Object.assign(wrapper.style, styles); wrapper.src = `${domain}/widget.html?host=${hostId}`; @@ -31,6 +32,14 @@ window.addEventListener( wrapper.setAttribute("width", closeWidth); wrapper.setAttribute("height", closeHeight); break; + case "RELOAD_WITH_OPEN": + { + const url = new URL(wrapper.src); + url.searchParams.append("open", new Date().getTime()); + console.log("new src", url.href); + wrapper.src = url.href; + } + break; default: break; } diff --git a/src/common/component/GithubLoginButton.tsx b/src/common/component/GithubLoginButton.tsx index f3869ba3..91514264 100644 --- a/src/common/component/GithubLoginButton.tsx +++ b/src/common/component/GithubLoginButton.tsx @@ -1,12 +1,7 @@ -import { useEffect, FC } from "react"; +import { FC, useEffect } from "react"; import IconGithub from "../../assets/icons/github.svg"; import styled from "styled-components"; -import { KEY_LOCAL_MAGIC_TOKEN } from "../../app/config"; - import Button from "./styled/Button"; -import { useLoginMutation } from "../../app/services/auth"; -import toast from "react-hot-toast"; -import { FetchBaseQueryError } from "@reduxjs/toolkit/dist/query"; const StyledSocialButton = styled(Button)` width: 100%; @@ -25,52 +20,42 @@ const StyledSocialButton = styled(Button)` `; type Props = { + source?: "widget" | "webapp", client_id?: string; type?: "login" | "register"; }; -const GithubLoginButton: FC = ({ type = "login", client_id }) => { - //拿本地存的magic token - const magic_token = localStorage.getItem(KEY_LOCAL_MAGIC_TOKEN); - const [login, { isLoading, isSuccess, error }] = useLoginMutation(); +const GithubLoginButton: FC = ({ type = "login", source = "webapp", client_id }) => { useEffect(() => { - const query = new URLSearchParams(location.search); - const isGithub = query.get("oauth") === "github"; - const code = query.get("code"); - if (isGithub && code) { - login({ - magic_token, - code: code, - type: "github" - }); - } - }, []); - useEffect(() => { - if (isSuccess) { - toast.success("Login Successfully"); - } - }, [isSuccess]); - useEffect(() => { - if (error) { - // todo: why? - switch ((error as FetchBaseQueryError).status) { - case 410: - toast.error( - "No associated account found, please user admin for an invitation link to join." - ); - break; - default: - toast.error("Something Error"); - break; + const handleGithubLoginStatusChange = (evt: StorageEvent) => { + const { key, newValue } = evt; + if (key == 'widget' && !!newValue) { + console.log("github logged in"); + localStorage.removeItem("widget"); + const parentWindow = window.parent; + if (parentWindow) { + parentWindow.postMessage("RELOAD_WITH_OPEN", '*'); + } } - return; + }; + if (source == "widget") { + window.addEventListener("storage", handleGithubLoginStatusChange); } - }, [error]); + + return () => { + if (source == "widget") { + window.removeEventListener("storage", handleGithubLoginStatusChange); + } + }; + }, [source]); + const handleGithubLogin = () => { - location.href = `https://github.com/login/oauth/authorize?client_id=${client_id}`; + window.open(`https://github.com/login/oauth/authorize?client_id=${client_id}&redirect_uri=${location.origin}/#/cb/github/${source}`); + // location.href = `https://github.com/login/oauth/authorize?client_id=${client_id}`; }; + return ( - + {` ${type === "login" ? "Sign in" : "Sign up"} with Github`} diff --git a/src/routes/callback/GithubCallback.tsx b/src/routes/callback/GithubCallback.tsx new file mode 100644 index 00000000..01cbe666 --- /dev/null +++ b/src/routes/callback/GithubCallback.tsx @@ -0,0 +1,69 @@ +import { useEffect, FC } from 'react'; +import styled from 'styled-components'; +import { KEY_LOCAL_MAGIC_TOKEN } from "../../app/config"; +import { useLoginMutation } from "../../app/services/auth"; +import toast from "react-hot-toast"; +import { FetchBaseQueryError } from "@reduxjs/toolkit/dist/query"; + +const Styled = styled.section` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 10px; + .success{ + font-size: 30px; + font-weight: bold; + color: green; + } +`; +export type GithubLoginSource = "widget" | "webapp" +type Props = { + code: string, from?: GithubLoginSource +} +const GithubCallback: FC = ({ code, from = "webapp" }) => { + //拿本地存的magic token + const magic_token = localStorage.getItem(KEY_LOCAL_MAGIC_TOKEN); + const [login, { isLoading, isSuccess, error }] = useLoginMutation(); + useEffect(() => { + if (code) { + login({ + magic_token, + code, + type: "github" + }); + } + }, [code]); + useEffect(() => { + if (isSuccess) { + toast.success("Login Successfully"); + // 通知widget + if (from == 'widget') { + localStorage.setItem("widget", `${new Date().getTime()}`); + } + } + }, [isSuccess, from]); + useEffect(() => { + if (error) { + // todo: why? + switch ((error as FetchBaseQueryError).status) { + case 410: + toast.error( + "No associated account found, please user admin for an invitation link to join." + ); + break; + default: + toast.error("Something Error"); + break; + } + return; + } + }, [error]); + if (error) return Something Error; + return + {isSuccess && from == 'widget' &&

Please close this window and return widget window

} + {isLoading ? "Github Logging in..." : "Github Login Success!"} +
; +}; + +export default GithubCallback; \ No newline at end of file diff --git a/src/routes/callback/index.tsx b/src/routes/callback/index.tsx index 8c08380e..b4719630 100644 --- a/src/routes/callback/index.tsx +++ b/src/routes/callback/index.tsx @@ -1,10 +1,11 @@ import { useParams } from "react-router-dom"; import PaymentSuccess from "./PaymentSuccess"; +import GithubCallback, { GithubLoginSource } from "./GithubCallback"; import StyledWrapper from "./styled"; // type Props = { // type: "payment_success"; // }; -// 该页面服务于一些第三方服务的回调,比如stripe付款成功的回调 +// 该页面服务于一些第三方服务的回调,比如stripe付款成功的回调,GitHub登录成功的回调 export default function CallbackPage() { const { type = "", payload = "" } = useParams(); if (type == "payment_success") { @@ -14,5 +15,14 @@ export default function CallbackPage() { ); } + if (type == "github") { + const query = new URLSearchParams(location.search); + const code = query.get("code") ?? ""; + return ( + + + + ); + } return callback page; } diff --git a/src/widget/Popup/Header.tsx b/src/widget/Popup/Header.tsx index 26d57a95..22aced48 100644 --- a/src/widget/Popup/Header.tsx +++ b/src/widget/Popup/Header.tsx @@ -7,15 +7,15 @@ type Props = { }; const Index: FC = ({ handleClose }) => { - const { name, logo } = useAppSelector(store => store.server); + const { name, description, logo } = useAppSelector(store => store.server); return ( -
-
+
+
logo
- {name} - {/* {online ? 'Active now' : 'Offline now'} */} + {name} + {description && {description}}
diff --git a/src/widget/Popup/Login/index.tsx b/src/widget/Popup/Login/index.tsx index 37eb4cc2..33e84ac5 100644 --- a/src/widget/Popup/Login/index.tsx +++ b/src/widget/Popup/Login/index.tsx @@ -20,9 +20,9 @@ const Login = () => { } = loginConfig; const googleLogin = enableGoogleLogin && clientId; return ( -
+
{googleLogin && } - {enableGithubLogin && } + {enableGithubLogin && }
); }; diff --git a/src/widget/Popup/MessageFeed/Message/Text.tsx b/src/widget/Popup/MessageFeed/Message/Text.tsx index 7a7401c4..27d0bcab 100644 --- a/src/widget/Popup/MessageFeed/Message/Text.tsx +++ b/src/widget/Popup/MessageFeed/Message/Text.tsx @@ -28,18 +28,18 @@ export type MessageProps = { const Index: FC = (props) => { const { server: { name, logo }, loginUser } = useAppSelector(store => { return { server: store.server, loginUser: store.authData.user }; }); - const { hostId, from_uid, content, created_at, compact, isFirst = false } = props; + const { hostId, from_uid, content, created_at = 0, compact, isFirst = false } = props; const isHost = from_uid == hostId; return (
{!compact && ( -
+
{isHost ? ( logo ) : ( @@ -48,19 +48,19 @@ const Index: FC = (props) => {
)} {!compact && ( - - {isHost ? name : loginUser?.name} -