mirror of
https://github.com/jeffvli/feishin.git
synced 2026-06-16 16:34:24 +02:00
Update login styles
This commit is contained in:
@@ -1,122 +1,130 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import {
|
import { Stack, Alert, Box, Center, Group } from '@mantine/core';
|
||||||
TextInput,
|
import { ErrorBoundary } from 'react-error-boundary';
|
||||||
PasswordInput,
|
|
||||||
Button,
|
|
||||||
Stack,
|
|
||||||
Title,
|
|
||||||
Loader,
|
|
||||||
Alert,
|
|
||||||
Box,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { useDebouncedValue } from '@mantine/hooks';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { RiCheckboxCircleFill } from 'react-icons/ri';
|
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import { Button, PasswordInput, Text, TextInput } from '@/renderer/components';
|
||||||
|
import { ErrorFallback } from '@/renderer/features/action-required';
|
||||||
import { useLogin } from '@/renderer/features/auth/queries/use-login';
|
import { useLogin } from '@/renderer/features/auth/queries/use-login';
|
||||||
import { usePingServer } from '@/renderer/features/auth/queries/use-ping-server';
|
|
||||||
import { normalizeServerUrl } from '@/renderer/utils';
|
import { normalizeServerUrl } from '@/renderer/utils';
|
||||||
|
|
||||||
const Container = styled(Box)`
|
const Container = styled(Box)`
|
||||||
min-width: 400px;
|
width: 100%;
|
||||||
max-width: 50%;
|
background: var(--main-bg);
|
||||||
margin: auto;
|
|
||||||
padding: 3rem;
|
|
||||||
background: rgba(50, 50, 50, 40%);
|
|
||||||
border-radius: 5px;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const LoginRoute = () => {
|
export const LoginRoute = () => {
|
||||||
const { t } = useTranslation();
|
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
|
||||||
|
const [errorMessage, setErrorMessage] = useState('');
|
||||||
const [username, setUsername] = useState(searchParams.get('username') || '');
|
const [username, setUsername] = useState(searchParams.get('username') || '');
|
||||||
const [password, setPassword] = useState(searchParams.get('password') || '');
|
const [password, setPassword] = useState(searchParams.get('password') || '');
|
||||||
const [server, setServer] = useState(
|
const [server, setServer] = useState(
|
||||||
searchParams.get('server') || 'http://localhost:8843'
|
searchParams.get('server') || 'http://localhost:8843'
|
||||||
);
|
);
|
||||||
const [debouncedServer] = useDebouncedValue(server, 500);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mutate: handleLogin,
|
mutate: handleLogin,
|
||||||
isLoading,
|
isLoading,
|
||||||
isError,
|
isError,
|
||||||
} = useLogin(normalizeServerUrl(server), {
|
} = useLogin(
|
||||||
password,
|
normalizeServerUrl(server),
|
||||||
username,
|
{
|
||||||
});
|
password,
|
||||||
|
username,
|
||||||
const {
|
},
|
||||||
isLoading: isCheckingServer,
|
{
|
||||||
isSuccess: isValidServer,
|
onError: (error) => {
|
||||||
isFetched,
|
setErrorMessage(error?.response?.data?.error || error.message);
|
||||||
} = usePingServer(normalizeServerUrl(debouncedServer));
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Title>{t('auth.login')}</Title>
|
<Center sx={{ height: '100%' }}>
|
||||||
<form
|
<Stack
|
||||||
onSubmit={(e) => {
|
spacing={0}
|
||||||
e.preventDefault();
|
sx={{
|
||||||
handleLogin(undefined, {
|
filter: 'drop-shadow(0 0 5px var(--generic-border-color))',
|
||||||
onError: () => {},
|
height: '50%',
|
||||||
onSuccess: () => {},
|
maxWidth: '800px',
|
||||||
});
|
minWidth: '500px',
|
||||||
}}
|
width: '40vw',
|
||||||
>
|
}}
|
||||||
<Stack spacing="md">
|
>
|
||||||
<TextInput
|
<ErrorBoundary FallbackComponent={ErrorFallback}>
|
||||||
required
|
<Group position="center">
|
||||||
disabled={isLoading}
|
<form
|
||||||
error={!isValidServer && isFetched}
|
style={{
|
||||||
label={t('auth.server.label')}
|
display: 'flex',
|
||||||
placeholder={t('auth.server.placeholder')}
|
justifyContent: 'center',
|
||||||
rightSection={
|
width: '100%',
|
||||||
isCheckingServer ? (
|
}}
|
||||||
<Loader size="xs" />
|
onSubmit={(e) => {
|
||||||
) : isValidServer ? (
|
e.preventDefault();
|
||||||
<RiCheckboxCircleFill size={20} />
|
handleLogin(undefined, {
|
||||||
) : null
|
onError: () => {},
|
||||||
}
|
onSuccess: () => {},
|
||||||
value={server}
|
});
|
||||||
variant="default"
|
}}
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
>
|
||||||
setServer(e.currentTarget.value)
|
<Stack
|
||||||
}
|
p="2rem"
|
||||||
/>
|
spacing="xl"
|
||||||
<TextInput
|
sx={{
|
||||||
required
|
background: 'var(--main-bg)',
|
||||||
disabled={isLoading}
|
borderRadius: '5px',
|
||||||
label={`${t('auth.username.label')}`}
|
width: '80%',
|
||||||
placeholder={`${t('auth.username.placeholder')}`}
|
}}
|
||||||
value={username}
|
>
|
||||||
variant="default"
|
<Text
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
gradient={{ deg: 45, from: 'indigo', to: 'cyan' }}
|
||||||
setUsername(e.currentTarget.value)
|
size="xl"
|
||||||
}
|
variant="gradient"
|
||||||
/>
|
>
|
||||||
<PasswordInput
|
Login to Feishin
|
||||||
required
|
</Text>
|
||||||
disabled={isLoading}
|
<TextInput
|
||||||
label={`${t('auth.password.label')}`}
|
disabled={isLoading}
|
||||||
placeholder={`${t('auth.password.placeholder')}`}
|
label="Server URL"
|
||||||
value={password}
|
placeholder="http://localhost:8843"
|
||||||
variant="default"
|
value={server}
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
setPassword(e.currentTarget.value)
|
setServer(e.currentTarget.value)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Button disabled={!isValidServer} type="submit">
|
<TextInput
|
||||||
Login
|
disabled={isLoading}
|
||||||
</Button>
|
label="Username"
|
||||||
{isError && (
|
value={username}
|
||||||
<Alert color="red" variant="outline">
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
{t('Invalid username or password.')}
|
setUsername(e.currentTarget.value)
|
||||||
</Alert>
|
}
|
||||||
)}
|
/>
|
||||||
|
<PasswordInput
|
||||||
|
disabled={isLoading}
|
||||||
|
label="Password"
|
||||||
|
value={password}
|
||||||
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
|
setPassword(e.currentTarget.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
disabled={!username || !password}
|
||||||
|
loading={isLoading}
|
||||||
|
radius="xl"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</Button>
|
||||||
|
{isError && <Alert color="red">{errorMessage}</Alert>}
|
||||||
|
</Stack>
|
||||||
|
</form>
|
||||||
|
</Group>
|
||||||
|
</ErrorBoundary>
|
||||||
</Stack>
|
</Stack>
|
||||||
</form>
|
</Center>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user