mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 04:40:32 +00:00
WIP Fix & last tasks
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useState, useMemo } from 'react';
|
||||
import React, { useCallback, useState, useMemo, useEffect } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Popover,
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
Alert,
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useQuery, queryCache } from 'react-query';
|
||||
|
||||
import Icon from 'components/Icon';
|
||||
import { compose } from 'utils';
|
||||
@@ -18,133 +18,165 @@ import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import DataTable from 'components/DataTable';
|
||||
import AppToaster from 'components/AppToaster';
|
||||
|
||||
import withDashboard from 'connectors/Dashboard.connector';
|
||||
import withDashboard from 'containers/Dashboard/withDashboard';
|
||||
|
||||
import withCurrencies from 'containers/Currencies/withCurrencies';
|
||||
import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
|
||||
import {
|
||||
FormattedMessage as T,
|
||||
FormattedHTMLMessage,
|
||||
useIntl,
|
||||
} from 'react-intl';
|
||||
|
||||
function CurrenciesList({
|
||||
// #withCurrencies
|
||||
currenciesList,
|
||||
|
||||
currenciesList,
|
||||
currenciesLoading,
|
||||
// #withCurrenciesActions
|
||||
requestDeleteCurrency,
|
||||
requestFetchCurrencies,
|
||||
|
||||
// #withDialog
|
||||
openDialog,
|
||||
changePreferencesPageTitle,
|
||||
|
||||
// #ownProps
|
||||
onFetchData,
|
||||
}) {
|
||||
const [deleteCurrencyState, setDeleteCurrencyState] = useState(false);
|
||||
const { formatMessage } = useIntl()
|
||||
const fetchCurrencies = useQuery(['currencies-table'],
|
||||
() => requestFetchCurrencies());
|
||||
const [tableLoading, setTableLoading] = useState(false);
|
||||
const [initialMount, setInitialMount] = useState(false);
|
||||
|
||||
// const handleEditCurrency = (currency) => {
|
||||
// openDialog('currency-form', {
|
||||
// action: 'edit',
|
||||
// currencyCode: currency.currency_code,
|
||||
// });
|
||||
// };
|
||||
const handleEditCurrency =useCallback((currency)=>{
|
||||
openDialog('currency-form', {
|
||||
action: 'edit',
|
||||
currencyCode: currency.currency_code,
|
||||
});
|
||||
},[openDialog])
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const fetchCurrencies = useQuery('currencies-table', () =>
|
||||
requestFetchCurrencies(),
|
||||
);
|
||||
|
||||
// const onDeleteCurrency = (currency) => {
|
||||
// setDeleteCurrencyState(currency);
|
||||
// };
|
||||
useEffect(() => {
|
||||
changePreferencesPageTitle(formatMessage({ id: 'currencies' }));
|
||||
}, [changePreferencesPageTitle, formatMessage]);
|
||||
|
||||
const onDeleteCurrency =useCallback((currency)=>{setDeleteCurrencyState(currency);},[])
|
||||
const handleEditCurrency = useCallback(
|
||||
(currency) => {
|
||||
openDialog('currency-form', {
|
||||
action: 'edit',
|
||||
currencyCode: currency.currency_code,
|
||||
});
|
||||
},
|
||||
[openDialog],
|
||||
);
|
||||
|
||||
const onDeleteCurrency = useCallback((currency) => {
|
||||
setDeleteCurrencyState(currency);
|
||||
}, []);
|
||||
const handleCancelCurrencyDelete = () => {
|
||||
setDeleteCurrencyState(false);
|
||||
};
|
||||
|
||||
const handleConfirmCurrencyDelete = useCallback(() => {
|
||||
requestDeleteCurrency(deleteCurrencyState.currency_code).then(
|
||||
(response) => {
|
||||
setDeleteCurrencyState(false);
|
||||
AppToaster.show({
|
||||
message: formatMessage({id:'the_currency_has_been_successfully_deleted'}),
|
||||
const handleConfirmCurrencyDelete = useCallback(
|
||||
(refetch) => {
|
||||
requestDeleteCurrency(deleteCurrencyState.currency_code)
|
||||
.then((response) => {
|
||||
setDeleteCurrencyState(false);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_currency_has_been_successfully_deleted',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
})
|
||||
.catch((errors) => {
|
||||
setDeleteCurrencyState(false);
|
||||
});
|
||||
}
|
||||
);
|
||||
}, [requestDeleteCurrency,deleteCurrencyState,formatMessage]);
|
||||
|
||||
const actionMenuList = useCallback((currency) => (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
text={<T id={'edit_currency'} />}
|
||||
onClick={() => handleEditCurrency(currency)} />
|
||||
|
||||
<MenuItem
|
||||
text={<T id={'delete_currency'} />}
|
||||
onClick={() => onDeleteCurrency(currency)}
|
||||
/>
|
||||
</Menu>
|
||||
), [handleEditCurrency,onDeleteCurrency]);
|
||||
|
||||
const columns = useMemo(() => [
|
||||
{
|
||||
Header: formatMessage({id:'currency_name'}),
|
||||
accessor: 'currency_name',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
Header: formatMessage({id:'currency_code'}),
|
||||
accessor: 'currency_code',
|
||||
className: 'currency_code',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
Header: 'Currency sign',
|
||||
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,formatMessage]);
|
||||
[deleteCurrencyState, requestDeleteCurrency, formatMessage],
|
||||
);
|
||||
|
||||
const handleDatatableFetchData = useCallback(() => {
|
||||
const actionMenuList = useCallback(
|
||||
(currency) => (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
text={<T id={'edit_currency'} />}
|
||||
onClick={() => handleEditCurrency(currency)}
|
||||
/>
|
||||
|
||||
<MenuItem
|
||||
text={<T id={'delete_currency'} />}
|
||||
onClick={() => onDeleteCurrency(currency)}
|
||||
intent={Intent.DANGER}
|
||||
/>
|
||||
</Menu>
|
||||
),
|
||||
[handleEditCurrency, onDeleteCurrency],
|
||||
);
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: formatMessage({ id: 'currency_name' }),
|
||||
accessor: 'currency_name',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
Header: formatMessage({ id: 'currency_code' }),
|
||||
accessor: 'currency_code',
|
||||
className: 'currency_code',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
Header: 'Currency sign',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
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, formatMessage],
|
||||
);
|
||||
|
||||
const handleDataTableFetchData = useCallback(() => {
|
||||
onFetchData && onFetchData();
|
||||
}, [onFetchData]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<LoadingIndicator>
|
||||
<LoadingIndicator loading={fetchCurrencies.isFetching}>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={currenciesList}
|
||||
loading={fetchCurrencies.isFetching}
|
||||
onFetchData={handleDataTableFetchData()}
|
||||
loading={currenciesLoading && !initialMount}
|
||||
selectionColumn={false}
|
||||
manualSortBy={true}
|
||||
expandable={false}
|
||||
/>
|
||||
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'}/>}
|
||||
confirmButtonText={<T id={'move_to_trash'}/>}
|
||||
icon='trash'
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={<T id={'delete'} />}
|
||||
icon="trash"
|
||||
intent={Intent.DANGER}
|
||||
isOpen={deleteCurrencyState}
|
||||
onCancel={handleCancelCurrencyDelete}
|
||||
onConfirm={handleConfirmCurrencyDelete}
|
||||
>
|
||||
<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.
|
||||
<FormattedHTMLMessage
|
||||
id={'once_delete_this_currency_you_will_able_to_restore_it'}
|
||||
/>
|
||||
</p>
|
||||
</Alert>
|
||||
</LoadingIndicator>
|
||||
@@ -152,10 +184,10 @@ function CurrenciesList({
|
||||
}
|
||||
|
||||
export default compose(
|
||||
DialogConnect,
|
||||
withDashboard,
|
||||
withCurrencies(({ currenciesList }) => ({
|
||||
currenciesList,
|
||||
})),
|
||||
withCurrenciesActions,
|
||||
DialogConnect,
|
||||
withDashboard
|
||||
)(CurrenciesList);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState} from 'react';
|
||||
import React, { useState, useCallback, useEffect } from 'react';
|
||||
import { useFormik } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import {
|
||||
@@ -8,81 +8,153 @@ import {
|
||||
Intent,
|
||||
MenuItem,
|
||||
Classes,
|
||||
Spinner,
|
||||
} from '@blueprintjs/core';
|
||||
import classNames from 'classnames';
|
||||
import { TimezonePicker } from '@blueprintjs/timezone';
|
||||
import { Select } from '@blueprintjs/select';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useQuery, queryCache } from 'react-query';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import moment from 'moment';
|
||||
|
||||
import { compose, optionsMapToArray } from 'utils';
|
||||
|
||||
import ErrorMessage from 'components/ErrorMessage';
|
||||
import AppToaster from 'components/AppToaster';
|
||||
import { ListSelect } from 'components';
|
||||
import { If } from 'components';
|
||||
|
||||
import withDashboard from 'containers/Dashboard/withDashboard';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withSettingsActions from 'containers/Settings/withSettingsActions';
|
||||
|
||||
|
||||
function GeneralPreferences({
|
||||
// #withSettings
|
||||
organizationSettings,
|
||||
|
||||
//# withDashboard
|
||||
changePreferencesPageTitle,
|
||||
|
||||
// #withSettingsActions
|
||||
requestSubmitOptions,
|
||||
requestFetchOptions,
|
||||
}) {
|
||||
const {formatMessage} = useIntl();
|
||||
const { formatMessage } = useIntl();
|
||||
const [selectedItems, setSelectedItems] = useState({});
|
||||
const [timeZone, setTimeZone] = useState('');
|
||||
|
||||
const fetchHook = useQuery(['settings'],
|
||||
() => { requestFetchOptions(); });
|
||||
const fetchHook = useQuery(
|
||||
['settings'],
|
||||
() => {
|
||||
requestFetchOptions();
|
||||
},
|
||||
{ manual: true },
|
||||
);
|
||||
|
||||
const businessLocation = [
|
||||
{ id: 218, name: 'LIBYA', code: 'LY' },
|
||||
{ id: 380, name: 'UKRAINE', code: 'UA' },
|
||||
{ id: 212, name: 'Morocco', code: 'MA' },
|
||||
];
|
||||
useEffect(() => {
|
||||
changePreferencesPageTitle(formatMessage({ id: 'general' }));
|
||||
}, [changePreferencesPageTitle, formatMessage]);
|
||||
|
||||
const businessLocation = [{ id: 218, name: 'LIBYA', value: 'libya' }];
|
||||
const languagesDisplay = [
|
||||
{ id: 0, name: 'EN', label: 'English' },
|
||||
{ id: 1, name: 'Arb', label: 'Arabic' },
|
||||
{ id: 0, name: 'English', value: 'EN' },
|
||||
{ id: 1, name: 'Arabic', value: 'Arab ' },
|
||||
];
|
||||
const currencies = [
|
||||
{ id: 0, name: 'US Dollar', code: 'USD' },
|
||||
{ id: 1, name: 'Euro', code: 'EUR' },
|
||||
{ id: 2, name: 'Libyan Dinar ', code: 'LYD' },
|
||||
{ id: 0, name: 'US Dollar', value: 'USD' },
|
||||
{ id: 1, name: 'Euro', value: 'EUR' },
|
||||
{ id: 1, name: 'Libyan Dinar ', value: 'LYD' },
|
||||
];
|
||||
|
||||
const fiscalYear = [
|
||||
{ id: 0, name: 'January-July', label: 'January-July' },
|
||||
{ id: 1, name: 'August-December', label: 'August-December' },
|
||||
{ id: 0, name: 'January - December', value: 'january' },
|
||||
{ id: 1, name: 'February - January', value: 'february' },
|
||||
{ id: 2, name: 'March - February', value: 'March' },
|
||||
{ id: 3, name: 'April - March', value: 'april' },
|
||||
{ id: 4, name: 'May - April', value: 'may' },
|
||||
{ id: 5, name: 'June - May', value: 'june' },
|
||||
{ id: 6, name: 'July - June', value: 'july' },
|
||||
{ id: 7, name: 'August - July', value: 'August' },
|
||||
{ id: 8, name: 'September - August', value: 'september' },
|
||||
{ id: 9, name: 'October - September', value: 'october' },
|
||||
{ id: 10, name: 'November - October', value: 'november' },
|
||||
{ id: 11, name: 'December - November', value: 'December' },
|
||||
];
|
||||
|
||||
const dateFormat = [
|
||||
{ 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' },
|
||||
{
|
||||
id: 1,
|
||||
name: 'MM/DD/YY',
|
||||
label: `${moment().format('MM/DD/YYYY')}`,
|
||||
value: 'mm/dd/yy',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'DD/MM/YY',
|
||||
label: `${moment().format('DD/MM/YYYY')}`,
|
||||
value: 'dd/mm/yy',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'YY/MM/DD',
|
||||
label: `${moment().format('YYYY/MM/DD')}`,
|
||||
value: 'yy/mm/dd',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'MM-DD-YY',
|
||||
label: `${moment().format('MM-DD-YYYY')}`,
|
||||
value: 'mm-dd-yy',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'DD-MM-YY',
|
||||
label: `${moment().format('DD-MM-YYYY')}`,
|
||||
value: 'dd-mm-yy',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'YY-MM-DD',
|
||||
label: `${moment().format('YYYY-MM-DD')}`,
|
||||
value: 'yy-mm-dd',
|
||||
},
|
||||
];
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
name: Yup.string().required().label(formatMessage({id:'organization_name_'})),
|
||||
industry: Yup.string().required().label(formatMessage({id:'organization_industry_'})),
|
||||
location: Yup.string().required().label(formatMessage({id:'location'})),
|
||||
base_currency: Yup.string().required(
|
||||
formatMessage({ id: 'required' })
|
||||
),
|
||||
fiscal_year: Yup.string().required().label(formatMessage({id:'base_currency_'})),
|
||||
language: Yup.string().required().label(formatMessage({id:'language'})),
|
||||
// time_zone: Yup.object().required()..label(formatMessage({id:''})),
|
||||
date_format: Yup.date().required().label(formatMessage({id:'date_format_'})),
|
||||
name: Yup.string()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'organization_name_' })),
|
||||
industry: Yup.string()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'organization_industry_' })),
|
||||
location: Yup.string()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'location' })),
|
||||
base_currency: Yup.string().required(formatMessage({ id: 'required' })),
|
||||
fiscal_year: Yup.string()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'base_currency_' })),
|
||||
language: Yup.string()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'language' })),
|
||||
// time_zone: Yup.string()
|
||||
// .required()
|
||||
// .label(formatMessage({ id: 'time_zone' })),
|
||||
date_format: Yup.string()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'date_format_' })),
|
||||
});
|
||||
|
||||
const query = queryCache.refetchQueries('settings');
|
||||
|
||||
const {
|
||||
values,
|
||||
errors,
|
||||
touched,
|
||||
setFieldValue,
|
||||
getFieldProps,
|
||||
handleSubmit,
|
||||
resetForm,
|
||||
isSubmitting,
|
||||
} = useFormik({
|
||||
enableReinitialize: true,
|
||||
initialValues: {
|
||||
@@ -93,13 +165,17 @@ function GeneralPreferences({
|
||||
const options = optionsMapToArray(values).map((option) => {
|
||||
return { key: option.key, ...option, group: 'organization' };
|
||||
});
|
||||
|
||||
requestSubmitOptions({ options })
|
||||
.then((response) => {
|
||||
AppToaster.show({
|
||||
message: 'The_Options_has_been_Submit',
|
||||
message: formatMessage({
|
||||
id: 'the_options_has_been_successfully_created',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
setSubmitting(false);
|
||||
resetForm();
|
||||
queryCache.refetchQueries('settings', { force: true });
|
||||
})
|
||||
.catch((error) => {
|
||||
setSubmitting(false);
|
||||
@@ -112,7 +188,6 @@ function GeneralPreferences({
|
||||
className={'preferences-menu'}
|
||||
key={item.id}
|
||||
text={item.name}
|
||||
label={item.code}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
);
|
||||
@@ -122,7 +197,7 @@ function GeneralPreferences({
|
||||
className={'preferences-menu'}
|
||||
key={item.id}
|
||||
text={item.name}
|
||||
label={item.code}
|
||||
label={item.value}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
);
|
||||
@@ -140,7 +215,6 @@ function GeneralPreferences({
|
||||
className={'preferences-menu'}
|
||||
key={item.id}
|
||||
text={item.name}
|
||||
label={item.label}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
);
|
||||
@@ -149,8 +223,8 @@ function GeneralPreferences({
|
||||
<MenuItem
|
||||
className={'preferences-menu'}
|
||||
key={item.id}
|
||||
text={item.format}
|
||||
label={item.name}
|
||||
text={item.name}
|
||||
label={item.label}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
);
|
||||
@@ -161,218 +235,228 @@ function GeneralPreferences({
|
||||
...selectedItems,
|
||||
[filedName]: filed,
|
||||
});
|
||||
setFieldValue(filedName, filed.name);
|
||||
setFieldValue(filedName, filed.value);
|
||||
};
|
||||
};
|
||||
|
||||
const getSelectedItemLabel = (filedName, defaultLabel) => {
|
||||
return typeof selectedItems[filedName] !== 'undefined'
|
||||
? selectedItems[filedName].name
|
||||
: defaultLabel;
|
||||
const filterItems = (query, item, _index, exactMatch) => {
|
||||
const normalizedTitle = item.name.toLowerCase();
|
||||
const normalizedQuery = query.toLowerCase();
|
||||
|
||||
if (exactMatch) {
|
||||
return normalizedTitle === normalizedQuery;
|
||||
} else {
|
||||
return normalizedTitle.indexOf(normalizedQuery) >= 0;
|
||||
}
|
||||
};
|
||||
|
||||
const handleTimezoneChange = (timezone) => setTimeZone(timezone);
|
||||
|
||||
return (
|
||||
<div className='preferences__inside-content--general'>
|
||||
<div
|
||||
className={classNames({
|
||||
'preferences__inside-content--general': true,
|
||||
preferences__loading: fetchHook.pending,
|
||||
})}
|
||||
>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<FormGroup
|
||||
label={<T id={'organization_name'}/>}
|
||||
label={<T id={'organization_name'} />}
|
||||
inline={true}
|
||||
intent={(errors.name && touched.name) && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='name' {...{errors, touched}} />}
|
||||
intent={errors.name && touched.name && Intent.DANGER}
|
||||
helperText={<ErrorMessage name="name" {...{ errors, touched }} />}
|
||||
>
|
||||
<InputGroup
|
||||
medium={'true'}
|
||||
intent={(errors.name && touched.name) && Intent.DANGER}
|
||||
intent={errors.name && touched.name && Intent.DANGER}
|
||||
{...getFieldProps('name')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={<T id={'organization_industry'}/>}
|
||||
label={<T id={'organization_industry'} />}
|
||||
inline={true}
|
||||
intent={(errors.industry && touched.industry) && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='industry' {...{errors, touched}} />}
|
||||
intent={errors.industry && touched.industry && Intent.DANGER}
|
||||
helperText={<ErrorMessage name="industry" {...{ errors, touched }} />}
|
||||
>
|
||||
<InputGroup
|
||||
medium={'true'}
|
||||
intent={(errors.industry && touched.industry) && Intent.DANGER}
|
||||
intent={errors.industry && touched.industry && Intent.DANGER}
|
||||
{...getFieldProps('industry')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={<T id={'business_location'}/>}
|
||||
label={<T id={'business_location'} />}
|
||||
className={classNames(
|
||||
'form-group--business-location',
|
||||
'form-group--select-list',
|
||||
Classes.FILL
|
||||
Classes.FILL,
|
||||
)}
|
||||
inline={true}
|
||||
helperText={<ErrorMessage name='location' {...{errors, touched}} />}
|
||||
intent={(errors.location && touched.location) && Intent.DANGER}
|
||||
helperText={<ErrorMessage name="location" {...{ errors, touched }} />}
|
||||
intent={errors.location && touched.location && Intent.DANGER}
|
||||
>
|
||||
<Select
|
||||
<ListSelect
|
||||
items={businessLocation}
|
||||
noResults={<MenuItem disabled={true} text='No result.' />}
|
||||
noResults={<MenuItem disabled={true} text="No result." />}
|
||||
itemRenderer={businessLocationItem}
|
||||
popoverProps={{ minimal: true }}
|
||||
onItemSelect={onItemsSelect('location')}
|
||||
>
|
||||
<Button
|
||||
fill={true}
|
||||
rightIcon='caret-down'
|
||||
text={getSelectedItemLabel(
|
||||
'location',
|
||||
organizationSettings.location
|
||||
)}
|
||||
/>
|
||||
</Select>
|
||||
selectedItem={values.location}
|
||||
selectedItemProp={'value'}
|
||||
defaultText={<T id={'select_business_location'} />}
|
||||
labelProp={'name'}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={<T id={'base_currency'}/>}
|
||||
label={<T id={'base_currency'} />}
|
||||
className={classNames(
|
||||
'form-group--base-currency',
|
||||
'form-group--select-list',
|
||||
Classes.FILL
|
||||
Classes.LOADING,
|
||||
Classes.FILL,
|
||||
)}
|
||||
inline={true}
|
||||
helperText={<ErrorMessage name='base_currency' {...{ errors, touched }} />}
|
||||
intent={(errors.base_currency && touched.base_currency) && Intent.DANGER}
|
||||
helperText={
|
||||
<ErrorMessage name="base_currency" {...{ errors, touched }} />
|
||||
}
|
||||
intent={
|
||||
errors.base_currency && touched.base_currency && Intent.DANGER
|
||||
}
|
||||
>
|
||||
<Select
|
||||
<ListSelect
|
||||
items={currencies}
|
||||
noResults={<MenuItem disabled={true} text='No result.' />}
|
||||
noResults={<MenuItem disabled={true} text="No result." />}
|
||||
itemRenderer={currencyItem}
|
||||
popoverProps={{ minimal: true }}
|
||||
onItemSelect={onItemsSelect('base_currency')}
|
||||
>
|
||||
<Button
|
||||
fill={true}
|
||||
rightIcon='caret-down'
|
||||
text={getSelectedItemLabel(
|
||||
'base_currency',
|
||||
organizationSettings.base_currency
|
||||
)}
|
||||
/>
|
||||
</Select>
|
||||
itemPredicate={filterItems}
|
||||
selectedItem={values.base_currency}
|
||||
selectedItemProp={'value'}
|
||||
defaultText={<T id={'select_base_currency'} />}
|
||||
labelProp={'name'}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={<T id={'fiscal_year'}/>}
|
||||
label={<T id={'fiscal_year'} />}
|
||||
className={classNames(
|
||||
'form-group--fiscal-year',
|
||||
'form-group--select-list',
|
||||
Classes.FILL
|
||||
Classes.FILL,
|
||||
)}
|
||||
inline={true}
|
||||
helperText={<ErrorMessage name='fiscal_year' {...{errors, touched}} />}
|
||||
intent={(errors.fiscal_year && touched.fiscal_year) && Intent.DANGER}
|
||||
helperText={
|
||||
<ErrorMessage name="fiscal_year" {...{ errors, touched }} />
|
||||
}
|
||||
intent={errors.fiscal_year && touched.fiscal_year && Intent.DANGER}
|
||||
>
|
||||
<Select
|
||||
<ListSelect
|
||||
items={fiscalYear}
|
||||
noResults={<MenuItem disabled={true} text='No result.' />}
|
||||
noResults={<MenuItem disabled={true} text="No result." />}
|
||||
itemRenderer={fiscalYearItem}
|
||||
popoverProps={{ minimal: true }}
|
||||
onItemSelect={onItemsSelect('fiscal_year')}
|
||||
>
|
||||
<Button
|
||||
fill={true}
|
||||
rightIcon='caret-down'
|
||||
text={getSelectedItemLabel(
|
||||
'fiscal_year',
|
||||
organizationSettings.fiscal_year
|
||||
)}
|
||||
/>
|
||||
</Select>
|
||||
itemPredicate={filterItems}
|
||||
selectedItem={values.fiscal_year}
|
||||
selectedItemProp={'value'}
|
||||
defaultText={<T id={'select_fiscal_year'} />}
|
||||
labelProp={'name'}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup
|
||||
label={<T id={'language'}/>}
|
||||
label={<T id={'language'} />}
|
||||
inline={true}
|
||||
className={classNames(
|
||||
'form-group--language',
|
||||
'form-group--select-list',
|
||||
Classes.FILL
|
||||
Classes.FILL,
|
||||
)}
|
||||
intent={(errors.language && touched.language) && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='language' {...{errors, touched}} />}
|
||||
intent={errors.language && touched.language && Intent.DANGER}
|
||||
helperText={<ErrorMessage name="language" {...{ errors, touched }} />}
|
||||
>
|
||||
<Select
|
||||
<ListSelect
|
||||
items={languagesDisplay}
|
||||
noResults={<MenuItem disabled={true} text='No results.' />}
|
||||
noResults={<MenuItem disabled={true} text="No results." />}
|
||||
itemRenderer={languageItem}
|
||||
popoverProps={{ minimal: true }}
|
||||
onItemSelect={onItemsSelect('language')}
|
||||
>
|
||||
<Button
|
||||
rightIcon='caret-down'
|
||||
text={getSelectedItemLabel(
|
||||
'language',
|
||||
organizationSettings.language
|
||||
)}
|
||||
/>
|
||||
</Select>
|
||||
itemPredicate={filterItems}
|
||||
selectedItem={values.language}
|
||||
selectedItemProp={'value'}
|
||||
defaultText={<T id={'select_language'} />}
|
||||
labelProp={'name'}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={<T id={'time_zone'}/>}
|
||||
label={<T id={'time_zone'} />}
|
||||
inline={true}
|
||||
className={classNames(
|
||||
'form-group--time-zone',
|
||||
'form-group--select-list',
|
||||
Classes.FILL
|
||||
Classes.FILL,
|
||||
)}
|
||||
intent={(errors.time_zone && touched.time_zone) && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='time_zone' {...{errors, touched}} />}
|
||||
intent={errors.time_zone && touched.time_zone && Intent.DANGER}
|
||||
helperText={
|
||||
<ErrorMessage name="time_zone" {...{ errors, touched }} />
|
||||
}
|
||||
>
|
||||
<TimezonePicker
|
||||
value={timeZone}
|
||||
onChange={handleTimezoneChange}
|
||||
showLocalTimezone={true}
|
||||
valueDisplayFormat='composite'
|
||||
valueDisplayFormat="composite"
|
||||
placeholder={<T id={'select_time_zone'} />}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={<T id={'date_format'}/>}
|
||||
label={<T id={'date_format'} />}
|
||||
inline={true}
|
||||
className={classNames(
|
||||
'form-group--language',
|
||||
'form-group--select-list',
|
||||
Classes.FILL
|
||||
Classes.FILL,
|
||||
)}
|
||||
intent={(errors.date_format && touched.date_format) && Intent.DANGER}
|
||||
helperText={<ErrorMessage name='date_format' {...{errors, touched}} />}
|
||||
intent={errors.date_format && touched.date_format && Intent.DANGER}
|
||||
helperText={
|
||||
<ErrorMessage name="date_format" {...{ errors, touched }} />
|
||||
}
|
||||
>
|
||||
<Select
|
||||
<ListSelect
|
||||
items={dateFormat}
|
||||
noResults={<MenuItem disabled={true} text='No result.' />}
|
||||
noResults={<MenuItem disabled={true} text="No result." />}
|
||||
itemRenderer={date_format}
|
||||
popoverProp={{ minimal: true }}
|
||||
onItemSelect={onItemsSelect('date_format')}
|
||||
>
|
||||
<Button
|
||||
rightIcon='caret-down'
|
||||
text={getSelectedItemLabel(
|
||||
'date_format',
|
||||
organizationSettings.date_format
|
||||
)}
|
||||
/>
|
||||
</Select>
|
||||
itemPredicate={filterItems}
|
||||
selectedItem={values.date_format}
|
||||
selectedItemProp={'value'}
|
||||
defaultText={<T id={'select_date_format'} />}
|
||||
labelProp={'name'}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<div className={'preferences__floating-footer '}>
|
||||
<Button
|
||||
className={'preferences-button'}
|
||||
intent={Intent.PRIMARY}
|
||||
type='submit'
|
||||
type="submit"
|
||||
loading={isSubmitting}
|
||||
>
|
||||
<T id={'save'}/>
|
||||
<T id={'save'} />
|
||||
</Button>
|
||||
<Button onClick={'handleClose'}>
|
||||
<T id={'close'} />
|
||||
</Button>
|
||||
<Button onClick={'handleClose'}><T id={'close'}/></Button>
|
||||
</div>
|
||||
</form>
|
||||
<If condition={fetchHook.isFetching || isSubmitting}>
|
||||
<div className={'preferences__loading-overlay'}>
|
||||
<Spinner size={40} />
|
||||
</div>
|
||||
</If>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -380,4 +464,5 @@ function GeneralPreferences({
|
||||
export default compose(
|
||||
withSettings,
|
||||
withSettingsActions,
|
||||
withDashboard,
|
||||
)(GeneralPreferences);
|
||||
|
||||
@@ -16,7 +16,7 @@ function UsersActions({
|
||||
}, [openDialog]);
|
||||
|
||||
return (
|
||||
<div claass="preferences-actions">
|
||||
<div className="preferences-actions">
|
||||
<Button
|
||||
icon={<Icon icon='plus' iconSize={12} />}
|
||||
onClick={onClickNewUser}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useMemo, useCallback } from 'react';
|
||||
import React, { useState, useMemo, useCallback, useEffect } from 'react';
|
||||
import { queryCache, useQuery } from 'react-query';
|
||||
import DataTable from 'components/DataTable';
|
||||
import {
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
|
||||
import Icon from 'components/Icon';
|
||||
import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import { If } from 'components';
|
||||
|
||||
import AppToaster from 'components/AppToaster';
|
||||
|
||||
@@ -34,7 +35,7 @@ import { compose } from 'utils';
|
||||
function UsersListPreferences({
|
||||
// #withDialog
|
||||
openDialog,
|
||||
closeDialog,
|
||||
changePreferencesPageTitle,
|
||||
|
||||
// #withUsers
|
||||
usersList,
|
||||
@@ -52,9 +53,14 @@ function UsersListPreferences({
|
||||
const { formatMessage } = useIntl();
|
||||
const fetchUsers = useQuery('users-table', () => requestFetchUsers());
|
||||
|
||||
const onInactiveUser = (user) => {
|
||||
useEffect(() => {
|
||||
changePreferencesPageTitle(formatMessage({ id: 'users' }));
|
||||
}, [changePreferencesPageTitle, formatMessage]);
|
||||
|
||||
|
||||
const onInactiveUser = useCallback((user) => {
|
||||
setInactiveUserState(user);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Handle cancel inactive user alert
|
||||
const handleCancelInactiveUser = useCallback(() => {
|
||||
@@ -63,38 +69,42 @@ function UsersListPreferences({
|
||||
|
||||
// handel confirm user activation
|
||||
const handleConfirmUserActive = useCallback(() => {
|
||||
requestInactiveUser(inactiveUserState.id).then(() => {
|
||||
setInactiveUserState(false);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_user_has_been_successfully_inactivated',
|
||||
}),
|
||||
requestInactiveUser(inactiveUserState.id)
|
||||
.then(() => {
|
||||
setInactiveUserState(false);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_user_has_been_successfully_inactivated',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.refetchQueries('users-table', { force: true });
|
||||
})
|
||||
.catch((error) => {
|
||||
setInactiveUserState(false);
|
||||
});
|
||||
});
|
||||
}, [
|
||||
inactiveUserState,
|
||||
requestInactiveUser,
|
||||
requestFetchUsers,
|
||||
formatMessage,
|
||||
]);
|
||||
}, [inactiveUserState, requestInactiveUser, formatMessage]);
|
||||
|
||||
const onDeleteUser = (user) => {
|
||||
const onDeleteUser = useCallback((user) => {
|
||||
setDeleteUserState(user);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleCancelUserDelete = () => {
|
||||
setDeleteUserState(false);
|
||||
};
|
||||
|
||||
const onEditUser = (user) => () => {
|
||||
const form = Object.keys(user).reduce((obj, key) => {
|
||||
const camelKey = snakeCase(key);
|
||||
obj[camelKey] = user[key];
|
||||
return obj;
|
||||
}, {});
|
||||
const onEditUser = useCallback(
|
||||
(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 });
|
||||
};
|
||||
openDialog('userList-form', { action: 'edit', user: form });
|
||||
},
|
||||
[openDialog],
|
||||
);
|
||||
|
||||
// Handle confirm User delete
|
||||
|
||||
@@ -121,19 +131,24 @@ function UsersListPreferences({
|
||||
const actionMenuList = useCallback(
|
||||
(user) => (
|
||||
<Menu>
|
||||
<MenuItem text={<T id={'edit_user'} />} onClick={onEditUser(user)} />
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
text={<T id={'inactivate_user'} />}
|
||||
onClick={() => onInactiveUser(user)}
|
||||
/>
|
||||
<If condition={user.invite_accepted_at}>
|
||||
<MenuItem text={<T id={'edit_user'} />} onClick={onEditUser(user)} />
|
||||
<MenuDivider />
|
||||
|
||||
<MenuItem
|
||||
text={<T id={'inactivate_user'} />}
|
||||
onClick={() => onInactiveUser(user)}
|
||||
/>
|
||||
</If>
|
||||
|
||||
<MenuItem
|
||||
text={<T id={'delete_user'} />}
|
||||
onClick={() => onDeleteUser(user)}
|
||||
intent={Intent.DANGER}
|
||||
/>
|
||||
</Menu>
|
||||
),
|
||||
[],
|
||||
[onInactiveUser, onDeleteUser, onEditUser],
|
||||
);
|
||||
|
||||
const columns = useMemo(
|
||||
@@ -160,7 +175,11 @@ function UsersListPreferences({
|
||||
id: 'status',
|
||||
Header: 'Status',
|
||||
accessor: (user) =>
|
||||
user.active ? (
|
||||
!user.invite_accepted_at ? (
|
||||
<Tag minimal={true}>
|
||||
<T id={'inviting'} />
|
||||
</Tag>
|
||||
) : user.active ? (
|
||||
<Tag intent={Intent.SUCCESS} minimal={true}>
|
||||
<T id={'activate'} />
|
||||
</Tag>
|
||||
@@ -193,7 +212,7 @@ function UsersListPreferences({
|
||||
|
||||
const handelDataTableFetchData = useCallback(() => {
|
||||
onFetchData && onFetchData();
|
||||
}, []);
|
||||
}, [onFetchData]);
|
||||
|
||||
return (
|
||||
<LoadingIndicator>
|
||||
|
||||
Reference in New Issue
Block a user