mirror of
https://github.com/Myzel394/kleckrelay-website.git
synced 2025-06-19 07:55:25 +02:00
added ability to login from different devices
This commit is contained in:
parent
ccdaf12ee3
commit
8ae24aec8e
@ -35,6 +35,7 @@
|
||||
"title": "You got mail!",
|
||||
"description": "We sent you a code to your email. Enter it below to login",
|
||||
"continueAction": "Log in",
|
||||
"allowLoginFromDifferentDevices": "Allow login from different devices",
|
||||
"form": {
|
||||
"code": {
|
||||
"label": "Verification Code",
|
||||
@ -43,6 +44,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"confirmFromDifferentDevice": {
|
||||
"title": "Login failed",
|
||||
"description": "You could not be logged in. This could either be because you are not allowed to login from different devices or the verification code is invalid or expired."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -15,7 +15,7 @@ export default async function changeAllowEmailLoginFromDifferentDevices({
|
||||
const {data} = await client.patch(
|
||||
`${
|
||||
import.meta.env.VITE_SERVER_BASE_URL
|
||||
}/auth/login/email-token/allow-email-login-from-different-devices`,
|
||||
}/auth/login/email-token/allow-login-from-different-devices`,
|
||||
{
|
||||
email,
|
||||
sameRequestToken,
|
||||
|
@ -5,7 +5,7 @@ import parseUser from "~/apis/helpers/parse-user"
|
||||
export interface VerifyLoginWithEmailData {
|
||||
email: string
|
||||
token: string
|
||||
sameRequestToken: string
|
||||
sameRequestToken?: string
|
||||
}
|
||||
|
||||
export default async function verifyLoginWithEmail({
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as yup from "yup"
|
||||
import {AxiosError} from "axios"
|
||||
import {ReactElement} from "react"
|
||||
import {ReactElement, useState} from "react"
|
||||
import {useFormik} from "formik"
|
||||
import {FaHashtag} from "react-icons/fa"
|
||||
import {MdChevronRight, MdMail} from "react-icons/md"
|
||||
@ -8,13 +8,27 @@ import {useLoaderData} from "react-router-dom"
|
||||
import {useTranslation} from "react-i18next"
|
||||
|
||||
import {useMutation} from "@tanstack/react-query"
|
||||
import {Box, Grid, InputAdornment, TextField, Typography} from "@mui/material"
|
||||
import {
|
||||
Box,
|
||||
FormControlLabel,
|
||||
Grid,
|
||||
InputAdornment,
|
||||
Switch,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material"
|
||||
import {LoadingButton} from "@mui/lab"
|
||||
|
||||
import {AuthenticationDetails, ServerSettings, ServerUser} from "~/server-types"
|
||||
import {
|
||||
AuthenticationDetails,
|
||||
ServerSettings,
|
||||
ServerUser,
|
||||
SimpleDetailResponse,
|
||||
} from "~/server-types"
|
||||
import {VerifyLoginWithEmailData, verifyLoginWithEmail} from "~/apis"
|
||||
import {MultiStepFormElement} from "~/components"
|
||||
import {parseFastAPIError} from "~/utils"
|
||||
import changeAllowEmailLoginFromDifferentDevices from "~/apis/change-allow-email-login-from-different-devices"
|
||||
|
||||
import ResendMailButton from "./ResendMailButton"
|
||||
|
||||
@ -84,6 +98,25 @@ export default function ConfirmCodeForm({
|
||||
}
|
||||
},
|
||||
})
|
||||
const [allowLoginFromDifferentDevices, setAllowLoginFromDifferentDevices] =
|
||||
useState<boolean>(false)
|
||||
const {mutateAsync: changeAllowLoginFromDifferentDevice, isLoading} = useMutation<
|
||||
SimpleDetailResponse,
|
||||
AxiosError,
|
||||
boolean
|
||||
>(
|
||||
allow =>
|
||||
changeAllowEmailLoginFromDifferentDevices({
|
||||
allow,
|
||||
email,
|
||||
sameRequestToken,
|
||||
}),
|
||||
{
|
||||
onSuccess: (_, allow) => {
|
||||
setAllowLoginFromDifferentDevices(allow)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
return (
|
||||
<MultiStepFormElement>
|
||||
@ -110,6 +143,28 @@ export default function ConfirmCodeForm({
|
||||
{t("routes.LoginRoute.forms.confirmCode.description")}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Grid container spacing={2} direction="column">
|
||||
<Grid item>
|
||||
<FormControlLabel
|
||||
disabled={isLoading}
|
||||
control={
|
||||
<Switch
|
||||
disabled={isLoading}
|
||||
checked={allowLoginFromDifferentDevices}
|
||||
onChange={() =>
|
||||
changeAllowLoginFromDifferentDevice(
|
||||
!allowLoginFromDifferentDevices,
|
||||
)
|
||||
}
|
||||
/>
|
||||
}
|
||||
labelPlacement="end"
|
||||
label={t(
|
||||
"routes.LoginRoute.forms.confirmCode.allowLoginFromDifferentDevices",
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<TextField
|
||||
key="code"
|
||||
@ -131,6 +186,8 @@ export default function ConfirmCodeForm({
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Grid width="100%" container display="flex" justifyContent="space-between">
|
||||
<Grid item>
|
||||
|
71
src/route-widgets/LoginRoute/ConfirmFromDifferentDevice.tsx
Normal file
71
src/route-widgets/LoginRoute/ConfirmFromDifferentDevice.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import {ReactElement} from "react"
|
||||
import {AxiosError} from "axios"
|
||||
import {useMount} from "react-use"
|
||||
import {useTranslation} from "react-i18next"
|
||||
|
||||
import {useMutation} from "@tanstack/react-query"
|
||||
import {Box, Grid, Paper, Typography} from "@mui/material"
|
||||
|
||||
import {AuthenticationDetails, ServerUser} from "~/server-types"
|
||||
import {verifyLoginWithEmail} from "~/apis"
|
||||
import LoadingData from "~/components/LoadingData"
|
||||
|
||||
export interface ConfirmFromDifferentDeviceProps {
|
||||
email: string
|
||||
token: string
|
||||
|
||||
onConfirm: (user: ServerUser) => void
|
||||
}
|
||||
|
||||
export default function ConfirmFromDifferentDevice({
|
||||
email,
|
||||
token,
|
||||
onConfirm,
|
||||
}: ConfirmFromDifferentDeviceProps): ReactElement {
|
||||
const {t} = useTranslation()
|
||||
const {mutate, isLoading, isError} = useMutation<AuthenticationDetails, AxiosError, void>(
|
||||
() =>
|
||||
verifyLoginWithEmail({
|
||||
email,
|
||||
token,
|
||||
}),
|
||||
{
|
||||
onSuccess: ({user}) => onConfirm(user),
|
||||
},
|
||||
)
|
||||
|
||||
useMount(mutate)
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Paper>
|
||||
<LoadingData />
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<Paper>
|
||||
<Box padding={4}>
|
||||
<Grid container spacing={2} direction="column" alignItems="center">
|
||||
<Grid item>
|
||||
<Typography variant="h6" component="h1">
|
||||
{t("routes.LoginRoute.forms.confirmFromDifferentDevice.title")}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="body1">
|
||||
{t(
|
||||
"routes.LoginRoute.forms.confirmFromDifferentDevice.description",
|
||||
)}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
|
||||
return <></>
|
||||
}
|
@ -3,12 +3,15 @@ import {useNavigate} from "react-router-dom"
|
||||
import {useUpdateEffect} from "react-use"
|
||||
|
||||
import {MultiStepForm} from "~/components"
|
||||
import {useQueryParams} from "~/hooks"
|
||||
import AuthContext from "~/AuthContext/AuthContext"
|
||||
import ConfirmCodeForm from "~/route-widgets/LoginRoute/ConfirmCodeForm/ConfirmCodeForm"
|
||||
import ConfirmFromDifferentDevice from "~/route-widgets/LoginRoute/ConfirmFromDifferentDevice"
|
||||
import EmailForm from "~/route-widgets/LoginRoute/EmailForm"
|
||||
|
||||
export default function LoginRoute(): ReactElement {
|
||||
const navigate = useNavigate()
|
||||
const {token, email: queryEmail} = useQueryParams<{token: string; email: string}>()
|
||||
const {login, user} = useContext(AuthContext)
|
||||
|
||||
const [email, setEmail] = useState<string>("")
|
||||
@ -26,6 +29,10 @@ export default function LoginRoute(): ReactElement {
|
||||
}
|
||||
}, [user?.encryptedPassword])
|
||||
|
||||
if (token && queryEmail) {
|
||||
return <ConfirmFromDifferentDevice email={queryEmail} token={token} onConfirm={login} />
|
||||
}
|
||||
|
||||
return (
|
||||
<MultiStepForm
|
||||
steps={[
|
||||
|
Loading…
x
Reference in New Issue
Block a user