refactor: magic link auth

This commit is contained in:
Tristan Yang
2022-06-20 17:41:58 +08:00
parent b25907f7fc
commit b938b6b3aa
17 changed files with 349 additions and 111 deletions
+33
View File
@@ -0,0 +1,33 @@
// import React from "react";
import styled from "styled-components";
const Styled = styled.div`
display: flex;
flex-direction: column;
align-items: center;
.title {
font-weight: 600;
font-size: 30px;
line-height: 38px;
color: #101828;
margin-bottom: 12px;
}
.desc {
text-align: center;
font-weight: 400;
font-size: 16px;
line-height: 24px;
color: #667085;
&:not(:last-child) {
margin-bottom: 24px;
}
}
`;
export default function EmailNextTip() {
return (
<Styled>
<div className="title">Magic link Sent</div>
<p className="desc">Login to your email client, and continue next step</p>
<p className="desc">You can close this window now.</p>
</Styled>
);
}
+33 -18
View File
@@ -1,25 +1,30 @@
/* eslint-disable no-undef */
import { useState, useEffect } from "react";
import { useDispatch } from "react-redux";
// import { useNavigate } from "react-router-dom";
// import toast from "react-hot-toast";
import { useParams } from "react-router-dom";
import { setAuthData } from "../../app/slices/auth.data";
import Input from "../../common/component/styled/Input";
import Button from "../../common/component/styled/Button";
import { useLoginMutation, useCheckInviteTokenValidMutation } from "../../app/services/auth";
import { useLoginMutation, useCheckMagicTokenValidMutation } from "../../app/services/auth";
import toast from "react-hot-toast";
import ExpiredTip from "./ExpiredTip";
import { useRegisterMutation } from "../../app/services/auth";
export default function RegWithUsername() {
const { token } = useParams();
const [checkTokenInvalid, { data: isTokenValid, isLoading: checkingToken }] =
useCheckInviteTokenValidMutation();
const [login, { isLoading, error, isSuccess, data }] = useLoginMutation();
useCheckMagicTokenValidMutation();
const [login, { isLoading: loginLoading, error, isSuccess: loginSuccess, data: loginData }] =
useLoginMutation();
const [register, { isLoading: regLoading, isSuccess: regSuccess, data: regData }] =
useRegisterMutation();
// const navigateTo = useNavigate();
const { from = "reg" } = useParams();
const dispatch = useDispatch();
const [username, setUsername] = useState("");
const query = new URLSearchParams(location.search);
// const githubCode = query.get("gcode");
const token = query.get("magic_token");
useEffect(() => {
if (token) {
checkTokenInvalid(token);
@@ -38,32 +43,42 @@ export default function RegWithUsername() {
}
}, [error]);
useEffect(() => {
const isSuccess = loginSuccess || regSuccess;
const data = loginData || regData;
if (isSuccess && data) {
// 更新本地认证信息
console.log("login data", data);
toast.success("Login Successfully");
dispatch(setAuthData(data));
// tricky
location.href = `/#/`;
}
}, [isSuccess, data]);
}, [loginSuccess, regSuccess, loginData, regData]);
const handleLogin = (evt) => {
const handleAuth = (evt) => {
evt.preventDefault();
login({
token,
username,
type: "magiclink"
});
// sendMagicLink(email);
if (from == "reg") {
register({
magic_token: token,
name: username
});
} else {
login({
magic_token: token,
extra_name: username,
type: "magiclink"
});
}
};
const handleInput = (evt) => {
const { value } = evt.target;
setUsername(value);
};
if (!token) return "no token";
if (checkingToken) return "checking Magic Link...";
if (!token) return "No Token";
if (checkingToken) return "Checking Magic Link...";
if (!isTokenValid) return <ExpiredTip />;
const isLoading = loginLoading || regLoading;
const isSuccess = loginSuccess || regSuccess;
return (
<>
<div className="tips">
@@ -73,7 +88,7 @@ export default function RegWithUsername() {
visible to others in spaces you joined.
</span>
</div>
<form onSubmit={handleLogin}>
<form onSubmit={handleAuth}>
<Input
className="large"
name="username"
+63 -19
View File
@@ -1,42 +1,86 @@
/* eslint-disable no-undef */
import { useState } from "react";
import { useState, useEffect } from "react";
// import { useDispatch } from "react-redux";
// import { useNavigate } from "react-router-dom";
import { useNavigate } from "react-router-dom";
// import toast from "react-hot-toast";
import Input from "../../common/component/styled/Input";
import Button from "../../common/component/styled/Button";
// import { useSendMagicLinkMutation } from "../../app/services/auth";
import { useSendRegMagicLinkMutation } from "../../app/services/auth";
import EmailNextTip from "./EmailNextStepTip";
// import { useSendLoginMagicLinkMutation } from "../../app/services/auth";
export default function Reg() {
// const [
// sendMagicLink,
// { data, isSuccess, isLoading, error },
// ] = useSendMagicLinkMutation();
// const navigateTo = useNavigate();
// const dispatch = useDispatch();
const [username, setUsername] = useState("");
const [sendRegMagicLink, { isLoading, data, isSuccess }] = useSendRegMagicLinkMutation();
const navigateTo = useNavigate();
const [magicToken, setMagicToken] = useState("");
const [input, setInput] = useState({
email: "",
password: "",
confirmPassword: ""
});
useEffect(() => {
const query = new URLSearchParams(location.search);
// const githubCode = query.get("gcode");
const token = query.get("magic_token");
if (token) {
setMagicToken(token);
}
}, []);
useEffect(() => {
if (isSuccess && data) {
const { new_magic_token, mail_is_sent } = data;
if (!mail_is_sent && new_magic_token) {
// 直接进入set_name流程
navigateTo(`?magic_token=${new_magic_token}#/register/set_name`);
}
}
}, [isSuccess, data]);
const handleLogin = (evt) => {
const handleReg = (evt) => {
evt.preventDefault();
const { email, password } = input;
sendRegMagicLink({
magic_token: magicToken,
email,
password
});
// sendMagicLink(email);
};
const handleInput = (evt) => {
const { type } = evt.target.dataset;
const { value } = evt.target;
console.log(value);
setUsername(value);
// console.log(type, value);
setInput((prev) => {
prev[type] = value;
return { ...prev };
});
};
const { email, password } = input;
if (data?.mail_is_sent) return <EmailNextTip />;
return (
<form onSubmit={handleLogin}>
<form onSubmit={handleReg}>
<Input
className="large"
name="username"
value={username}
name="email"
value={email}
required
placeholder="Enter your Name22"
placeholder="Enter your email"
data-type="email"
onChange={handleInput}
/>
<Button type="submit">{isLoading ? "Sending" : `Register`}</Button>
<Input
className="large"
type="password"
value={password}
name="password"
required
data-type="password"
onChange={handleInput}
placeholder="Enter your password"
/>
<Button type="submit" disabled={isLoading}>
{isLoading ? "Signing Up" : `Sign Up`}
</Button>
</form>
);
}
+34
View File
@@ -0,0 +1,34 @@
import styled from "styled-components";
import { useNavigate } from "react-router-dom";
const StyledSignInLink = styled.p`
text-align: center;
margin: 24px 0 8px;
> span {
font-weight: 400;
font-size: 14px;
line-height: 20px;
color: #667085;
margin-right: 4px;
}
> a {
font-weight: 500;
font-size: 14px;
line-height: 20px;
color: #22d3ee;
cursor: pointer;
}
`;
export default function SignInLink() {
const navigate = useNavigate();
const handleSignIn = () => {
navigate("/login");
};
return (
<StyledSignInLink>
<span>Have an account?</span>
<a onClick={handleSignIn}>Sign In</a>
</StyledSignInLink>
);
}
+38 -1
View File
@@ -1,12 +1,49 @@
/* eslint-disable no-undef */
import { Outlet } from "react-router-dom";
import { useMatch } from "react-router-dom";
import BASE_URL from "../../app/config";
import SignInLink from "./SignInLink";
import { useGetLoginConfigQuery } from "../../app/services/server";
import useGithubAuthConfig from "../../common/hook/useGithubAuthConfig";
import useGoogleAuthConfig from "../../common/hook/useGoogleAuthConfig";
import GoogleLoginButton from "../../common/component/GoogleLoginButton";
import GithubLoginButton from "../../common/component/GithubLoginButton";
import StyledWrapper from "./styled";
export default function Reg() {
const isRegHome = useMatch(`/register`);
const { clientId } = useGoogleAuthConfig();
const { config: githubAuthConfig } = useGithubAuthConfig();
const { data: loginConfig, isSuccess: loginConfigSuccess } = useGetLoginConfigQuery();
if (!loginConfigSuccess) return null;
const {
github: enableGithubLogin,
google: enableGoogleLogin,
who_can_sign_up: whoCanSignUp
} = loginConfig;
const googleLogin = enableGoogleLogin && clientId;
// 没有开放注册
if (whoCanSignUp !== "EveryOne") return `Open Register is Closed!`;
return (
<StyledWrapper>
<div className="form">
{isRegHome && (
<>
<div className="tips">
<img src={`${BASE_URL}/resource/organization/logo`} alt="logo" className="logo" />
<h2 className="title">Sign Up to Rustchat</h2>
<span className="desc">Please enter your details.</span>
</div>
</>
)}
<Outlet />
{isRegHome && (
<>
<hr className="or" />
{googleLogin && <GoogleLoginButton clientId={clientId} />}
{enableGithubLogin && <GithubLoginButton config={githubAuthConfig} />}
<SignInLink />
</>
)}
</div>
</StyledWrapper>
);
+19
View File
@@ -45,6 +45,25 @@ const StyledWrapper = styled.div`
width: 360px;
}
}
.or {
border: none;
position: relative;
height: 1px;
background-color: #e4e7ec;
margin: 26px 0;
&:after {
padding: 4px;
background-color: #fff;
content: "OR";
position: absolute;
left: 50%;
top: 50%;
transform: translate3d(-50%, -50%, 0);
font-size: 14px;
line-height: 20px;
color: #667085;
}
}
`;
export default StyledWrapper;