1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-10-18 11:14:57 +02:00
unleash.unleash/frontend/src/component/user/HostedAuth.tsx
Thomas Heartman b2c58102dd
chore(unl-204): remove uses of toast text and confetti (#8941)
As of PR #8935, we no longer support both text and title, and confetti
has been removed.

This PR:
- removes `confetti` from the toast interface
- merges `text` and `title` into `text` and updates its uses across the
codebase.
- readjusts the text where necessary.
2024-12-10 13:38:04 +00:00

176 lines
6.3 KiB
TypeScript

import { type FormEventHandler, useState, type VFC } from 'react';
import { Button, Grid, styled, TextField, Typography } from '@mui/material';
import { useNavigate } from 'react-router';
import useQueryParams from 'hooks/useQueryParams';
import AuthOptions from './common/AuthOptions/AuthOptions';
import DividerText from 'component/common/DividerText/DividerText';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import PasswordField from 'component/common/PasswordField/PasswordField';
import { useAuthApi } from 'hooks/api/actions/useAuthApi/useAuthApi';
import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser';
import { LOGIN_BUTTON, LOGIN_EMAIL_ID, LOGIN_PASSWORD_ID } from 'utils/testIds';
import type { IAuthEndpointDetailsResponse } from 'hooks/api/getters/useAuth/useAuthEndpoint';
import { BadRequestError, NotFoundError } from 'utils/apiUtils';
import { contentSpacingY } from 'themes/themeStyles';
import useToast from 'hooks/useToast';
interface IHostedAuthProps {
authDetails: IAuthEndpointDetailsResponse;
redirect: string;
}
const StyledTypography = styled(Typography)(({ theme }) => ({
color: theme.palette.error.main,
}));
const StyledDiv = styled('div')(({ theme }) => ({
...contentSpacingY(theme),
display: 'flex',
flexDirection: 'column',
}));
const StyledButton = styled(Button)(({ theme }) => ({
width: '150px',
margin: theme.spacing(2, 'auto', 0, 'auto'),
display: 'block',
textAlign: 'center',
}));
const HostedAuth: VFC<IHostedAuthProps> = ({ authDetails, redirect }) => {
const { refetchUser } = useAuthUser();
const navigate = useNavigate();
const params = useQueryParams();
const { passwordAuth } = useAuthApi();
const [username, setUsername] = useState(params.get('email') || '');
const [password, setPassword] = useState('');
const [errors, setErrors] = useState<{
usernameError?: string;
passwordError?: string;
apiError?: string;
}>({});
const { setToastData } = useToast();
const handleSubmit: FormEventHandler<HTMLFormElement> = async (evt) => {
evt.preventDefault();
if (!username) {
setErrors((prev) => ({
...prev,
usernameError: 'This is a required field',
}));
}
if (!password) {
setErrors((prev) => ({
...prev,
passwordError: 'This is a required field',
}));
}
if (!password || !username) {
return;
}
try {
const data = await passwordAuth(
authDetails.path,
username,
password,
);
if (data.deletedSessions && data.activeSessions) {
setToastData({
type: 'success',
text: `Maximum session limit of ${data.activeSessions} reached`,
});
}
refetchUser();
navigate(redirect, { replace: true });
} catch (error: any) {
if (
error instanceof NotFoundError ||
error instanceof BadRequestError
) {
setErrors((prev) => ({
...prev,
apiError: 'Invalid login details',
}));
setPassword('');
setUsername('');
} else {
setErrors({
apiError: 'Unknown error while trying to authenticate.',
});
}
}
};
const { usernameError, passwordError, apiError } = errors;
const { options = [] } = authDetails;
return (
<>
<ConditionallyRender
condition={options.length > 0}
show={
<>
<AuthOptions options={options} />
<DividerText text='or signin with username' />
</>
}
/>
<ConditionallyRender
condition={!authDetails.defaultHidden}
show={
<form onSubmit={handleSubmit}>
<StyledTypography variant='subtitle2'>
{apiError}
</StyledTypography>
<StyledDiv>
<TextField
label='Username or email'
name='username'
id='username'
type='text'
onChange={(evt) =>
setUsername(evt.target.value)
}
value={username}
error={Boolean(usernameError)}
helperText={usernameError}
variant='outlined'
size='small'
data-testid={LOGIN_EMAIL_ID}
/>
<PasswordField
label='Password'
onChange={(evt) =>
setPassword(evt.target.value)
}
name='password'
id='password'
value={password}
error={Boolean(passwordError)}
helperText={passwordError}
autoComplete='current-password'
data-testid={LOGIN_PASSWORD_ID}
/>
<Grid container>
<StyledButton
variant='contained'
color='primary'
type='submit'
data-testid={LOGIN_BUTTON}
>
Sign in
</StyledButton>
</Grid>
</StyledDiv>
</form>
}
/>
</>
);
};
export default HostedAuth;