mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
WIP Feature / General & Users & Sidebar
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { useIntl } from "react-intl"
|
||||
import {useFormik} from 'formik';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useFormik } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import {
|
||||
Dialog,
|
||||
@@ -18,8 +18,12 @@ import UserFormDialogConnect from 'connectors/UserFormDialog.connector';
|
||||
import DialogReduxConnect from 'components/DialogReduxConnect';
|
||||
import AppToaster from 'components/AppToaster';
|
||||
import useAsync from 'hooks/async';
|
||||
import {objectKeysTransform} from 'utils';
|
||||
import {pick, snakeCase} from 'lodash';
|
||||
import { objectKeysTransform } from 'utils';
|
||||
import { pick, snakeCase } from 'lodash';
|
||||
import ErrorMessage from 'components/ErrorMessage';
|
||||
import classNames from 'classnames';
|
||||
import Icon from 'components/Icon';
|
||||
import { compose } from 'utils';
|
||||
|
||||
function UserFormDialog({
|
||||
fetchUser,
|
||||
@@ -34,27 +38,21 @@ function UserFormDialog({
|
||||
const intl = useIntl();
|
||||
const fetchHook = useAsync(async () => {
|
||||
await Promise.all([
|
||||
...(payload.action === 'edit') ? [
|
||||
fetchUser(payload.user.id),
|
||||
] : [],
|
||||
...(payload.action === 'edit' ? [fetchUser(payload.user.id)] : []),
|
||||
]);
|
||||
}, false);
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
first_name: Yup.string().required(),
|
||||
last_name: Yup.string().required(),
|
||||
email: Yup.string().email().required(),
|
||||
phone_number: Yup.string().required(),
|
||||
password: Yup.string().min(5).required(),
|
||||
});
|
||||
|
||||
const initialValues = {
|
||||
status: 1,
|
||||
...payload.action === 'edit' &&
|
||||
...(payload.action === 'edit' &&
|
||||
pick(
|
||||
objectKeysTransform(payload.user, snakeCase),
|
||||
Object.keys(validationSchema.fields)
|
||||
),
|
||||
)),
|
||||
password: '',
|
||||
};
|
||||
|
||||
@@ -84,113 +82,76 @@ function UserFormDialog({
|
||||
}
|
||||
},
|
||||
});
|
||||
const { values, errors, touched } = useMemo(() => formik, [formik]);
|
||||
|
||||
const statusOptions = [
|
||||
{value: 1, label: 'Active'},
|
||||
{value: 2, label: 'Inactive'},
|
||||
{ value: 1, label: 'Active' },
|
||||
{ value: 2, label: 'Inactive' },
|
||||
];
|
||||
|
||||
const onDialogOpening = () => { fetchHook.execute(); };
|
||||
const onDialogOpening = () => {
|
||||
fetchHook.execute();
|
||||
};
|
||||
|
||||
const onDialogClosed = () => {
|
||||
formik.resetForm();
|
||||
|
||||
};
|
||||
|
||||
const handleClose = () => { closeDialog(name); };
|
||||
const handleClose = () => {
|
||||
closeDialog(name);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
isOpen={isOpen}
|
||||
name={name}
|
||||
title={payload.action === 'edit' ? 'Edit User' : 'New User'}
|
||||
title={payload.action === 'edit' ? 'Edit invite' : 'New invite'}
|
||||
className={classNames({
|
||||
'dialog--loading': fetchHook.pending,
|
||||
'dialog--invite-form': true,
|
||||
})}
|
||||
autoFocus={true}
|
||||
canEscapeKeyClose={true}
|
||||
isOpen={isOpen}
|
||||
isLoading={fetchHook.pending}
|
||||
onClosed={onDialogClosed}
|
||||
onOpening={onDialogOpening}>
|
||||
|
||||
onOpening={onDialogOpening}
|
||||
>
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<FormGroup
|
||||
label={'First Name'}
|
||||
className={'form-group--first-name'}
|
||||
intent={formik.errors.first_name && Intent.DANGER}
|
||||
helperText={formik.errors.first_name && formik.errors.first_name}
|
||||
inline={true}>
|
||||
|
||||
label={'Email'}
|
||||
className={'form-group--email'}
|
||||
intent={errors.email && touched.email && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='email' {...formik} />}
|
||||
inline={true}
|
||||
>
|
||||
<InputGroup
|
||||
intent={formik.errors.first_name && Intent.DANGER}
|
||||
{...formik.getFieldProps('first_name')} />
|
||||
medium={true}
|
||||
intent={errors.email && touched.email && Intent.DANGER}
|
||||
{...formik.getFieldProps('email')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={'Last Name'}
|
||||
className={'form-group--last-name'}
|
||||
intent={formik.errors.last_name && Intent.DANGER}
|
||||
helperText={formik.errors.last_name && formik.errors.last_name}
|
||||
inline={true}>
|
||||
|
||||
<InputGroup
|
||||
intent={formik.errors.last_name && Intent.DANGER}
|
||||
{...formik.getFieldProps('last_name')} />
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={'Email'}
|
||||
className={'form-group--email'}
|
||||
intent={formik.errors.email && Intent.DANGER}
|
||||
helperText={formik.errors.email && formik.errors.email}
|
||||
inline={true}>
|
||||
|
||||
intent={errors.email && touched.email && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='email' {...formik} />}
|
||||
inline={true}
|
||||
>
|
||||
<InputGroup
|
||||
intent={formik.errors.email && Intent.DANGER}
|
||||
{...formik.getFieldProps('email')} />
|
||||
medium={true}
|
||||
intent={errors.email && touched.email && Intent.DANGER}
|
||||
{...formik.getFieldProps('email')}
|
||||
/>
|
||||
</FormGroup>
|
||||
</div>
|
||||
|
||||
<FormGroup
|
||||
label={'Phone Number'}
|
||||
className={'form-group--phone-number'}
|
||||
intent={formik.errors.phone_number && Intent.DANGER}
|
||||
helperText={formik.errors.phone_number && formik.errors.phone_number}
|
||||
inline={true}>
|
||||
|
||||
<InputGroup
|
||||
intent={formik.errors.phone_number && Intent.DANGER}
|
||||
{...formik.getFieldProps('phone_number')} />
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={'Password'}
|
||||
className={'form-group--password'}
|
||||
intent={formik.errors.password && Intent.DANGER}
|
||||
helperText={formik.errors.password && formik.errors.password}
|
||||
inline={true}>
|
||||
|
||||
<InputGroup
|
||||
intent={formik.errors.password && Intent.DANGER}
|
||||
className={Classes.FILL}
|
||||
{...formik.getFieldProps('password')} />
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={'Status'}
|
||||
className={'form-group--status'}
|
||||
intent={formik.errors.status && Intent.DANGER}
|
||||
helperText={formik.errors.status && formik.errors.status}
|
||||
inline={true}>
|
||||
|
||||
<HTMLSelect
|
||||
options={statusOptions}
|
||||
className={Classes.FILL}
|
||||
{...formik.getFieldProps(`status`)} />
|
||||
</FormGroup>
|
||||
|
||||
<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' : 'Submit' }
|
||||
</Button>
|
||||
</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' : 'invite'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -198,4 +159,7 @@ function UserFormDialog({
|
||||
);
|
||||
}
|
||||
|
||||
export default UserFormDialogConnect(DialogReduxConnect(UserFormDialog));
|
||||
export default compose(
|
||||
UserFormDialogConnect,
|
||||
DialogReduxConnect
|
||||
)(UserFormDialog);
|
||||
|
||||
@@ -3,21 +3,45 @@ import {} from 'reselect';
|
||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
||||
|
||||
import { compose } from 'utils';
|
||||
import { NavbarGroup, Button, Classes, Intent } from '@blueprintjs/core';
|
||||
import {
|
||||
NavbarGroup,
|
||||
Button,
|
||||
Classes,
|
||||
Intent,
|
||||
Popover,
|
||||
Position,
|
||||
PopoverInteractionKind,
|
||||
} from '@blueprintjs/core';
|
||||
import classNames from 'classnames';
|
||||
import Icon from 'components/Icon';
|
||||
import DashboardConnect from 'connectors/Dashboard.connector';
|
||||
import ItemsCategoryConnect from 'connectors/ItemsCategory.connect';
|
||||
import DialogConnect from 'connectors/Dialog.connector';
|
||||
import FilterDropdown from 'components/FilterDropdown';
|
||||
import ResourceConnect from 'connectors/Resource.connector';
|
||||
|
||||
const ItemsCategoryActionsBar = ({ openDialog, onDeleteCategory }) => {
|
||||
const ItemsCategoryActionsBar = ({
|
||||
openDialog,
|
||||
onDeleteCategory,
|
||||
onFilterChanged,
|
||||
getResourceFields,
|
||||
}) => {
|
||||
const onClickNewCategory = () => {
|
||||
openDialog('item-form', {});
|
||||
};
|
||||
|
||||
const handleDeleteCategory = category => {
|
||||
const handleDeleteCategory = (category) => {
|
||||
onDeleteCategory(category);
|
||||
};
|
||||
|
||||
const categoriesFields = getResourceFields('itemCategories');
|
||||
|
||||
const filterDropdown = FilterDropdown({
|
||||
fields: categoriesFields,
|
||||
onFilterChange: (filterConditions) => {
|
||||
onFilterChanged && onFilterChanged(filterConditions);
|
||||
},
|
||||
});
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
@@ -27,6 +51,17 @@ const ItemsCategoryActionsBar = ({ openDialog, onDeleteCategory }) => {
|
||||
text='New Category'
|
||||
onClick={onClickNewCategory}
|
||||
/>
|
||||
<Popover
|
||||
content={filterDropdown}
|
||||
interactionKind={PopoverInteractionKind.CLICK}
|
||||
position={Position.BOTTOM_LEFT}
|
||||
>
|
||||
<Button
|
||||
className={classNames(Classes.MINIMAL, 'button--filter')}
|
||||
text='Filter'
|
||||
icon={<Icon icon='filter' />}
|
||||
/>
|
||||
</Popover>
|
||||
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
@@ -54,5 +89,6 @@ const ItemsCategoryActionsBar = ({ openDialog, onDeleteCategory }) => {
|
||||
export default compose(
|
||||
DialogConnect,
|
||||
DashboardConnect,
|
||||
ItemsCategoryConnect
|
||||
ItemsCategoryConnect,
|
||||
ResourceConnect
|
||||
)(ItemsCategoryActionsBar);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useCallback, useMemo } from 'react';
|
||||
import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
||||
import { useFormik } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import {
|
||||
@@ -10,16 +10,24 @@ import {
|
||||
Classes,
|
||||
} from '@blueprintjs/core';
|
||||
|
||||
import { optionsMapToArray, momentFormatter } from 'utils';
|
||||
import { optionsMapToArray, momentFormatter, optionsArrayToMap } from 'utils';
|
||||
import { TimezonePicker } from '@blueprintjs/timezone';
|
||||
import { Select } from '@blueprintjs/select';
|
||||
import classNames from 'classnames';
|
||||
import ErrorMessage from 'components/ErrorMessage';
|
||||
import Icon from 'components/Icon';
|
||||
import { compose } from 'utils';
|
||||
import SettingsConnect from 'connectors/Settings.connect';
|
||||
import AppToaster from 'components/AppToaster';
|
||||
import { useIntl } from 'react-intl';
|
||||
import useAsync from 'hooks/async';
|
||||
|
||||
function GeneralPreferences(props) {
|
||||
function GeneralPreferences({
|
||||
organizationSettings,
|
||||
requestSubmitOptions,
|
||||
requestFetchOptions,
|
||||
}) {
|
||||
const [selectedItems, setSelectedItems] = useState({});
|
||||
const [disableItems, setDisableItems] = useState(false);
|
||||
const [timeZone, setTimeZone] = useState('');
|
||||
|
||||
const businessLocation = [
|
||||
@@ -28,8 +36,8 @@ function GeneralPreferences(props) {
|
||||
{ id: 212, name: 'Morocco', code: 'MA' },
|
||||
];
|
||||
const languagesDisplay = [
|
||||
{ name: 'EN', label: 'English' },
|
||||
{ name: 'Arb', label: 'Arabic' },
|
||||
{ id: 0, name: 'EN', label: 'English' },
|
||||
{ id: 1, name: 'Arb', label: 'Arabic' },
|
||||
];
|
||||
const currencies = [
|
||||
{ id: 0, name: 'US Dollar', code: 'USD' },
|
||||
@@ -41,34 +49,59 @@ function GeneralPreferences(props) {
|
||||
{ id: 1, name: 'August-December', label: 'August-December' },
|
||||
];
|
||||
const dateFormat = [
|
||||
{ name: '04/11/2020', format: 'MM-DD-YY' },
|
||||
{ name: '2020/03/21', format: 'YY/MM/DD' },
|
||||
{ name: 'Apr 11, 2020', format: 'MMMM yyyy' },
|
||||
{ name: 'Saturday, Apr 11, 2020', format: 'EEEE, MMM d, yyyy' },
|
||||
{ id: 1, name: '04/11/2020', format: 'MM-DD-YY' },
|
||||
{ id: 3, name: '2020/03/21', format: 'YY/MM/DD' },
|
||||
{ id: 4, name: 'Apr 11, 2020', format: 'MMMM yyyy' },
|
||||
{ id: 6, name: 'Saturday, Apr 11, 2020', format: 'EEEE, MMM d, yyyy' },
|
||||
];
|
||||
|
||||
const intl = useIntl();
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
organization_name: Yup.string().required('required field'),
|
||||
organization_industry: Yup.string().required('required field'),
|
||||
business_location: Yup.string().required('required field'),
|
||||
base_currency: Yup.string().required('required field'),
|
||||
fiscal_year: Yup.string().required('required field'),
|
||||
language: Yup.string().required('required field'),
|
||||
time_zone: Yup.date().required('required field'),
|
||||
date_format: Yup.date().required('required field'),
|
||||
name: Yup.string().required(intl.formatMessage({ id: 'required' })),
|
||||
industry: Yup.string().required(intl.formatMessage({ id: 'required' })),
|
||||
location: Yup.string().required(intl.formatMessage({ id: 'required' })),
|
||||
base_currency: Yup.string().required(
|
||||
intl.formatMessage({ id: 'required' })
|
||||
),
|
||||
fiscal_year: Yup.string().required(intl.formatMessage({ id: 'required' })),
|
||||
language: Yup.string().required(intl.formatMessage({ id: 'required' })),
|
||||
// time_zone: Yup.object().required(intl.formatMessage({ id: 'required' })),
|
||||
date_format: Yup.date().required(intl.formatMessage({ id: 'required' })),
|
||||
});
|
||||
console.log(organizationSettings.name);
|
||||
|
||||
const formik = useFormik({
|
||||
enableReinitialize: true,
|
||||
initialValues: {},
|
||||
initialValues: {
|
||||
...organizationSettings,
|
||||
},
|
||||
validationSchema: validationSchema,
|
||||
onSubmit: (values) => {
|
||||
|
||||
onSubmit: (values, { setSubmitting }) => {
|
||||
const options = optionsMapToArray(values).map((option) => {
|
||||
return { ...option, group: 'general' };
|
||||
return { key: option.key, ...option, group: 'organization' };
|
||||
});
|
||||
|
||||
requestSubmitOptions({ options })
|
||||
.then((response) => {
|
||||
AppToaster.show({
|
||||
message: 'The_Options_has_been_Submit',
|
||||
});
|
||||
setSubmitting(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
setSubmitting(false);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const { errors, values, touched } = useMemo(() => formik, [formik]);
|
||||
|
||||
const fetchHook = useAsync(async () => {
|
||||
await Promise.all([requestFetchOptions()]);
|
||||
});
|
||||
|
||||
const businessLocationItem = (item, { handleClick }) => (
|
||||
<MenuItem
|
||||
className={'preferences-menu'}
|
||||
@@ -107,7 +140,7 @@ function GeneralPreferences(props) {
|
||||
/>
|
||||
);
|
||||
|
||||
const data_Format = (item, { handleClick }) => (
|
||||
const date_format = (item, { handleClick }) => (
|
||||
<MenuItem
|
||||
className={'preferences-menu'}
|
||||
key={item.id}
|
||||
@@ -126,6 +159,7 @@ function GeneralPreferences(props) {
|
||||
formik.setFieldValue(filedName, filed.name);
|
||||
};
|
||||
};
|
||||
|
||||
const getSelectedItemLabel = (filedName, defaultLabel) => {
|
||||
return typeof selectedItems[filedName] !== 'undefined'
|
||||
? selectedItems[filedName].name
|
||||
@@ -140,42 +174,26 @@ function GeneralPreferences(props) {
|
||||
<FormGroup
|
||||
label={'Organization Name'}
|
||||
inline={true}
|
||||
intent={
|
||||
errors.organization_name &&
|
||||
touched.organization_name &&
|
||||
Intent.DANGER
|
||||
}
|
||||
helperText={<ErrorMessage name='organization_name' {...formik} />}
|
||||
intent={errors.name && touched.name && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='name' {...formik} />}
|
||||
>
|
||||
<InputGroup
|
||||
medium={true}
|
||||
intent={
|
||||
errors.organization_name &&
|
||||
touched.organization_name &&
|
||||
Intent.DANGER
|
||||
}
|
||||
{...formik.getFieldProps('organization_name')}
|
||||
medium={'true'}
|
||||
intent={errors.name && touched.name && Intent.DANGER}
|
||||
{...formik.getFieldProps('name')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={'Organization Industry'}
|
||||
inline={true}
|
||||
intent={
|
||||
errors.organization_industry &&
|
||||
touched.organization_industry &&
|
||||
Intent.DANGER
|
||||
}
|
||||
helperText={<ErrorMessage name='organization_industry' {...formik} />}
|
||||
intent={errors.industry && touched.industry && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='industry' {...formik} />}
|
||||
>
|
||||
<InputGroup
|
||||
medium={true}
|
||||
intent={
|
||||
errors.organization_industry &&
|
||||
touched.organization_industry &&
|
||||
Intent.DANGER
|
||||
}
|
||||
{...formik.getFieldProps('organization_industry')}
|
||||
medium={'true'}
|
||||
intent={errors.industry && touched.industry && Intent.DANGER}
|
||||
{...formik.getFieldProps('industry')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
@@ -187,26 +205,22 @@ function GeneralPreferences(props) {
|
||||
Classes.FILL
|
||||
)}
|
||||
inline={true}
|
||||
helperText={<ErrorMessage name='business_location' {...formik} />}
|
||||
intent={
|
||||
errors.business_location &&
|
||||
touched.business_location &&
|
||||
Intent.DANGER
|
||||
}
|
||||
helperText={<ErrorMessage name='location' {...formik} />}
|
||||
intent={errors.location && touched.location && Intent.DANGER}
|
||||
>
|
||||
<Select
|
||||
items={businessLocation}
|
||||
noResults={<MenuItem disabled={true} text='No result.' />}
|
||||
itemRenderer={businessLocationItem}
|
||||
popoverProps={{ minimal: true }}
|
||||
onItemSelect={onItemsSelect('business_location')}
|
||||
onItemSelect={onItemsSelect('location')}
|
||||
>
|
||||
<Button
|
||||
fill={true}
|
||||
rightIcon='caret-down'
|
||||
text={getSelectedItemLabel(
|
||||
'business_location',
|
||||
'Business Location'
|
||||
'location',
|
||||
organizationSettings.location
|
||||
)}
|
||||
/>
|
||||
</Select>
|
||||
@@ -235,7 +249,10 @@ function GeneralPreferences(props) {
|
||||
<Button
|
||||
fill={true}
|
||||
rightIcon='caret-down'
|
||||
text={getSelectedItemLabel('base_currency', 'Base Currency')}
|
||||
text={getSelectedItemLabel(
|
||||
'base_currency',
|
||||
organizationSettings.base_currency
|
||||
)}
|
||||
/>
|
||||
</Select>
|
||||
</FormGroup>
|
||||
@@ -261,7 +278,10 @@ function GeneralPreferences(props) {
|
||||
<Button
|
||||
fill={true}
|
||||
rightIcon='caret-down'
|
||||
text={getSelectedItemLabel('fiscal_year', 'Fiscal Year')}
|
||||
text={getSelectedItemLabel(
|
||||
'fiscal_year',
|
||||
organizationSettings.fiscal_year
|
||||
)}
|
||||
/>
|
||||
</Select>
|
||||
</FormGroup>
|
||||
@@ -286,11 +306,13 @@ function GeneralPreferences(props) {
|
||||
>
|
||||
<Button
|
||||
rightIcon='caret-down'
|
||||
text={getSelectedItemLabel('language', 'English')}
|
||||
text={getSelectedItemLabel(
|
||||
'language',
|
||||
organizationSettings.language
|
||||
)}
|
||||
/>
|
||||
</Select>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={'Time Zone'}
|
||||
inline={true}
|
||||
@@ -309,30 +331,30 @@ function GeneralPreferences(props) {
|
||||
valueDisplayFormat='composite'
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={'Date Format'}
|
||||
inline={true}
|
||||
className={classNames(
|
||||
'form-group--date-format',
|
||||
'form-group--language',
|
||||
'form-group--select-list',
|
||||
Classes.FILL
|
||||
)}
|
||||
intent={errors.date_format && touched.data_Format && Intent.DANGER}
|
||||
intent={errors.date_format && touched.date_format && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='date_format' {...formik} />}
|
||||
minimal={true}
|
||||
>
|
||||
<Select
|
||||
items={dateFormat}
|
||||
noResults={<MenuItem disabled={true} text='No result.' />}
|
||||
itemRenderer={data_Format}
|
||||
popoverProps={{ minimal: true }}
|
||||
itemRenderer={date_format}
|
||||
popoverProp={{ minimal: true }}
|
||||
onItemSelect={onItemsSelect('date_format')}
|
||||
>
|
||||
<Button
|
||||
fill={true}
|
||||
rightIcon='caret-down'
|
||||
text={getSelectedItemLabel('fiscal_year', 'Fiscal Year')}
|
||||
text={getSelectedItemLabel(
|
||||
'date_format',
|
||||
organizationSettings.date_format
|
||||
)}
|
||||
/>
|
||||
</Select>
|
||||
</FormGroup>
|
||||
@@ -352,4 +374,4 @@ function GeneralPreferences(props) {
|
||||
);
|
||||
}
|
||||
|
||||
export default GeneralPreferences;
|
||||
export default compose(SettingsConnect)(GeneralPreferences);
|
||||
|
||||
@@ -29,17 +29,18 @@ function UsersPreferences({
|
||||
onChange={onChangeTabs}>
|
||||
<Tab id="users" title="Users" />
|
||||
<Tab id="roles" title="Roles" />
|
||||
</Tabs>
|
||||
|
||||
|
||||
<div class="preferences__tabs-extra-actions">
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
onClick={onClickNewUser}>New User</Button>
|
||||
onClick={onClickNewUser}>New invite</Button>
|
||||
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
onClick={onClickNewUser}>New Role</Button>
|
||||
</div>
|
||||
</Tabs>
|
||||
</div>
|
||||
<PreferencesSubContent preferenceTab="users" />
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import React, {useState} from 'react';
|
||||
import {useAsync} from 'react-use';
|
||||
import {
|
||||
GridComponent,
|
||||
ColumnsDirective,
|
||||
ColumnDirective,
|
||||
} from '@syncfusion/ej2-react-grids';
|
||||
import React, { useState, useMemo, useCallback } from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import DataTable from 'components/DataTable';
|
||||
import {
|
||||
Alert,
|
||||
Popover,
|
||||
@@ -17,9 +13,12 @@ import {
|
||||
} from '@blueprintjs/core';
|
||||
import Icon from 'components/Icon';
|
||||
import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import {snakeCase} from 'lodash';
|
||||
import connector from 'connectors/UsersList.connector';
|
||||
import { snakeCase } from 'lodash';
|
||||
import UserListConnect from 'connectors/UsersList.connector';
|
||||
import AppToaster from 'components/AppToaster';
|
||||
import { compose } from 'utils';
|
||||
import DialogConnect from 'connectors/Dialog.connector';
|
||||
import DashboardConnect from 'connectors/Dashboard.connector';
|
||||
|
||||
function UsersListPreferences({
|
||||
fetchUsers,
|
||||
@@ -27,22 +26,23 @@ function UsersListPreferences({
|
||||
openDialog,
|
||||
closeDialog,
|
||||
deleteUser,
|
||||
onFetchData,
|
||||
}) {
|
||||
const [deleteUserState, setDeleteUserState] = useState(false);
|
||||
const [inactiveUserState, setInactiveUserState] = useState(false);
|
||||
|
||||
const asyncHook = useAsync(async () => {
|
||||
await Promise.all([
|
||||
fetchUsers(),
|
||||
]);
|
||||
await Promise.all([fetchUsers()]);
|
||||
}, []);
|
||||
|
||||
const onInactiveUser = (user) => {
|
||||
const onInactiveUser = (user) => {};
|
||||
|
||||
const onDeleteUser = (user) => {
|
||||
setDeleteUserState(user);
|
||||
};
|
||||
const handleCancelUserDelete = () => {
|
||||
setDeleteUserState(false);
|
||||
};
|
||||
|
||||
const onDeleteUser = (user) => { setDeleteUserState(user); };
|
||||
const handleCancelUserDelete = () => { setDeleteUserState(false); };
|
||||
|
||||
const onEditUser = (user) => () => {
|
||||
const form = Object.keys(user).reduce((obj, key) => {
|
||||
@@ -51,11 +51,13 @@ function UsersListPreferences({
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
openDialog('user-form', { action: 'edit', user: form, });
|
||||
openDialog('user-form', { action: 'edit', user: form });
|
||||
};
|
||||
|
||||
const handleConfirmUserDelete = () => {
|
||||
if (!deleteUserState) { return; }
|
||||
if (!deleteUserState) {
|
||||
return;
|
||||
}
|
||||
|
||||
deleteUser(deleteUserState.id).then((response) => {
|
||||
setDeleteUserState(false);
|
||||
@@ -65,79 +67,96 @@ function UsersListPreferences({
|
||||
});
|
||||
};
|
||||
|
||||
const actionMenuList = (user) =>
|
||||
(<Menu>
|
||||
<MenuItem text="Edit User" onClick={onEditUser(user)} />
|
||||
<MenuItem text="New Account" />
|
||||
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>);
|
||||
<MenuItem text='Inactivate User' onClick={() => onInactiveUser(user)} />
|
||||
<MenuItem text='Delete User' onClick={() => onDeleteUser(user)} />
|
||||
</Menu>
|
||||
);
|
||||
console.log(usersList, 'X');
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'full_name',
|
||||
Header: 'Full Name',
|
||||
accessor: 'full_name',
|
||||
width: 170,
|
||||
},
|
||||
{
|
||||
id: 'email',
|
||||
Header: 'Email',
|
||||
accessor: 'email',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
id: 'phone_number',
|
||||
Header: 'Phone Number',
|
||||
accessor: 'phone_number',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
id: 'active',
|
||||
Header: 'Status',
|
||||
accessor: (user) =>
|
||||
user.active ? <span>Active</span> : <span>Inactivate</span>,
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
Header: '',
|
||||
Cell: ({ cell }) => (
|
||||
<Popover
|
||||
content={actionMenuList(cell.row.original)}
|
||||
position={Position.RIGHT_TOP}
|
||||
>
|
||||
<Button icon={<Icon icon='ellipsis-h' />} />
|
||||
</Popover>
|
||||
),
|
||||
className: 'actions',
|
||||
width: 50,
|
||||
},
|
||||
],
|
||||
[actionMenuList]
|
||||
);
|
||||
|
||||
const handelDataTableFetchData = useCallback(() => {
|
||||
onFetchData && onFetchData();
|
||||
}, []);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
field: '',
|
||||
headerText: 'Avatar',
|
||||
},
|
||||
{
|
||||
field: 'fullName',
|
||||
headerText: 'Full Name',
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
headerText: 'Email',
|
||||
},
|
||||
{
|
||||
field: 'phoneNumber',
|
||||
headerText: 'Phone Number',
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
headerText: 'Status',
|
||||
template: (user) => user.active
|
||||
? (<span>Active</span>) : (<span>Inactive</span>)
|
||||
},
|
||||
{
|
||||
template: (user) => (
|
||||
<Popover content={actionMenuList(user)} position={Position.RIGHT_BOTTOM}>
|
||||
<Button icon={<Icon icon="ellipsis-h" />} />
|
||||
</Popover>
|
||||
),
|
||||
}
|
||||
]
|
||||
return (
|
||||
<LoadingIndicator loading={asyncHook.loading}>
|
||||
<GridComponent
|
||||
dataSource={{result: usersList.results}}>
|
||||
|
||||
<ColumnsDirective>
|
||||
{columns.map((column) => {
|
||||
return (<ColumnDirective
|
||||
field={column.field}
|
||||
headerText={column.headerText}
|
||||
template={column.template}
|
||||
allowSorting={true}
|
||||
customAttributes={column.customAttributes}
|
||||
/>);
|
||||
})}
|
||||
</ColumnsDirective>
|
||||
</GridComponent>
|
||||
<LoadingIndicator>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={usersList}
|
||||
onFetchData={handelDataTableFetchData()}
|
||||
manualSortBy={true}
|
||||
expandable={false}
|
||||
/>
|
||||
|
||||
<Alert
|
||||
cancelButtonText="Cancel"
|
||||
confirmButtonText="Move to Trash"
|
||||
icon="trash"
|
||||
cancelButtonText='Cancel'
|
||||
confirmButtonText='Move to Trash'
|
||||
icon='trash'
|
||||
intent={Intent.DANGER}
|
||||
isOpen={deleteUserState}
|
||||
onCancel={handleCancelUserDelete}
|
||||
onConfirm={handleConfirmUserDelete}>
|
||||
onConfirm={handleConfirmUserDelete}
|
||||
>
|
||||
<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.
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
export default connector(UsersListPreferences);
|
||||
export default compose(
|
||||
UserListConnect,
|
||||
DialogConnect,
|
||||
DashboardConnect
|
||||
)(UsersListPreferences);
|
||||
|
||||
Reference in New Issue
Block a user