mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 13:20:31 +00:00
WIP fix-general
This commit is contained in:
192
client/src/containers/Dashboard/Dialogs/InviteUserDialog.js
Normal file
192
client/src/containers/Dashboard/Dialogs/InviteUserDialog.js
Normal file
@@ -0,0 +1,192 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useFormik } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import {
|
||||
Dialog,
|
||||
Button,
|
||||
FormGroup,
|
||||
InputGroup,
|
||||
Intent,
|
||||
Classes,
|
||||
} from '@blueprintjs/core';
|
||||
import UserListDialogConnect from 'connectors/UsersList.connector';
|
||||
import DialogReduxConnect from 'components/DialogReduxConnect';
|
||||
import useAsync from 'hooks/async';
|
||||
import { objectKeysTransform } from 'utils';
|
||||
import { pick, snakeCase } from 'lodash';
|
||||
import ErrorMessage from 'components/ErrorMessage';
|
||||
import classNames from 'classnames';
|
||||
import AppToaster from 'components/AppToaster';
|
||||
import { compose } from 'utils';
|
||||
|
||||
function InviteUserDialog({
|
||||
name,
|
||||
payload,
|
||||
isOpen,
|
||||
closeDialog,
|
||||
requestFetchUser,
|
||||
requestEditUser,
|
||||
}) {
|
||||
const intl = useIntl();
|
||||
|
||||
const fetchHook = useAsync(async () => {
|
||||
await Promise.all([
|
||||
...(payload.action === 'edit' ? [requestFetchUser(payload.user.id)] : []),
|
||||
]);
|
||||
}, false);
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
first_name: Yup.string().required(intl.formatMessage({ id: 'required' })),
|
||||
last_name: Yup.string().required(intl.formatMessage({ id: 'required' })),
|
||||
email: Yup.string()
|
||||
.email()
|
||||
.required(intl.formatMessage({ id: 'required' })),
|
||||
phone_number: Yup.number().required(intl.formatMessage({ id: 'required' })),
|
||||
});
|
||||
|
||||
const initialValues = useMemo(
|
||||
() => ({
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
email: '',
|
||||
phone_number: '',
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const formik = useFormik({
|
||||
enableReinitialize: true,
|
||||
initialValues: {
|
||||
...(payload.action === 'edit' &&
|
||||
pick(
|
||||
objectKeysTransform(payload.user, snakeCase),
|
||||
Object.keys(initialValues)
|
||||
)),
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: (values, { setSubmitting }) => {
|
||||
const form = {
|
||||
...values,
|
||||
};
|
||||
if (payload.action === 'edit') {
|
||||
requestEditUser(payload.user.id, form)
|
||||
.then((response) => {
|
||||
closeDialog(name);
|
||||
AppToaster.show({
|
||||
message: 'the_user_details_has_been_updated',
|
||||
});
|
||||
setSubmitting(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
setSubmitting(false);
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
const { values, errors, touched } = useMemo(() => formik, [formik]);
|
||||
|
||||
const onDialogOpening = () => {
|
||||
fetchHook.execute();
|
||||
};
|
||||
|
||||
const onDialogClosed = () => {
|
||||
formik.resetForm();
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
closeDialog(name);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
name={name}
|
||||
title={payload.action === 'edit' ? 'Edit invite' : ''}
|
||||
className={classNames({
|
||||
'dialog--loading': fetchHook.pending,
|
||||
'dialog--invite-user': true,
|
||||
})}
|
||||
autoFocus={true}
|
||||
canEscapeKeyClose={true}
|
||||
isOpen={isOpen}
|
||||
isLoading={fetchHook.pending}
|
||||
onClosed={onDialogClosed}
|
||||
onOpening={onDialogOpening}
|
||||
>
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<FormGroup
|
||||
label={'First Name'}
|
||||
className={'form-group--first-name'}
|
||||
intent={errors.first_name && touched.first_name && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='first_name' {...formik} />}
|
||||
inline={true}
|
||||
>
|
||||
<InputGroup
|
||||
intent={errors.first_name && touched.first_name && Intent.DANGER}
|
||||
{...formik.getFieldProps('first_name')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={'Last Name'}
|
||||
className={'form-group--last-name'}
|
||||
intent={errors.last_name && touched.last_name && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='last_name' {...formik} />}
|
||||
inline={true}
|
||||
>
|
||||
<InputGroup
|
||||
intent={errors.last_name && touched.last_name && Intent.DANGER}
|
||||
{...formik.getFieldProps('last_name')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={'Email'}
|
||||
className={'form-group--email'}
|
||||
intent={errors.email && touched.email && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='email' {...formik} />}
|
||||
inline={true}
|
||||
>
|
||||
<InputGroup
|
||||
medium={true}
|
||||
intent={errors.email && touched.email && Intent.DANGER}
|
||||
{...formik.getFieldProps('email')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={'Phone Number'}
|
||||
className={'form-group--phone-number'}
|
||||
intent={
|
||||
errors.phone_number && touched.phone_number && Intent.DANGER
|
||||
}
|
||||
helperText={<ErrorMessage name='phone_number' {...formik} />}
|
||||
inline={true}
|
||||
>
|
||||
<InputGroup
|
||||
intent={
|
||||
errors.phone_number && touched.phone_number && Intent.DANGER
|
||||
}
|
||||
{...formik.getFieldProps('phone_number')}
|
||||
/>
|
||||
</FormGroup>
|
||||
</div>
|
||||
|
||||
<div className={Classes.DIALOG_FOOTER}>
|
||||
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||
<Button onClick={handleClose}>Close</Button>
|
||||
<Button intent={Intent.PRIMARY} type='submit'>
|
||||
{payload.action === 'edit' ? 'Edit' : ''}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
UserListDialogConnect,
|
||||
DialogReduxConnect
|
||||
)(InviteUserDialog);
|
||||
@@ -21,9 +21,9 @@ import classNames from 'classnames';
|
||||
import { compose } from 'utils';
|
||||
|
||||
function UserFormDialog({
|
||||
fetchUser,
|
||||
submitUser,
|
||||
editUser,
|
||||
requestFetchUser,
|
||||
requestSubmitInvite,
|
||||
requestEditUser,
|
||||
name,
|
||||
payload,
|
||||
isOpen,
|
||||
@@ -32,12 +32,12 @@ function UserFormDialog({
|
||||
const intl = useIntl();
|
||||
const fetchHook = useAsync(async () => {
|
||||
await Promise.all([
|
||||
...(payload.action === 'edit' ? [fetchUser(payload.user.id)] : []),
|
||||
...(payload.action === 'edit' ? [requestFetchUser(payload.user.id)] : []),
|
||||
]);
|
||||
}, false);
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
email: Yup.string().email().required(),
|
||||
email: Yup.string().email().required(intl.formatMessage({id:'required'})),
|
||||
});
|
||||
|
||||
const initialValues = {
|
||||
@@ -47,7 +47,6 @@ function UserFormDialog({
|
||||
objectKeysTransform(payload.user, snakeCase),
|
||||
Object.keys(validationSchema.fields)
|
||||
)),
|
||||
password: '',
|
||||
};
|
||||
|
||||
const formik = useFormik({
|
||||
@@ -57,17 +56,16 @@ function UserFormDialog({
|
||||
onSubmit: (values) => {
|
||||
const form = {
|
||||
...values,
|
||||
confirm_password: values.password,
|
||||
};
|
||||
if (payload.action === 'edit') {
|
||||
editUser(payload.user.id, form).then((response) => {
|
||||
requestEditUser(payload.user.id, form).then((response) => {
|
||||
AppToaster.show({
|
||||
message: 'the_user_details_has_been_updated',
|
||||
});
|
||||
closeDialog(name);
|
||||
});
|
||||
} else {
|
||||
submitUser(form).then((response) => {
|
||||
requestSubmitInvite(form).then((response) => {
|
||||
AppToaster.show({
|
||||
message: 'the_user_has_been_invited',
|
||||
});
|
||||
@@ -93,7 +91,7 @@ function UserFormDialog({
|
||||
return (
|
||||
<Dialog
|
||||
name={name}
|
||||
title={payload.action === 'edit' ? 'Edit invite' : 'New invite'}
|
||||
title={payload.action === 'edit' ? 'Edit invite' : 'invite User'}
|
||||
className={classNames({
|
||||
'dialog--loading': fetchHook.pending,
|
||||
'dialog--invite-form': true,
|
||||
@@ -120,19 +118,6 @@ function UserFormDialog({
|
||||
{...formik.getFieldProps('email')}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={'Email'}
|
||||
className={'form-group--email'}
|
||||
intent={errors.email && touched.email && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='email' {...formik} />}
|
||||
inline={true}
|
||||
>
|
||||
<InputGroup
|
||||
medium={true}
|
||||
intent={errors.email && touched.email && Intent.DANGER}
|
||||
{...formik.getFieldProps('email')}
|
||||
/>
|
||||
</FormGroup>
|
||||
</div>
|
||||
|
||||
<div className={Classes.DIALOG_FOOTER}>
|
||||
|
||||
@@ -1,49 +1,36 @@
|
||||
import React, {useCallback} from 'react';
|
||||
import {
|
||||
Tabs,
|
||||
Tab,
|
||||
Button,
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import React, { useCallback } from 'react';
|
||||
import { Tabs, Tab, Button, Intent } from '@blueprintjs/core';
|
||||
import PreferencesSubContent from 'components/Preferences/PreferencesSubContent';
|
||||
import connector from 'connectors/UsersPreferences.connector';
|
||||
|
||||
function UsersPreferences({
|
||||
openDialog,
|
||||
}) {
|
||||
const onChangeTabs = (currentTabId) => {
|
||||
|
||||
};
|
||||
function UsersPreferences({ openDialog }) {
|
||||
const onChangeTabs = (currentTabId) => {};
|
||||
|
||||
const onClickNewUser = useCallback(() => {
|
||||
openDialog('user-form');
|
||||
}, [openDialog]);
|
||||
|
||||
return (
|
||||
<div class="preferences__inside-content preferences__inside-content--users-roles">
|
||||
<div class="preferences__tabs">
|
||||
<Tabs
|
||||
animate={true}
|
||||
large={true}
|
||||
onChange={onChangeTabs}>
|
||||
<Tab id="users" title="Users" />
|
||||
<Tab id="roles" title="Roles" />
|
||||
|
||||
<div class='preferences__inside-content preferences__inside-content--users-roles'>
|
||||
<div class='preferences__tabs'>
|
||||
<Tabs animate={true} large={true} onChange={onChangeTabs}>
|
||||
<Tab id='users' title='Users' />
|
||||
<Tab id='roles' title='Roles' />
|
||||
|
||||
<div class="preferences__tabs-extra-actions">
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
onClick={onClickNewUser}>New invite</Button>
|
||||
<div class='preferences__tabs-extra-actions'>
|
||||
<Button intent={Intent.PRIMARY} onClick={onClickNewUser}>
|
||||
Invite User
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
onClick={onClickNewUser}>New Role</Button>
|
||||
</div>
|
||||
<Button intent={Intent.PRIMARY} onClick={onClickNewUser}>
|
||||
New Role
|
||||
</Button>
|
||||
</div>
|
||||
</Tabs>
|
||||
</div>
|
||||
<PreferencesSubContent preferenceTab="users" />
|
||||
<PreferencesSubContent preferenceTab='users' />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connector(UsersPreferences);
|
||||
export default connector(UsersPreferences);
|
||||
|
||||
@@ -21,30 +21,48 @@ import DialogConnect from 'connectors/Dialog.connector';
|
||||
import DashboardConnect from 'connectors/Dashboard.connector';
|
||||
|
||||
function UsersListPreferences({
|
||||
fetchUsers,
|
||||
requestFetchUsers,
|
||||
usersList,
|
||||
openDialog,
|
||||
closeDialog,
|
||||
deleteUser,
|
||||
requestDeleteUser,
|
||||
requestInactiveUser,
|
||||
onFetchData,
|
||||
}) {
|
||||
const [deleteUserState, setDeleteUserState] = useState(false);
|
||||
const [inactiveUserState, setInactiveUserState] = useState(false);
|
||||
|
||||
const asyncHook = useAsync(async () => {
|
||||
await Promise.all([fetchUsers()]);
|
||||
await Promise.all([requestFetchUsers()]);
|
||||
}, []);
|
||||
|
||||
const onInactiveUser = (user) => {};
|
||||
const onInactiveUser = (user) => {
|
||||
setInactiveUserState(user);
|
||||
};
|
||||
|
||||
// Handle cancel inactive user alert
|
||||
const handleCancelInactiveUser = useCallback(() => {
|
||||
setInactiveUserState(false);
|
||||
}, []);
|
||||
|
||||
// handel confirm user activation
|
||||
const handleConfirmUserActive = useCallback(() => {
|
||||
requestInactiveUser(inactiveUserState.id).then(() => {
|
||||
setInactiveUserState(false);
|
||||
requestFetchUsers();
|
||||
AppToaster.show({ message: 'the_user_has_been_inactivated' });
|
||||
});
|
||||
}, [inactiveUserState, requestInactiveUser, requestFetchUsers]);
|
||||
|
||||
const onDeleteUser = (user) => {
|
||||
setDeleteUserState(user);
|
||||
};
|
||||
|
||||
const handleCancelUserDelete = () => {
|
||||
setDeleteUserState(false);
|
||||
};
|
||||
|
||||
const onEditUser = (user) => () => {
|
||||
const onEditInviteUser = (user) => () => {
|
||||
const form = Object.keys(user).reduce((obj, key) => {
|
||||
const camelKey = snakeCase(key);
|
||||
obj[camelKey] = user[key];
|
||||
@@ -54,12 +72,22 @@ function UsersListPreferences({
|
||||
openDialog('user-form', { action: 'edit', user: form });
|
||||
};
|
||||
|
||||
const onEditUser = (user) => () => {
|
||||
const form = Object.keys(user).reduce((obj, key) => {
|
||||
const camelKey = snakeCase(key);
|
||||
obj[camelKey] = user[key];
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
openDialog('userList-form', { action: 'edit', user: form });
|
||||
};
|
||||
|
||||
const handleConfirmUserDelete = () => {
|
||||
if (!deleteUserState) {
|
||||
return;
|
||||
}
|
||||
|
||||
deleteUser(deleteUserState.id).then((response) => {
|
||||
requestDeleteUser(deleteUserState.id).then((response) => {
|
||||
setDeleteUserState(false);
|
||||
AppToaster.show({
|
||||
message: 'the_user_has_been_deleted',
|
||||
@@ -67,16 +95,18 @@ function UsersListPreferences({
|
||||
});
|
||||
};
|
||||
|
||||
const actionMenuList = (user) => (
|
||||
<Menu>
|
||||
<MenuItem text='Edit User' onClick={onEditUser(user)} />
|
||||
<MenuItem text='New Account' />
|
||||
<MenuDivider />
|
||||
<MenuItem text='Inactivate User' onClick={() => onInactiveUser(user)} />
|
||||
<MenuItem text='Delete User' onClick={() => onDeleteUser(user)} />
|
||||
</Menu>
|
||||
const actionMenuList = useCallback(
|
||||
(user) => (
|
||||
<Menu>
|
||||
<MenuItem text='Edit User' onClick={onEditUser(user)} />
|
||||
<MenuDivider />
|
||||
<MenuItem text='Edit Invite ' onClick={onEditInviteUser(user)} />
|
||||
<MenuItem text='Inactivate User' onClick={() => onInactiveUser(user)} />
|
||||
<MenuItem text='Delete User' onClick={() => onDeleteUser(user)} />
|
||||
</Menu>
|
||||
),
|
||||
[]
|
||||
);
|
||||
console.log(usersList, 'X');
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
@@ -151,6 +181,21 @@ function UsersListPreferences({
|
||||
able to restore it later, but it will become private to you.
|
||||
</p>
|
||||
</Alert>
|
||||
|
||||
<Alert
|
||||
cancelButtonText='Cancel'
|
||||
confirmButtonText='Inactivate'
|
||||
icon='trash'
|
||||
intent={Intent.WARNING}
|
||||
isOpen={inactiveUserState}
|
||||
onCancel={handleCancelInactiveUser}
|
||||
onConfirm={handleConfirmUserActive}
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to move <b>filename</b> to Trash? You will be
|
||||
able to restore it later, but it will become private to you.
|
||||
</p>
|
||||
</Alert>
|
||||
</LoadingIndicator>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user