mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 20:30:33 +00:00
feat(server): remove the phone number from users management
This commit is contained in:
@@ -4,7 +4,6 @@ import intl from 'react-intl-universal';
|
||||
import { Formik } from 'formik';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { Intent, Position } from '@blueprintjs/core';
|
||||
import { FormattedMessage as T } from '@/components';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
import { useInviteAcceptContext } from './InviteAcceptProvider';
|
||||
@@ -13,6 +12,14 @@ import { InviteAcceptSchema } from './utils';
|
||||
import InviteAcceptFormContent from './InviteAcceptFormContent';
|
||||
import { AuthInsiderCard } from './_components';
|
||||
|
||||
const initialValues = {
|
||||
organization_name: '',
|
||||
invited_email: '',
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
password: '',
|
||||
};
|
||||
|
||||
export default function InviteAcceptForm() {
|
||||
const history = useHistory();
|
||||
|
||||
@@ -20,9 +27,8 @@ export default function InviteAcceptForm() {
|
||||
const { inviteAcceptMutate, inviteMeta, token } = useInviteAcceptContext();
|
||||
|
||||
// Invite value.
|
||||
const inviteValue = {
|
||||
organization_name: '',
|
||||
invited_email: '',
|
||||
const inviteFormValue = {
|
||||
...initialValues,
|
||||
...(!isEmpty(inviteMeta)
|
||||
? {
|
||||
invited_email: inviteMeta.email,
|
||||
@@ -34,19 +40,17 @@ export default function InviteAcceptForm() {
|
||||
// Handle form submitting.
|
||||
const handleSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
inviteAcceptMutate([values, token])
|
||||
.then((response) => {
|
||||
.then(() => {
|
||||
AppToaster.show({
|
||||
message: intl.getHTML(
|
||||
'congrats_your_account_has_been_created_and_invited',
|
||||
{
|
||||
organization_name: inviteValue.organization_name,
|
||||
organization_name: inviteMeta.organizationName,
|
||||
},
|
||||
),
|
||||
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
history.push('/auth/login');
|
||||
setSubmitting(false);
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
@@ -84,7 +88,7 @@ export default function InviteAcceptForm() {
|
||||
<AuthInsiderCard>
|
||||
<Formik
|
||||
validationSchema={InviteAcceptSchema}
|
||||
initialValues={inviteValue}
|
||||
initialValues={inviteFormValue}
|
||||
onSubmit={handleSubmit}
|
||||
component={InviteAcceptFormContent}
|
||||
/>
|
||||
|
||||
@@ -1,34 +1,45 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { InputGroup, Intent } from '@blueprintjs/core';
|
||||
import { Button, InputGroup, Intent } from '@blueprintjs/core';
|
||||
import { Form, useFormikContext } from 'formik';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Tooltip2 } from '@blueprintjs/popover2';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Col, FFormGroup, Row, FormattedMessage as T } from '@/components';
|
||||
import {
|
||||
Col,
|
||||
FFormGroup,
|
||||
FInputGroup,
|
||||
Row,
|
||||
FormattedMessage as T,
|
||||
} from '@/components';
|
||||
import { useInviteAcceptContext } from './InviteAcceptProvider';
|
||||
import { PasswordRevealer } from './components';
|
||||
import { AuthSubmitButton } from './_components';
|
||||
|
||||
/**
|
||||
* Invite user form.
|
||||
*/
|
||||
export default function InviteUserFormContent() {
|
||||
// Invite accept context.
|
||||
const { inviteMeta } = useInviteAcceptContext();
|
||||
const [showPassword, setShowPassword] = useState<boolean>(false);
|
||||
|
||||
// Formik context.
|
||||
const { inviteMeta } = useInviteAcceptContext();
|
||||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
const [passwordType, setPasswordType] = React.useState('password');
|
||||
|
||||
// Handle password revealer changing.
|
||||
const handlePasswordRevealerChange = React.useCallback(
|
||||
(shown) => {
|
||||
const type = shown ? 'text' : 'password';
|
||||
setPasswordType(type);
|
||||
},
|
||||
[setPasswordType],
|
||||
const handleLockClick = () => {
|
||||
setShowPassword(!showPassword);
|
||||
};
|
||||
const lockButton = (
|
||||
<Tooltip2 content={`${showPassword ? 'Hide' : 'Show'} Password`}>
|
||||
<Button
|
||||
icon={showPassword ? 'unlock' : 'lock'}
|
||||
intent={Intent.WARNING}
|
||||
minimal={true}
|
||||
onClick={handleLockClick}
|
||||
small={true}
|
||||
/>
|
||||
</Tooltip2>
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -36,26 +47,27 @@ export default function InviteUserFormContent() {
|
||||
<Row>
|
||||
<Col md={6}>
|
||||
<FFormGroup name={'first_name'} label={<T id={'first_name'} />}>
|
||||
<InputGroup name={'first_name'} />
|
||||
<FInputGroup name={'first_name'} large={true} />
|
||||
</FFormGroup>
|
||||
</Col>
|
||||
|
||||
<Col md={6}>
|
||||
<FFormGroup name={'last_name'} label={<T id={'last_name'} />}>
|
||||
<InputGroup name={'last_name'} />
|
||||
<FInputGroup name={'last_name'} large={true} />
|
||||
</FFormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<FFormGroup
|
||||
name={'password'}
|
||||
label={<T id={'password'} />}
|
||||
labelInfo={<PasswordRevealer onChange={handlePasswordRevealerChange} />}
|
||||
>
|
||||
<InputGroup name={'password'} />
|
||||
<FFormGroup name={'password'} label={<T id={'password'} />}>
|
||||
<FInputGroup
|
||||
name={'password'}
|
||||
large={true}
|
||||
rightElement={lockButton}
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<div className={'invite-form__statement-section'}>
|
||||
<InviteAcceptFooterParagraphs>
|
||||
<p>
|
||||
<T id={'you_email_address_is'} /> <b>{inviteMeta.email},</b> <br />
|
||||
<T id={'you_will_use_this_address_to_sign_in_to_bigcapital'} />
|
||||
@@ -66,16 +78,25 @@ export default function InviteUserFormContent() {
|
||||
privacy: (msg) => <Link>{msg}</Link>,
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
</InviteAcceptFooterParagraphs>
|
||||
|
||||
<AuthSubmitButton
|
||||
<InviteAuthSubmitButton
|
||||
intent={Intent.PRIMARY}
|
||||
type="submit"
|
||||
fill={true}
|
||||
large={true}
|
||||
loading={isSubmitting}
|
||||
>
|
||||
<T id={'create_account'} />
|
||||
</AuthSubmitButton>
|
||||
</InviteAuthSubmitButton>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
const InviteAcceptFooterParagraphs = styled.div`
|
||||
opacity: 0.8;
|
||||
`;
|
||||
|
||||
const InviteAuthSubmitButton = styled(AuthSubmitButton)`
|
||||
margin-top: 1.6rem;
|
||||
`;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// @ts-nocheck
|
||||
import React, { createContext, useContext } from 'react';
|
||||
import React, { createContext, useContext, useEffect } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useInviteMetaByToken, useAuthInviteAccept } from '@/hooks/query';
|
||||
import { InviteAcceptLoading } from './components';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
const InviteAcceptContext = createContext();
|
||||
|
||||
@@ -22,11 +22,10 @@ function InviteAcceptProvider({ token, ...props }) {
|
||||
const { mutateAsync: inviteAcceptMutate } = useAuthInviteAccept({
|
||||
retry: false,
|
||||
});
|
||||
|
||||
// History context.
|
||||
const history = useHistory();
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (inviteMetaError) { history.push('/auth/login'); }
|
||||
}, [history, inviteMetaError]);
|
||||
|
||||
|
||||
@@ -1,51 +1,42 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import ContentLoader from 'react-content-loader';
|
||||
import { If, Icon, FormattedMessage as T } from '@/components';
|
||||
import { saveInvoke } from '@/utils';
|
||||
|
||||
export function PasswordRevealer({ defaultShown = false, onChange }) {
|
||||
const [shown, setShown] = React.useState(defaultShown);
|
||||
|
||||
const handleClick = () => {
|
||||
setShown(!shown);
|
||||
saveInvoke(onChange, !shown);
|
||||
};
|
||||
|
||||
return (
|
||||
<span class="password-revealer" onClick={handleClick}>
|
||||
<If condition={shown}>
|
||||
<Icon icon="eye-slash" />{' '}
|
||||
</If>
|
||||
<If condition={!shown}>
|
||||
<Icon icon="eye" />{' '}
|
||||
</If>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
import styled from 'styled-components';
|
||||
import { AuthInsiderCard } from './_components';
|
||||
import { Skeleton } from '@/components';
|
||||
|
||||
/**
|
||||
* Invite accept loading space.
|
||||
*/
|
||||
export function InviteAcceptLoading({ isLoading, children, ...props }) {
|
||||
export function InviteAcceptLoading({ isLoading, children }) {
|
||||
return isLoading ? (
|
||||
<ContentLoader
|
||||
speed={2}
|
||||
width={400}
|
||||
height={280}
|
||||
viewBox="0 0 400 280"
|
||||
backgroundColor="#f3f3f3"
|
||||
foregroundColor="#e6e6e6"
|
||||
{...props}
|
||||
>
|
||||
<rect x="0" y="80" rx="2" ry="2" width="200" height="20" />
|
||||
<rect x="0" y="0" rx="2" ry="2" width="250" height="30" />
|
||||
<rect x="0" y="38" rx="2" ry="2" width="300" height="15" />
|
||||
<rect x="0" y="175" rx="2" ry="2" width="200" height="20" />
|
||||
<rect x="1" y="205" rx="2" ry="2" width="385" height="38" />
|
||||
<rect x="0" y="110" rx="2" ry="2" width="385" height="38" />
|
||||
</ContentLoader>
|
||||
<AuthInsiderCard>
|
||||
<Fields>
|
||||
<SkeletonField />
|
||||
<SkeletonField />
|
||||
<SkeletonField />
|
||||
</Fields>
|
||||
</AuthInsiderCard>
|
||||
) : (
|
||||
children
|
||||
);
|
||||
}
|
||||
|
||||
function SkeletonField() {
|
||||
return (
|
||||
<SkeletonFieldRoot>
|
||||
<Skeleton>XXXX XXXX</Skeleton>
|
||||
<Skeleton minWidth={100}>XXXX XXXX XXXX XXXX</Skeleton>
|
||||
</SkeletonFieldRoot>
|
||||
);
|
||||
}
|
||||
|
||||
const Fields = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
`;
|
||||
const SkeletonFieldRoot = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
`;
|
||||
|
||||
@@ -42,10 +42,6 @@ export const SendResetPasswordSchema = Yup.object().shape({
|
||||
export const InviteAcceptSchema = Yup.object().shape({
|
||||
first_name: Yup.string().required().label(intl.get('first_name_')),
|
||||
last_name: Yup.string().required().label(intl.get('last_name_')),
|
||||
phone_number: Yup.string()
|
||||
.matches()
|
||||
.required()
|
||||
.label(intl.get('phone_number')),
|
||||
password: Yup.string().min(4).required().label(intl.get('password')),
|
||||
});
|
||||
|
||||
|
||||
@@ -6,10 +6,6 @@ const Schema = Yup.object().shape({
|
||||
email: Yup.string().email().required().label(intl.get('email')),
|
||||
first_name: Yup.string().required().label(intl.get('first_name_')),
|
||||
last_name: Yup.string().required().label(intl.get('last_name_')),
|
||||
phone_number: Yup.string()
|
||||
.matches()
|
||||
.required()
|
||||
.label(intl.get('phone_number_')),
|
||||
role_id: Yup.string().required().label(intl.get('roles.label.role_name_')),
|
||||
});
|
||||
|
||||
|
||||
@@ -13,7 +13,14 @@ import UserFormContent from './UserFormContent';
|
||||
import { useUserFormContext } from './UserFormProvider';
|
||||
import { transformErrors } from './utils';
|
||||
|
||||
import { compose, objectKeysTransform } from '@/utils';
|
||||
import { compose, objectKeysTransform, transformToForm } from '@/utils';
|
||||
|
||||
const initialValues = {
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
email: '',
|
||||
role_id: '',
|
||||
};
|
||||
|
||||
/**
|
||||
* User form.
|
||||
@@ -27,12 +34,9 @@ function UserForm({
|
||||
const { dialogName, user, userId, isEditMode, EditUserMutate } =
|
||||
useUserFormContext();
|
||||
|
||||
const initialValues = {
|
||||
...(isEditMode &&
|
||||
pick(
|
||||
objectKeysTransform(user, snakeCase),
|
||||
Object.keys(UserFormSchema.fields),
|
||||
)),
|
||||
const initialFormValues = {
|
||||
...initialValues,
|
||||
...(isEditMode && transformToForm(user, initialValues)),
|
||||
};
|
||||
|
||||
const handleSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
@@ -68,7 +72,7 @@ function UserForm({
|
||||
return (
|
||||
<Formik
|
||||
validationSchema={UserFormSchema}
|
||||
initialValues={initialValues}
|
||||
initialValues={initialFormValues}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<UserFormContent calloutCode={calloutCode} />
|
||||
|
||||
@@ -8,9 +8,10 @@ import {
|
||||
Button,
|
||||
} from '@blueprintjs/core';
|
||||
import { FastField, Form, useFormikContext, ErrorMessage } from 'formik';
|
||||
import { FormattedMessage as T } from '@/components';
|
||||
import { CLASSES } from '@/constants/classes';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { FFormGroup, FInputGroup, FormattedMessage as T } from '@/components';
|
||||
import { CLASSES } from '@/constants/classes';
|
||||
import { inputIntent } from '@/utils';
|
||||
import { ListSelect, FieldRequiredHint } from '@/components';
|
||||
import { useUserFormContext } from './UserFormProvider';
|
||||
@@ -23,6 +24,7 @@ import { UserFormCalloutAlerts } from './components';
|
||||
*/
|
||||
function UserFormContent({
|
||||
calloutCode,
|
||||
|
||||
// #withDialogActions
|
||||
closeDialog,
|
||||
}) {
|
||||
@@ -39,60 +41,20 @@ function UserFormContent({
|
||||
<UserFormCalloutAlerts calloutCodes={calloutCode} />
|
||||
|
||||
{/* ----------- Email ----------- */}
|
||||
<FastField name={'email'}>
|
||||
{({ field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'email'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
className={classNames('form-group--email', CLASSES.FILL)}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="email" />}
|
||||
>
|
||||
<InputGroup medium={true} {...field} />
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
<FFormGroup name={'email'} label={<T id={'email'} />}>
|
||||
<FInputGroup name={'email'} />
|
||||
</FFormGroup>
|
||||
|
||||
{/* ----------- First name ----------- */}
|
||||
<FastField name={'first_name'}>
|
||||
{({ form, field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'first_name'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name={'first_name'} />}
|
||||
>
|
||||
<InputGroup intent={inputIntent({ error, touched })} {...field} />
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
<FFormGroup name={'first_name'} label={<T id={'first_name'} />}>
|
||||
<FInputGroup name={'first_name'} />
|
||||
</FFormGroup>
|
||||
|
||||
{/* ----------- Last name ----------- */}
|
||||
<FastField name={'last_name'}>
|
||||
{({ form, field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'last_name'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name={'last_name'} />}
|
||||
>
|
||||
<InputGroup intent={inputIntent({ error, touched })} {...field} />
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
{/* ----------- Phone name ----------- */}
|
||||
<FastField name={'phone_number'}>
|
||||
{({ form, field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'phone_number'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name={'phone_number'} />}
|
||||
>
|
||||
<InputGroup intent={inputIntent({ error, touched })} {...field} />
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
<FFormGroup name={'last_name'} label={<T id={'last_name'} />}>
|
||||
<FInputGroup name={'last_name'} />
|
||||
</FFormGroup>
|
||||
|
||||
{/* ----------- Role name ----------- */}
|
||||
<FastField name={'role_id'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
@@ -127,7 +89,12 @@ function UserFormContent({
|
||||
<T id={'cancel'} />
|
||||
</Button>
|
||||
|
||||
<Button intent={Intent.PRIMARY} type="submit" disabled={isSubmitting}>
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
loading={isSubmitting}
|
||||
>
|
||||
<T id={'edit'} />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user