[React] Login improvements (#5752)

* Logout user if user query fails

* login / logout improvements

- Add timeout to request (otherwise hangs indefinitely)

* Improve "checking login" page

* Update login form

- Disable button if logging in
- Show loader

* Fixed unused vars
This commit is contained in:
Oliver 2023-10-19 13:42:12 +11:00 committed by GitHub
parent 566fef5309
commit 2be5ec26f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 18 deletions

View File

@ -3,6 +3,7 @@ import {
Anchor,
Button,
Group,
Loader,
Paper,
PasswordInput,
Stack,
@ -13,6 +14,7 @@ import { useForm } from '@mantine/form';
import { useDisclosure } from '@mantine/hooks';
import { notifications } from '@mantine/notifications';
import { IconCheck } from '@tabler/icons-react';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { doClassicLogin, doSimpleLogin } from '../../functions/auth';
@ -25,12 +27,18 @@ export function AuthenticationForm() {
const [classicLoginMode, setMode] = useDisclosure(true);
const navigate = useNavigate();
const [isLoggingIn, setIsLoggingIn] = useState<boolean>(false);
function handleLogin() {
setIsLoggingIn(true);
if (classicLoginMode === true) {
doClassicLogin(
classicForm.values.username,
classicForm.values.password
).then((ret) => {
setIsLoggingIn(false);
if (ret === false) {
notifications.show({
title: t`Login failed`,
@ -49,6 +57,8 @@ export function AuthenticationForm() {
});
} else {
doSimpleLogin(simpleForm.values.email).then((ret) => {
setIsLoggingIn(false);
if (ret?.status === 'ok') {
notifications.show({
title: t`Mail delivery successful`,
@ -126,11 +136,17 @@ export function AuthenticationForm() {
<Trans>I will use username and password</Trans>
)}
</Anchor>
<Button type="submit" onClick={handleLogin}>
{classicLoginMode ? (
<Trans>Log in</Trans>
<Button type="submit" disabled={isLoggingIn} onClick={handleLogin}>
{isLoggingIn ? (
<Loader size="sm" />
) : (
<Trans>Send mail</Trans>
<>
{classicLoginMode ? (
<Trans>Log In</Trans>
) : (
<Trans>Send Email</Trans>
)}
</>
)}
</Button>
</Group>

View File

@ -20,7 +20,8 @@ export const doClassicLogin = async (username: string, password: string) => {
const token = await axios
.get(apiUrl(ApiPaths.user_token), {
auth: { username, password },
baseURL: host.toString()
baseURL: host.toString(),
timeout: 5000
})
.then((response) => response.data.token)
.catch((error) => {
@ -62,7 +63,7 @@ export const doSimpleLogin = async (email: string) => {
email: email
})
.then((response) => response.data)
.catch((error) => {
.catch((_error) => {
return false;
});
return mail;
@ -107,9 +108,14 @@ export function handleReset(navigate: any, values: { email: string }) {
});
}
export function checkLoginState(navigate: any) {
/**
* Check login state, and redirect the user as required
*/
export function checkLoginState(navigate: any, redirect?: string) {
api
.get(apiUrl(ApiPaths.user_token))
.get(apiUrl(ApiPaths.user_token), {
timeout: 5000
})
.then((val) => {
if (val.status === 200 && val.data.token) {
doTokenLogin(val.data.token);
@ -120,13 +126,13 @@ export function checkLoginState(navigate: any) {
color: 'green',
icon: <IconCheck size="1rem" />
});
navigate('/home');
navigate(redirect ?? '/home');
} else {
navigate('/login');
}
})
.catch(() => {
.catch((error) => {
console.error('Error fetching login information:', error);
navigate('/login');
});
}

View File

@ -1,5 +1,5 @@
import { Trans } from '@lingui/macro';
import { Text } from '@mantine/core';
import { Card, Container, Group, Loader, Stack, Text } from '@mantine/core';
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
@ -14,9 +14,20 @@ export default function Logged_In() {
return (
<>
<Text>
<Trans>Checking if you are already logged in</Trans>
</Text>
<Container>
<Stack align="center">
<Card shadow="sm" padding="lg" radius="md">
<Stack>
<Text size="lg">
<Trans>Checking if you are already logged in</Trans>
</Text>
<Group position="center">
<Loader />
</Group>
</Stack>
</Card>
</Stack>
</Container>
</>
);
}

View File

@ -1,6 +1,7 @@
import { create } from 'zustand';
import { api } from '../App';
import { doClassicLogout } from '../functions/auth';
import { ApiPaths, apiUrl } from './ApiState';
import { UserProps } from './states';
@ -19,17 +20,19 @@ export const useUserState = create<UserStateProps>((set, get) => ({
username: () => {
const user: UserProps = get().user as UserProps;
if (user.first_name || user.last_name) {
if (user?.first_name || user?.last_name) {
return `${user.first_name} ${user.last_name}`.trim();
} else {
return user.username;
return user?.username ?? '';
}
},
setUser: (newUser: UserProps) => set({ user: newUser }),
fetchUserState: async () => {
// Fetch user data
await api
.get(apiUrl(ApiPaths.user_me))
.get(apiUrl(ApiPaths.user_me), {
timeout: 5000
})
.then((response) => {
const user: UserProps = {
first_name: response.data?.first_name ?? '',
@ -41,6 +44,8 @@ export const useUserState = create<UserStateProps>((set, get) => ({
})
.catch((error) => {
console.error('Error fetching user data:', error);
// Redirect to login page
doClassicLogout();
});
// Fetch role data