change(ui): auth with api error messages and antd components
This commit is contained in:
parent
0d9c265452
commit
ba55b359fb
5 changed files with 70 additions and 87 deletions
|
|
@ -1,8 +1,9 @@
|
|||
import React from 'react';
|
||||
import { Form, Input, Loader, Button, Icon } from 'UI';
|
||||
import { Loader, Icon } from 'UI';
|
||||
import ReCAPTCHA from 'react-google-recaptcha';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useStore } from 'App/mstore';
|
||||
import {Form, Input, Button } from 'antd'
|
||||
|
||||
function ResetPasswordRequest() {
|
||||
const { userStore } = useStore();
|
||||
|
|
@ -20,8 +21,8 @@ function ResetPasswordRequest() {
|
|||
if (name === 'email') setEmail(value);
|
||||
};
|
||||
|
||||
const onSubmit = (e: any) => {
|
||||
e.preventDefault();
|
||||
const onSubmit = () => {
|
||||
// e.preventDefault();
|
||||
if (CAPTCHA_ENABLED && recaptchaRef.current) {
|
||||
recaptchaRef.current.execute();
|
||||
} else if (!CAPTCHA_ENABLED) {
|
||||
|
|
@ -30,19 +31,21 @@ function ResetPasswordRequest() {
|
|||
};
|
||||
|
||||
const handleSubmit = (token?: any) => {
|
||||
if (CAPTCHA_ENABLED && recaptchaRef.current && (token === null || token === undefined)) return;
|
||||
if (CAPTCHA_ENABLED && recaptchaRef.current && (token === null || token === undefined)) return;
|
||||
|
||||
setError(null);
|
||||
requestResetPassword({ email: email.trim(), 'g-recaptcha-response': token })
|
||||
.then((response: any) => {
|
||||
setRequested(true);
|
||||
if (response && response.errors && response.errors.length > 0) {
|
||||
setError(response.errors[0]);
|
||||
}
|
||||
});
|
||||
// if (response && response.errors && response.errors.length > 0) {
|
||||
// setError(response.errors[0]);
|
||||
// }
|
||||
}).catch((err: any) => {
|
||||
setRequested(false);
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Form onSubmit={onSubmit} style={{ minWidth: '50%' }} className="flex flex-col">
|
||||
<Form onFinish={onSubmit} style={{ minWidth: '50%' }} className="flex flex-col">
|
||||
<Loader loading={false}>
|
||||
{CAPTCHA_ENABLED && (
|
||||
<div className="flex justify-center">
|
||||
|
|
@ -57,7 +60,7 @@ function ResetPasswordRequest() {
|
|||
)}
|
||||
{!requested && (
|
||||
<>
|
||||
<Form.Field>
|
||||
<Form.Item>
|
||||
<label>{'Email Address'}</label>
|
||||
<Input
|
||||
autoFocus={true}
|
||||
|
|
@ -67,11 +70,11 @@ function ResetPasswordRequest() {
|
|||
name="email"
|
||||
onChange={write}
|
||||
className="w-full"
|
||||
icon="envelope"
|
||||
prefix={<Icon name="envelope" size={16} />}
|
||||
required
|
||||
/>
|
||||
</Form.Field>
|
||||
<Button type="submit" variant="primary" className="mt-4 rounded-lg" loading={loading} disabled={loading}>
|
||||
</Form.Item>
|
||||
<Button type="primary" htmlType="submit" loading={loading} disabled={loading}>
|
||||
Email Password Reset Link
|
||||
</Button>
|
||||
</>
|
||||
|
|
@ -89,14 +92,14 @@ function ResetPasswordRequest() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<div className="flex items-center flex-col text-center">
|
||||
<div className="w-16 h-16 rounded-full bg-red-lightest flex items-center justify-center mb-2">
|
||||
<Icon name="envelope-x" size="30" color="red" />
|
||||
</div>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
{/*{error && (*/}
|
||||
{/* <div className="flex items-center flex-col text-center">*/}
|
||||
{/* <div className="w-16 h-16 rounded-full bg-red-lightest flex items-center justify-center mb-2">*/}
|
||||
{/* <Icon name="envelope-x" size="30" color="red" />*/}
|
||||
{/* </div>*/}
|
||||
{/* {error}*/}
|
||||
{/* </div>*/}
|
||||
{/*)}*/}
|
||||
</Loader>
|
||||
</Form>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ import { toast } from 'react-toastify';
|
|||
import { ENTERPRISE_REQUEIRED } from 'App/constants';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { forgotPassword, signup } from 'App/routes';
|
||||
import { Button, Form, Icon, Input, Link, Loader, Tooltip } from 'UI';
|
||||
import { Icon, Link, Loader, Tooltip } from 'UI';
|
||||
import { Button, Form, Input } from 'antd';
|
||||
|
||||
import Copyright from 'Shared/Copyright';
|
||||
|
||||
|
|
@ -24,12 +25,12 @@ interface LoginProps {
|
|||
}
|
||||
|
||||
const Login = ({
|
||||
location,
|
||||
}: LoginProps) => {
|
||||
location
|
||||
}: LoginProps) => {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const CAPTCHA_ENABLED = React.useMemo(() => {
|
||||
return window.env.CAPTCHA_ENABLED === 'true'
|
||||
return window.env.CAPTCHA_ENABLED === 'true';
|
||||
}, []);
|
||||
const recaptchaRef = useRef<ReCAPTCHA>(null);
|
||||
const { loginStore, userStore } = useStore();
|
||||
|
|
@ -41,9 +42,9 @@ const Login = ({
|
|||
const params = new URLSearchParams(location.search);
|
||||
|
||||
useEffect(() => {
|
||||
if (authDetails && !authDetails.tenants) {
|
||||
history.push(SIGNUP_ROUTE);
|
||||
}
|
||||
if (authDetails && !authDetails.tenants) {
|
||||
history.push(SIGNUP_ROUTE);
|
||||
}
|
||||
}, [authDetails]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -83,7 +84,7 @@ const Login = ({
|
|||
window.postMessage(
|
||||
{
|
||||
type: 'orspot:token',
|
||||
token: jwt,
|
||||
token: jwt
|
||||
},
|
||||
'*'
|
||||
);
|
||||
|
|
@ -104,7 +105,7 @@ const Login = ({
|
|||
.generateJWT()
|
||||
.then((resp) => {
|
||||
if (resp) {
|
||||
userStore.syntheticLogin(resp)
|
||||
userStore.syntheticLogin(resp);
|
||||
setJwt({ jwt: resp.jwt, spotJwt: resp.spotJwt ?? null });
|
||||
handleSpotLogin(resp.spotJwt);
|
||||
}
|
||||
|
|
@ -114,8 +115,7 @@ const Login = ({
|
|||
});
|
||||
};
|
||||
|
||||
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
const onSubmit = () => {
|
||||
if (CAPTCHA_ENABLED && recaptchaRef.current) {
|
||||
recaptchaRef.current.execute();
|
||||
} else if (!CAPTCHA_ENABLED) {
|
||||
|
|
@ -140,7 +140,7 @@ const Login = ({
|
|||
</h2>
|
||||
<div className={cn(authDetails?.enforceSSO ? '!hidden' : '')}>
|
||||
<Form
|
||||
onSubmit={onSubmit}
|
||||
onFinish={onSubmit}
|
||||
className={cn('flex items-center justify-center flex-col')}
|
||||
style={{ width: '350px' }}
|
||||
>
|
||||
|
|
@ -154,7 +154,7 @@ const Login = ({
|
|||
/>
|
||||
)}
|
||||
<div style={{ width: '350px' }} className="px-8">
|
||||
<Form.Field>
|
||||
<Form.Item>
|
||||
<label>Email Address</label>
|
||||
<Input
|
||||
data-test-id={'login'}
|
||||
|
|
@ -165,10 +165,10 @@ const Login = ({
|
|||
name="email"
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
icon="envelope"
|
||||
prefix={<Icon name="envelope" size={16} />}
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<label className="mb-2">Password</label>
|
||||
<Input
|
||||
data-test-id={'password'}
|
||||
|
|
@ -178,9 +178,9 @@ const Login = ({
|
|||
name="password"
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
icon="key"
|
||||
prefix={<Icon name="key" size={16} />}
|
||||
/>
|
||||
</Form.Field>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</Loader>
|
||||
{errors && errors.length ? (
|
||||
|
|
@ -201,8 +201,8 @@ const Login = ({
|
|||
<Button
|
||||
data-test-id={'log-button'}
|
||||
className="mt-2 w-full text-center rounded-lg"
|
||||
type="submit"
|
||||
variant="primary"
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
>
|
||||
{'Login'}
|
||||
</Button>
|
||||
|
|
@ -221,7 +221,7 @@ const Login = ({
|
|||
<div className={cn(stl.sso, 'py-2 flex flex-col items-center')}>
|
||||
{authDetails.sso ? (
|
||||
<a href={ssoLink} rel="noopener noreferrer">
|
||||
<Button variant="text-primary" type="submit">
|
||||
<Button type="text" htmlType="submit">
|
||||
{`Login with SSO ${
|
||||
authDetails.ssoProvider
|
||||
? `(${authDetails.ssoProvider})`
|
||||
|
|
@ -247,8 +247,8 @@ const Login = ({
|
|||
placement="top"
|
||||
>
|
||||
<Button
|
||||
variant="text-primary"
|
||||
type="submit"
|
||||
type="text"
|
||||
htmlType="submit"
|
||||
className="pointer-events-none opacity-30"
|
||||
>
|
||||
{`Login with SSO ${
|
||||
|
|
@ -263,11 +263,11 @@ const Login = ({
|
|||
</div>
|
||||
<div
|
||||
className={cn('flex items-center w-96 justify-center my-8', {
|
||||
'!hidden': !authDetails?.enforceSSO,
|
||||
'!hidden': !authDetails?.enforceSSO
|
||||
})}
|
||||
>
|
||||
<a href={ssoLink} rel="noopener noreferrer">
|
||||
<Button variant="primary">{`Login with SSO ${
|
||||
<Button type="primary">{`Login with SSO ${
|
||||
authDetails.ssoProvider ? `(${authDetails.ssoProvider})` : ''
|
||||
}`}</Button>
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -399,21 +399,18 @@ class UserStore {
|
|||
};
|
||||
|
||||
requestResetPassword = async (params: any) => {
|
||||
runInAction(() => {
|
||||
this.loading = true;
|
||||
});
|
||||
this.loading = true;
|
||||
try {
|
||||
const response = await userService.requestResetPassword(params);
|
||||
if (response.errors) {
|
||||
toast.error(response.errors[0] || 'Error resetting your password, please try again');
|
||||
return response;
|
||||
}
|
||||
await userService.requestResetPassword(params);
|
||||
// if (response.errors) {
|
||||
// toast.error(response.errors[0] || 'Error resetting your password, please try again');
|
||||
// return response;
|
||||
// }
|
||||
} catch (error) {
|
||||
toast.error('Unexpected error resetting your password; please try again');
|
||||
toast.error(error.message || 'Unexpected error resetting your password; please try again');
|
||||
throw error;
|
||||
} finally {
|
||||
runInAction(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -156,17 +156,9 @@ export default class UserService {
|
|||
}
|
||||
|
||||
async requestResetPassword(data: any) {
|
||||
try {
|
||||
const response = await this.client.post('/password/reset-link', data);
|
||||
const responseData = await response.json();
|
||||
return responseData.data || {};
|
||||
} catch (error: any) {
|
||||
if (error.response) {
|
||||
const errorData = await error.response.json();
|
||||
return { errors: errorData.errors };
|
||||
}
|
||||
return { errors: ['An unexpected error occurred.'] };
|
||||
}
|
||||
const response = await this.client.post('/password/reset-link', data);
|
||||
const responseData = await response.json();
|
||||
return responseData.data || {};
|
||||
}
|
||||
|
||||
updatePassword = async (data: any) => {
|
||||
|
|
|
|||
|
|
@ -6,27 +6,18 @@ export default class LoginService extends BaseService {
|
|||
password: string,
|
||||
captchaResponse?: string
|
||||
}) {
|
||||
try {
|
||||
const response = await this.client.post('/login', {
|
||||
email: email.trim(),
|
||||
password,
|
||||
'g-recaptcha-response': captchaResponse
|
||||
});
|
||||
const response = await this.client.post('/login', {
|
||||
email: email.trim(),
|
||||
password,
|
||||
'g-recaptcha-response': captchaResponse
|
||||
});
|
||||
|
||||
const responseData = await response.json();
|
||||
const responseData = await response.json();
|
||||
|
||||
if (responseData.errors) {
|
||||
throw new Error(responseData.errors[0] || 'An unexpected error occurred.');
|
||||
}
|
||||
// if (responseData.errors) {
|
||||
// throw new Error(responseData.errors[0] || 'An unexpected error occurred.');
|
||||
// }
|
||||
|
||||
return responseData || {};
|
||||
} catch (error: any) {
|
||||
if (error.response) {
|
||||
const errorData = await error.response.json();
|
||||
const errorMessage = errorData.errors ? errorData.errors[0] : 'An unexpected error occurred.';
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
throw new Error('An unexpected error occurred.');
|
||||
}
|
||||
return responseData || {};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue