feat(webapp): sign-up restrictions

This commit is contained in:
a.bouhuolia
2023-05-07 23:54:42 +02:00
parent ad3c9ebfe9
commit dd26bdc482
9 changed files with 148 additions and 35 deletions

View File

@@ -0,0 +1,36 @@
// @ts-nocheck
import React, { createContext } from 'react';
import { useAuthMetadata } from '@/hooks/query';
import { Spinner } from '@blueprintjs/core';
import styled from 'styled-components';
const AuthMetaBootContext = createContext();
/**
* Boots the authentication page metadata.
*/
function AuthMetaBootProvider({ ...props }) {
const { isLoading: isAuthMetaLoading, data: authMeta } = useAuthMetadata();
const state = {
isAuthMetaLoading,
signupDisabled: authMeta?.meta?.signup_disabled,
};
if (isAuthMetaLoading) {
return (
<SpinnerRoot>
<Spinner size={30} value={null} />
</SpinnerRoot>
);
}
return <AuthMetaBootContext.Provider value={state} {...props} />;
}
const useAuthMetaBoot = () => React.useContext(AuthMetaBootContext);
export { AuthMetaBootContext, AuthMetaBootProvider, useAuthMetaBoot };
const SpinnerRoot = styled.div`
margin-top: 5rem;
`;

View File

@@ -10,12 +10,11 @@ import { Icon, FormattedMessage as T } from '@/components';
import { useIsAuthenticated } from '@/hooks/state';
import '@/style/pages/Authentication/Auth.scss';
import { AuthMetaBootProvider } from './AuthMetaBoot';
export function Authentication() {
const to = { pathname: '/' };
const location = useLocation();
const isAuthenticated = useIsAuthenticated();
const locationKey = location.pathname;
if (isAuthenticated) {
return <Redirect to={to} />;
@@ -28,30 +27,41 @@ export function Authentication() {
<Icon icon="bigcapital" height={37} width={214} />
</AuthLogo>
<TransitionGroup>
<CSSTransition
timeout={500}
key={locationKey}
classNames="authTransition"
>
<Switch>
{authenticationRoutes.map((route, index) => (
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.component}
/>
))}
</Switch>
</CSSTransition>
</TransitionGroup>
<AuthMetaBootProvider>
<AuthenticationRoutes />
</AuthMetaBootProvider>
</AuthInsider>
</AuthPage>
</BodyClassName>
);
}
function AuthenticationRoutes() {
const location = useLocation();
const locationKey = location.pathname;
return (
<TransitionGroup>
<CSSTransition
timeout={500}
key={locationKey}
classNames="authTransition"
>
<Switch>
{authenticationRoutes.map((route, index) => (
<Route
key={index}
path={route.path}
exact={route.exact}
component={route.component}
/>
))}
</Switch>
</CSSTransition>
</TransitionGroup>
);
}
const AuthPage = styled.div``;
const AuthInsider = styled.div`
width: 384px;

View File

@@ -14,11 +14,12 @@ import {
AuthFooterLink,
AuthInsiderCard,
} from './_components';
import { useAuthMetaBoot } from './AuthMetaBoot';
const initialValues = {
crediential: '',
password: '',
keepLoggedIn: false
keepLoggedIn: false,
};
/**
@@ -64,12 +65,15 @@ export default function Login() {
}
function LoginFooterLinks() {
const { signupDisabled } = useAuthMetaBoot();
return (
<AuthFooterLinks>
<AuthFooterLink>
Don't have an account? <Link to={'/auth/register'}>Sign up</Link>
</AuthFooterLink>
{!signupDisabled && (
<AuthFooterLink>
Don't have an account? <Link to={'/auth/register'}>Sign up</Link>
</AuthFooterLink>
)}
<AuthFooterLink>
<Link to={'/auth/send_reset_password'}>
<T id={'forget_my_password'} />

View File

@@ -10,7 +10,7 @@ import AuthInsider from '@/containers/Authentication/AuthInsider';
import { useAuthLogin, useAuthRegister } from '@/hooks/query/authentication';
import RegisterForm from './RegisterForm';
import { RegisterSchema, transformRegisterErrorsToForm } from './utils';
import { RegisterSchema, transformRegisterErrorsToForm, transformRegisterToastMessages } from './utils';
import {
AuthFooterLinks,
AuthFooterLink,
@@ -57,7 +57,11 @@ export default function RegisterUserForm() {
},
}) => {
const formErrors = transformRegisterErrorsToForm(errors);
const toastMessages = transformRegisterToastMessages(errors);
toastMessages.forEach((toastMessage) => {
AppToaster.show(toastMessage);
});
setErrors(formErrors);
setSubmitting(false);
},

View File

@@ -16,6 +16,7 @@ import {
} from './_components';
import ResetPasswordForm from './ResetPasswordForm';
import { ResetPasswordSchema } from './utils';
import { useAuthMetaBoot } from './AuthMetaBoot';
const initialValues = {
password: '',
@@ -79,12 +80,15 @@ export default function ResetPassword() {
}
function ResetPasswordFooterLinks() {
const { signupDisabled } = useAuthMetaBoot();
return (
<AuthFooterLinks>
<AuthFooterLink>
Don't have an account? <Link to={'/auth/register'}>Sign up</Link>
</AuthFooterLink>
{!signupDisabled && (
<AuthFooterLink>
Don't have an account? <Link to={'/auth/register'}>Sign up</Link>
</AuthFooterLink>
)}
<AuthFooterLink>
Return to <Link to={'/auth/login'}>Sign In</Link>
</AuthFooterLink>

View File

@@ -19,6 +19,7 @@ import {
transformSendResetPassErrorsToToasts,
} from './utils';
import AuthInsider from '@/containers/Authentication/AuthInsider';
import { useAuthMetaBoot } from './AuthMetaBoot';
const initialValues = {
crediential: '',
@@ -27,7 +28,7 @@ const initialValues = {
/**
* Send reset password page.
*/
export default function SendResetPassword({ requestSendResetPassword }) {
export default function SendResetPassword() {
const history = useHistory();
const { mutateAsync: sendResetPasswordMutate } = useAuthSendResetPassword();
@@ -75,12 +76,15 @@ export default function SendResetPassword({ requestSendResetPassword }) {
}
function SendResetPasswordFooterLinks() {
const { signupDisabled } = useAuthMetaBoot();
return (
<AuthFooterLinks>
<AuthFooterLink>
Don't have an account? <Link to={'/auth/register'}>Sign up</Link>
</AuthFooterLink>
{!signupDisabled && (
<AuthFooterLink>
Don't have an account? <Link to={'/auth/register'}>Sign up</Link>
</AuthFooterLink>
)}
<AuthFooterLink>
Return to <Link to={'/auth/login'}>Sign In</Link>
</AuthFooterLink>

View File

@@ -94,3 +94,29 @@ export const transformRegisterErrorsToForm = (errors) => {
}
return formErrors;
};
export const transformRegisterToastMessages = (errors) => {
const toastErrors = [];
if (errors.some((e) => e.type === 'SIGNUP_NOT_ALLOWED_EMAIL_DOMAIN')) {
toastErrors.push({
message:
'The sign-up is restricted, the given email domain is not allowed to sign-up.',
intent: Intent.DANGER,
});
} else if (
errors.some((e) => e.type === 'SIGNUP_NOT_ALLOWED_EMAIL_ADDRESS')
) {
toastErrors.push({
message:
'The sign-up is restricted, the given email address is not allowed to sign-up.',
intent: Intent.DANGER,
});
} else if (errors.find((e) => e.type === 'SIGNUP_RESTRICTED')) {
toastErrors.push({
message: 'Sign-up is disabled, and no new accounts can be created.',
intent: Intent.DANGER,
});
}
return toastErrors;
};

View File

@@ -2,6 +2,8 @@
import { useMutation } from 'react-query';
import useApiRequest from '../useRequest';
import { setCookie } from '../../utils';
import { useRequestQuery } from '../useQueryRequest';
import t from './types';
/**
* Saves the response data to cookies.
@@ -70,3 +72,21 @@ export const useAuthResetPassword = (props) => {
props,
);
};
/**
* Fetches the authentication page metadata.
*/
export const useAuthMetadata = (props) => {
return useRequestQuery(
[t.AUTH_METADATA_PAGE,],
{
method: 'get',
url: `auth/meta`,
},
{
select: (res) => res.data,
defaultData: {},
...props,
},
);
}

View File

@@ -1,4 +1,8 @@
// @ts-nocheck
const Authentication = {
AUTH_METADATA_PAGE: 'AUTH_META_PAGE'
}
const ACCOUNTS = {
ACCOUNT: 'ACCOUNT',
ACCOUNT_TRANSACTION: 'ACCOUNT_TRANSACTION',
@@ -217,6 +221,7 @@ const DASHBOARD = {
};
export default {
...Authentication,
...ACCOUNTS,
...BILLS,
...VENDORS,