refactor: magic link auth
This commit is contained in:
@@ -45,6 +45,13 @@ export const authApi = createApi({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
register: builder.mutation({
|
||||||
|
query: (data) => ({
|
||||||
|
url: `user/register`,
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
}),
|
||||||
// 更新token
|
// 更新token
|
||||||
renew: builder.mutation({
|
renew: builder.mutation({
|
||||||
query: ({ token, refreshToken }) => ({
|
query: ({ token, refreshToken }) => ({
|
||||||
@@ -87,9 +94,9 @@ export const authApi = createApi({
|
|||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
|
||||||
checkInviteTokenValid: builder.mutation({
|
checkMagicTokenValid: builder.mutation({
|
||||||
query: (token) => ({
|
query: (token) => ({
|
||||||
url: "user/check_invite_magic_token",
|
url: "user/check_magic_token",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: { magic_token: token }
|
body: { magic_token: token }
|
||||||
})
|
})
|
||||||
@@ -101,11 +108,23 @@ export const authApi = createApi({
|
|||||||
body: { old_password, new_password }
|
body: { old_password, new_password }
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
sendMagicLink: builder.mutation({
|
sendLoginMagicLink: builder.mutation({
|
||||||
query: (email) => ({
|
query: (email) => ({
|
||||||
url: "token/send_magic_link",
|
headers: {
|
||||||
|
// "content-type": "text/plain",
|
||||||
|
accept: "text/plain"
|
||||||
|
},
|
||||||
|
url: `user/send_login_magic_link?email=${encodeURIComponent(email)}`,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: { email }
|
responseHandler: (response) => response.text()
|
||||||
|
// body: { email }
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
sendRegMagicLink: builder.mutation({
|
||||||
|
query: (data) => ({
|
||||||
|
url: `user/send_reg_magic_link`,
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
getMetamaskNonce: builder.query({
|
getMetamaskNonce: builder.query({
|
||||||
@@ -147,7 +166,8 @@ export const authApi = createApi({
|
|||||||
|
|
||||||
export const {
|
export const {
|
||||||
useGetInitializedQuery,
|
useGetInitializedQuery,
|
||||||
useSendMagicLinkMutation,
|
useSendLoginMagicLinkMutation,
|
||||||
|
useSendRegMagicLinkMutation,
|
||||||
useGetCredentialsQuery,
|
useGetCredentialsQuery,
|
||||||
useUpdateDeviceTokenMutation,
|
useUpdateDeviceTokenMutation,
|
||||||
useGetOpenidMutation,
|
useGetOpenidMutation,
|
||||||
@@ -155,6 +175,7 @@ export const {
|
|||||||
useLazyGetMetamaskNonceQuery,
|
useLazyGetMetamaskNonceQuery,
|
||||||
useLoginMutation,
|
useLoginMutation,
|
||||||
useLazyLogoutQuery,
|
useLazyLogoutQuery,
|
||||||
useCheckInviteTokenValidMutation,
|
useCheckMagicTokenValidMutation,
|
||||||
useUpdatePasswordMutation
|
useUpdatePasswordMutation,
|
||||||
|
useRegisterMutation
|
||||||
} = authApi;
|
} = authApi;
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ import BASE_URL, { tokenHeader } from "../config";
|
|||||||
const whiteList = [
|
const whiteList = [
|
||||||
"login",
|
"login",
|
||||||
"register",
|
"register",
|
||||||
"sendMagicLink",
|
"sendLoginMagicLink",
|
||||||
"checkInviteTokenValid",
|
"sendRegMagicLink",
|
||||||
|
"checkMagicTokenValid",
|
||||||
"getGoogleAuthConfig",
|
"getGoogleAuthConfig",
|
||||||
"getGithubAuthConfig",
|
"getGithubAuthConfig",
|
||||||
"getSMTPStatus",
|
"getSMTPStatus",
|
||||||
|
|||||||
@@ -89,13 +89,7 @@ export const contactApi = createApi({
|
|||||||
body: data
|
body: data
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
register: builder.mutation({
|
|
||||||
query: (data) => ({
|
|
||||||
url: `user/register`,
|
|
||||||
method: "POST",
|
|
||||||
body: data
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
sendMsg: builder.mutation({
|
sendMsg: builder.mutation({
|
||||||
query: ({ id, content, type = "text", properties = "" }) => ({
|
query: ({ id, content, type = "text", properties = "" }) => ({
|
||||||
headers: {
|
headers: {
|
||||||
@@ -139,6 +133,5 @@ export const {
|
|||||||
useUpdateAvatarMutation,
|
useUpdateAvatarMutation,
|
||||||
useGetContactsQuery,
|
useGetContactsQuery,
|
||||||
useLazyGetContactsQuery,
|
useLazyGetContactsQuery,
|
||||||
useSendMsgMutation,
|
useSendMsgMutation
|
||||||
useRegisterMutation
|
|
||||||
} = contactApi;
|
} = contactApi;
|
||||||
|
|||||||
@@ -1,7 +1,23 @@
|
|||||||
// import { useState, useEffect } from "react";
|
// import { useState, useEffect } from "react";
|
||||||
// import { useGoogleLogin } from "react-google-login";
|
// import { useGoogleLogin } from "react-google-login";
|
||||||
import IconGithub from "../../assets/icons/github.svg";
|
import IconGithub from "../../assets/icons/github.svg";
|
||||||
import { StyledSocialButton } from "./styled";
|
import styled from "styled-components";
|
||||||
|
import Button from "./styled/Button";
|
||||||
|
const StyledSocialButton = styled(Button)`
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
color: #344054;
|
||||||
|
border: 1px solid #d0d5dd;
|
||||||
|
background: none !important;
|
||||||
|
.icon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
export default function GithubLoginButton({ config = {} }) {
|
export default function GithubLoginButton({ config = {} }) {
|
||||||
const { client_id } = config;
|
const { client_id } = config;
|
||||||
const handleGithubLogin = () => {
|
const handleGithubLogin = () => {
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import { useGoogleLogin } from "react-google-login";
|
||||||
|
|
||||||
|
import googleSvg from "../../assets/icons/google.svg?url";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import Button from "./styled/Button";
|
||||||
|
import { useLoginMutation } from "../../app/services/auth";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
const StyledSocialButton = styled(Button)`
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
color: #344054;
|
||||||
|
border: 1px solid #d0d5dd;
|
||||||
|
background: none !important;
|
||||||
|
.icon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export default function GoogleLoginButton({ clientId }) {
|
||||||
|
const [login, { isSuccess, isLoading }] = useLoginMutation();
|
||||||
|
const { signIn, loaded } = useGoogleLogin({
|
||||||
|
onScriptLoadFailure: (wtf) => {
|
||||||
|
console.error("google login script load failure", wtf);
|
||||||
|
},
|
||||||
|
clientId,
|
||||||
|
onSuccess: ({ tokenId, ...rest }) => {
|
||||||
|
console.info("google oauth success", tokenId, rest);
|
||||||
|
login({
|
||||||
|
id_token: tokenId,
|
||||||
|
type: "google"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onFailure: (wtf) => {
|
||||||
|
console.error("google login failure", wtf);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
if (isSuccess) {
|
||||||
|
toast.success("Login Successfully");
|
||||||
|
// navigateTo("/");
|
||||||
|
}
|
||||||
|
}, [isSuccess]);
|
||||||
|
const handleGoogleLogin = () => {
|
||||||
|
signIn();
|
||||||
|
};
|
||||||
|
// console.log("google login ", loaded);
|
||||||
|
return (
|
||||||
|
<StyledSocialButton disabled={!loaded || isLoading} onClick={handleGoogleLogin}>
|
||||||
|
<img className="icon" src={googleSvg} alt="google icon" />
|
||||||
|
{loaded ? `Sign in with Google` : `Initailizing`}
|
||||||
|
</StyledSocialButton>
|
||||||
|
);
|
||||||
|
}
|
||||||
+2
-2
@@ -75,9 +75,9 @@ const PageRoutes = () => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Route index element={<RegPage />} />
|
<Route index element={<RegPage />} />
|
||||||
<Route path="magiclink">
|
<Route path="set_name">
|
||||||
<Route index element={<RegWithUsernamePage />} />
|
<Route index element={<RegWithUsernamePage />} />
|
||||||
<Route path=":token" element={<RegWithUsernamePage />} />
|
<Route path=":from" element={<RegWithUsernamePage />} />
|
||||||
</Route>
|
</Route>
|
||||||
</Route>
|
</Route>
|
||||||
<Route
|
<Route
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import StyledWrapper from "./styled";
|
|||||||
import { Navigate } from "react-router-dom";
|
import { Navigate } from "react-router-dom";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import BASE_URL from "../../app/config";
|
import BASE_URL from "../../app/config";
|
||||||
import { useRegisterMutation } from "../../app/services/contact";
|
import { useRegisterMutation } from "../../app/services/auth";
|
||||||
import { useCheckInviteTokenValidMutation } from "../../app/services/auth";
|
import { useCheckMagicTokenValidMutation } from "../../app/services/auth";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
export default function InvitePage() {
|
export default function InvitePage() {
|
||||||
@@ -17,7 +17,7 @@ export default function InvitePage() {
|
|||||||
// const navigateTo = useNavigate();
|
// const navigateTo = useNavigate();
|
||||||
const [register, { data, isLoading, isSuccess, isError, error }] = useRegisterMutation();
|
const [register, { data, isLoading, isSuccess, isError, error }] = useRegisterMutation();
|
||||||
const [checkToken, { data: isValid, isLoading: checkLoading, isSuccess: checkSuccess }] =
|
const [checkToken, { data: isValid, isLoading: checkLoading, isSuccess: checkSuccess }] =
|
||||||
useCheckInviteTokenValidMutation();
|
useCheckMagicTokenValidMutation();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// console.log(search);
|
// console.log(search);
|
||||||
const query = new URLSearchParams(location.search);
|
const query = new URLSearchParams(location.search);
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
// import { useState, useEffect } from "react";
|
|
||||||
import { useGoogleLogin } from "react-google-login";
|
|
||||||
|
|
||||||
import googleSvg from "../../assets/icons/google.svg?url";
|
|
||||||
import { StyledSocialButton } from "./styled";
|
|
||||||
export default function GoogleLoginButton({ login, clientId }) {
|
|
||||||
const { signIn, loaded } = useGoogleLogin({
|
|
||||||
onScriptLoadFailure: (wtf) => {
|
|
||||||
console.error("google login script load failure", wtf);
|
|
||||||
},
|
|
||||||
clientId,
|
|
||||||
onSuccess: ({ tokenId, ...rest }) => {
|
|
||||||
console.info("google oauth success", tokenId, rest);
|
|
||||||
login({
|
|
||||||
id_token: tokenId,
|
|
||||||
type: "google"
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onFailure: (wtf) => {
|
|
||||||
console.error("google login failure", wtf);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const handleGoogleLogin = () => {
|
|
||||||
signIn();
|
|
||||||
};
|
|
||||||
// console.log("google login ", loaded);
|
|
||||||
return (
|
|
||||||
<StyledSocialButton disabled={!loaded} onClick={handleGoogleLogin}>
|
|
||||||
<img className="icon" src={googleSvg} alt="google icon" />
|
|
||||||
{loaded ? `Sign in with Google` : `Initailizing`}
|
|
||||||
</StyledSocialButton>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -24,7 +24,7 @@ const StyledSignUpLink = styled.p`
|
|||||||
export default function MagicLinkLogin() {
|
export default function MagicLinkLogin() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const handleSignUp = () => {
|
const handleSignUp = () => {
|
||||||
navigate("/");
|
navigate("/register");
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<StyledSignUpLink>
|
<StyledSignUpLink>
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ import MetamaskLoginButton from "./MetamaskLoginButton";
|
|||||||
import OidcLoginButton from "./OidcLoginButton";
|
import OidcLoginButton from "./OidcLoginButton";
|
||||||
import Input from "../../common/component/styled/Input";
|
import Input from "../../common/component/styled/Input";
|
||||||
import Button from "../../common/component/styled/Button";
|
import Button from "../../common/component/styled/Button";
|
||||||
import GoogleLoginButton from "./GoogleLoginButton";
|
|
||||||
import MagicLinkLogin from "./MagicLinkLogin";
|
import MagicLinkLogin from "./MagicLinkLogin";
|
||||||
import SignUpLink from "./SignUpLink";
|
import SignUpLink from "./SignUpLink";
|
||||||
import { useLoginMutation } from "../../app/services/auth";
|
import { useLoginMutation } from "../../app/services/auth";
|
||||||
import { useGetLoginConfigQuery, useGetSMTPStatusQuery } from "../../app/services/server";
|
import { useGetLoginConfigQuery, useGetSMTPStatusQuery } from "../../app/services/server";
|
||||||
import useGoogleAuthConfig from "../../common/hook/useGoogleAuthConfig";
|
import useGoogleAuthConfig from "../../common/hook/useGoogleAuthConfig";
|
||||||
import GithubLoginButton from "./GithubLoginButton";
|
|
||||||
import useGithubAuthConfig from "../../common/hook/useGithubAuthConfig";
|
import useGithubAuthConfig from "../../common/hook/useGithubAuthConfig";
|
||||||
|
import GoogleLoginButton from "../../common/component/GoogleLoginButton";
|
||||||
|
import GithubLoginButton from "../../common/component/GithubLoginButton";
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
const { data: enableSMTP } = useGetSMTPStatusQuery();
|
const { data: enableSMTP } = useGetSMTPStatusQuery();
|
||||||
const [login, { isSuccess, isLoading, error }] = useLoginMutation();
|
const [login, { isSuccess, isLoading, error }] = useLoginMutation();
|
||||||
@@ -32,7 +32,7 @@ export default function LoginPage() {
|
|||||||
const oauth = query.get("oauth");
|
const oauth = query.get("oauth");
|
||||||
const code = query.get("code");
|
const code = query.get("code");
|
||||||
const state = query.get("state");
|
const state = query.get("state");
|
||||||
const token = query.get("token");
|
const magic_token = query.get("magic_token");
|
||||||
const exists = query.get("exists");
|
const exists = query.get("exists");
|
||||||
if (oauth) {
|
if (oauth) {
|
||||||
switch (oauth) {
|
switch (oauth) {
|
||||||
@@ -58,18 +58,18 @@ export default function LoginPage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// magic link
|
// magic link
|
||||||
if (token && typeof exists !== "undefined") {
|
if (magic_token && typeof exists !== "undefined") {
|
||||||
console.log("tokken", token, exists);
|
// console.log("tokken", token, exists);
|
||||||
const isLogin = exists == "true";
|
const isLogin = exists == "true";
|
||||||
if (isLogin) {
|
if (isLogin) {
|
||||||
// login
|
// login
|
||||||
login({
|
login({
|
||||||
token,
|
magic_token,
|
||||||
type: "magiclink"
|
type: "magiclink"
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// reg
|
// reg with magic link and set name only
|
||||||
location.href = `/#/reg/magiclink/${token}`;
|
location.href = `?magic_token=${magic_token}#/register/set_name/login`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
@@ -167,7 +167,7 @@ export default function LoginPage() {
|
|||||||
</form>
|
</form>
|
||||||
{hasDivider && <hr className="or" />}
|
{hasDivider && <hr className="or" />}
|
||||||
{enableMagicLink && <MagicLinkLogin />}
|
{enableMagicLink && <MagicLinkLogin />}
|
||||||
{googleLogin && <GoogleLoginButton login={login} clientId={clientId} />}
|
{googleLogin && <GoogleLoginButton clientId={clientId} />}
|
||||||
{enableGithubLogin && <GithubLoginButton config={githubAuthConfig} />}
|
{enableGithubLogin && <GithubLoginButton config={githubAuthConfig} />}
|
||||||
{enableMetamaskLogin && <MetamaskLoginButton login={login} />}
|
{enableMetamaskLogin && <MetamaskLoginButton login={login} />}
|
||||||
{oidc.length > 0 && <OidcLoginButton issuers={oidc} />}
|
{oidc.length > 0 && <OidcLoginButton issuers={oidc} />}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,25 +1,30 @@
|
|||||||
/* eslint-disable no-undef */
|
/* eslint-disable no-undef */
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
// import { useNavigate } from "react-router-dom";
|
|
||||||
// import toast from "react-hot-toast";
|
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { setAuthData } from "../../app/slices/auth.data";
|
import { setAuthData } from "../../app/slices/auth.data";
|
||||||
|
|
||||||
import Input from "../../common/component/styled/Input";
|
import Input from "../../common/component/styled/Input";
|
||||||
import Button from "../../common/component/styled/Button";
|
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 toast from "react-hot-toast";
|
||||||
import ExpiredTip from "./ExpiredTip";
|
import ExpiredTip from "./ExpiredTip";
|
||||||
|
import { useRegisterMutation } from "../../app/services/auth";
|
||||||
|
|
||||||
export default function RegWithUsername() {
|
export default function RegWithUsername() {
|
||||||
const { token } = useParams();
|
|
||||||
const [checkTokenInvalid, { data: isTokenValid, isLoading: checkingToken }] =
|
const [checkTokenInvalid, { data: isTokenValid, isLoading: checkingToken }] =
|
||||||
useCheckInviteTokenValidMutation();
|
useCheckMagicTokenValidMutation();
|
||||||
const [login, { isLoading, error, isSuccess, data }] = useLoginMutation();
|
const [login, { isLoading: loginLoading, error, isSuccess: loginSuccess, data: loginData }] =
|
||||||
|
useLoginMutation();
|
||||||
|
const [register, { isLoading: regLoading, isSuccess: regSuccess, data: regData }] =
|
||||||
|
useRegisterMutation();
|
||||||
// const navigateTo = useNavigate();
|
// const navigateTo = useNavigate();
|
||||||
|
const { from = "reg" } = useParams();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
|
const query = new URLSearchParams(location.search);
|
||||||
|
// const githubCode = query.get("gcode");
|
||||||
|
const token = query.get("magic_token");
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (token) {
|
if (token) {
|
||||||
checkTokenInvalid(token);
|
checkTokenInvalid(token);
|
||||||
@@ -38,32 +43,42 @@ export default function RegWithUsername() {
|
|||||||
}
|
}
|
||||||
}, [error]);
|
}, [error]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const isSuccess = loginSuccess || regSuccess;
|
||||||
|
const data = loginData || regData;
|
||||||
if (isSuccess && data) {
|
if (isSuccess && data) {
|
||||||
// 更新本地认证信息
|
// 更新本地认证信息
|
||||||
console.log("login data", data);
|
|
||||||
toast.success("Login Successfully");
|
toast.success("Login Successfully");
|
||||||
dispatch(setAuthData(data));
|
dispatch(setAuthData(data));
|
||||||
|
// tricky
|
||||||
location.href = `/#/`;
|
location.href = `/#/`;
|
||||||
}
|
}
|
||||||
}, [isSuccess, data]);
|
}, [loginSuccess, regSuccess, loginData, regData]);
|
||||||
|
|
||||||
const handleLogin = (evt) => {
|
const handleAuth = (evt) => {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
login({
|
if (from == "reg") {
|
||||||
token,
|
register({
|
||||||
username,
|
magic_token: token,
|
||||||
type: "magiclink"
|
name: username
|
||||||
});
|
});
|
||||||
// sendMagicLink(email);
|
} else {
|
||||||
|
login({
|
||||||
|
magic_token: token,
|
||||||
|
extra_name: username,
|
||||||
|
type: "magiclink"
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleInput = (evt) => {
|
const handleInput = (evt) => {
|
||||||
const { value } = evt.target;
|
const { value } = evt.target;
|
||||||
setUsername(value);
|
setUsername(value);
|
||||||
};
|
};
|
||||||
if (!token) return "no token";
|
if (!token) return "No Token";
|
||||||
if (checkingToken) return "checking Magic Link...";
|
if (checkingToken) return "Checking Magic Link...";
|
||||||
if (!isTokenValid) return <ExpiredTip />;
|
if (!isTokenValid) return <ExpiredTip />;
|
||||||
|
const isLoading = loginLoading || regLoading;
|
||||||
|
const isSuccess = loginSuccess || regSuccess;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="tips">
|
<div className="tips">
|
||||||
@@ -73,7 +88,7 @@ export default function RegWithUsername() {
|
|||||||
visible to others in spaces you joined.
|
visible to others in spaces you joined.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<form onSubmit={handleLogin}>
|
<form onSubmit={handleAuth}>
|
||||||
<Input
|
<Input
|
||||||
className="large"
|
className="large"
|
||||||
name="username"
|
name="username"
|
||||||
|
|||||||
+63
-19
@@ -1,42 +1,86 @@
|
|||||||
/* eslint-disable no-undef */
|
import { useState, useEffect } from "react";
|
||||||
import { useState } from "react";
|
|
||||||
// import { useDispatch } from "react-redux";
|
// import { useDispatch } from "react-redux";
|
||||||
// import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
// import toast from "react-hot-toast";
|
// import toast from "react-hot-toast";
|
||||||
import Input from "../../common/component/styled/Input";
|
import Input from "../../common/component/styled/Input";
|
||||||
import Button from "../../common/component/styled/Button";
|
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() {
|
export default function Reg() {
|
||||||
// const [
|
const [sendRegMagicLink, { isLoading, data, isSuccess }] = useSendRegMagicLinkMutation();
|
||||||
// sendMagicLink,
|
const navigateTo = useNavigate();
|
||||||
// { data, isSuccess, isLoading, error },
|
const [magicToken, setMagicToken] = useState("");
|
||||||
// ] = useSendMagicLinkMutation();
|
const [input, setInput] = useState({
|
||||||
// const navigateTo = useNavigate();
|
email: "",
|
||||||
// const dispatch = useDispatch();
|
password: "",
|
||||||
const [username, setUsername] = useState("");
|
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();
|
evt.preventDefault();
|
||||||
|
const { email, password } = input;
|
||||||
|
sendRegMagicLink({
|
||||||
|
magic_token: magicToken,
|
||||||
|
email,
|
||||||
|
password
|
||||||
|
});
|
||||||
// sendMagicLink(email);
|
// sendMagicLink(email);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleInput = (evt) => {
|
const handleInput = (evt) => {
|
||||||
|
const { type } = evt.target.dataset;
|
||||||
const { value } = evt.target;
|
const { value } = evt.target;
|
||||||
console.log(value);
|
// console.log(type, value);
|
||||||
setUsername(value);
|
setInput((prev) => {
|
||||||
|
prev[type] = value;
|
||||||
|
return { ...prev };
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
const { email, password } = input;
|
||||||
|
if (data?.mail_is_sent) return <EmailNextTip />;
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleLogin}>
|
<form onSubmit={handleReg}>
|
||||||
<Input
|
<Input
|
||||||
className="large"
|
className="large"
|
||||||
name="username"
|
name="email"
|
||||||
value={username}
|
value={email}
|
||||||
required
|
required
|
||||||
placeholder="Enter your Name22"
|
placeholder="Enter your email"
|
||||||
|
data-type="email"
|
||||||
onChange={handleInput}
|
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>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -1,12 +1,49 @@
|
|||||||
/* eslint-disable no-undef */
|
|
||||||
import { Outlet } from "react-router-dom";
|
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";
|
import StyledWrapper from "./styled";
|
||||||
|
|
||||||
export default function Reg() {
|
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 (
|
return (
|
||||||
<StyledWrapper>
|
<StyledWrapper>
|
||||||
<div className="form">
|
<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 />
|
<Outlet />
|
||||||
|
{isRegHome && (
|
||||||
|
<>
|
||||||
|
<hr className="or" />
|
||||||
|
{googleLogin && <GoogleLoginButton clientId={clientId} />}
|
||||||
|
{enableGithubLogin && <GithubLoginButton config={githubAuthConfig} />}
|
||||||
|
<SignInLink />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -45,6 +45,25 @@ const StyledWrapper = styled.div`
|
|||||||
width: 360px;
|
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;
|
export default StyledWrapper;
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ import BASE_URL from "../../app/config";
|
|||||||
import StyledWrapper from "./styled";
|
import StyledWrapper from "./styled";
|
||||||
import Input from "../../common/component/styled/Input";
|
import Input from "../../common/component/styled/Input";
|
||||||
import Button from "../../common/component/styled/Button";
|
import Button from "../../common/component/styled/Button";
|
||||||
import { useSendMagicLinkMutation } from "../../app/services/auth";
|
import { useSendLoginMagicLinkMutation } from "../../app/services/auth";
|
||||||
import SentTip from "./SentTip";
|
import SentTip from "./SentTip";
|
||||||
|
|
||||||
export default function SendMagicLinkPage() {
|
export default function SendMagicLinkPage() {
|
||||||
const [sent, setSent] = useState(false);
|
const [sent, setSent] = useState(false);
|
||||||
const [sendMagicLink, { isSuccess, isLoading, error }] = useSendMagicLinkMutation();
|
const [sendMagicLink, { isSuccess, isLoading, error }] = useSendLoginMagicLinkMutation();
|
||||||
|
|
||||||
const navigateTo = useNavigate();
|
const navigateTo = useNavigate();
|
||||||
// const dispatch = useDispatch();
|
// const dispatch = useDispatch();
|
||||||
@@ -32,13 +32,13 @@ export default function SendMagicLinkPage() {
|
|||||||
toast.error(error.data);
|
toast.error(error.data);
|
||||||
break;
|
break;
|
||||||
case 401:
|
case 401:
|
||||||
toast.error("username or password incorrect");
|
toast.error("Username or Password Incorrect");
|
||||||
break;
|
break;
|
||||||
case 404:
|
case 404:
|
||||||
toast.error("account not exsit");
|
toast.error("Account not exsit");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
toast.error("something error");
|
toast.error("Something Error");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user