mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 06:40:31 +00:00
WIP optimize connect with redux state in preferences pages.
This commit is contained in:
@@ -13,6 +13,7 @@ import classnames from 'classnames';
|
|||||||
import { FixedSizeList } from 'react-window'
|
import { FixedSizeList } from 'react-window'
|
||||||
import { ConditionalWrapper } from 'utils';
|
import { ConditionalWrapper } from 'utils';
|
||||||
import { useUpdateEffect } from 'hooks';
|
import { useUpdateEffect } from 'hooks';
|
||||||
|
import { If } from 'components';
|
||||||
|
|
||||||
const IndeterminateCheckbox = React.forwardRef(
|
const IndeterminateCheckbox = React.forwardRef(
|
||||||
({ indeterminate, ...rest }, ref) => {
|
({ indeterminate, ...rest }, ref) => {
|
||||||
@@ -257,16 +258,19 @@ export default function DataTable({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div {...getTableBodyProps()} className="tbody">
|
<div {...getTableBodyProps()} className="tbody">
|
||||||
{ !loading && RenderTBody() }
|
<If condition={!loading}>
|
||||||
|
{ RenderTBody() }
|
||||||
{ !loading && (page.length === 0) && (
|
</If>
|
||||||
|
|
||||||
|
<If condition={!loading && (page.length === 0)}>
|
||||||
<div className={'tr no-results'}>
|
<div className={'tr no-results'}>
|
||||||
<div class="td">{ noResults }</div>
|
<div class="td">{ noResults }</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</If>
|
||||||
{ loading && (
|
|
||||||
|
<If condition={loading}>
|
||||||
<div class="loading"><Spinner size={spinnerProps.size} /></div>
|
<div class="loading"><Spinner size={spinnerProps.size} /></div>
|
||||||
) }
|
</If>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import PreferencesTopbar from 'components/Preferences/PreferencesTopbar';
|
import PreferencesTopbar from 'components/Preferences/PreferencesTopbar';
|
||||||
import PreferencesContentRoute from 'components/Preferences/PreferencesContentRoute';
|
import PreferencesContentRoute from 'components/Preferences/PreferencesContentRoute';
|
||||||
|
|
||||||
export default function () {
|
|
||||||
|
export default function PreferencesContent() {
|
||||||
return (
|
return (
|
||||||
<div className='dashboard-content dashboard-content--preferences'>
|
<div className='dashboard-content dashboard-content--preferences'>
|
||||||
<PreferencesTopbar pageTitle={'asdad'} />
|
<PreferencesTopbar pageTitle={'asdad'} />
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import { Route, Switch, Redirect } from 'react-router-dom';
|
import { Route, Switch, Redirect } from 'react-router-dom';
|
||||||
import preferencesRoutes from 'routes/preferences'
|
import preferencesRoutes from 'routes/preferences'
|
||||||
|
|
||||||
|
|
||||||
export default function DashboardContentRoute() {
|
export default function DashboardContentRoute() {
|
||||||
const defaultTab = '/dashboard/preferences/general';
|
const defaultTab = '/dashboard/preferences/general';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PreferencesSidebar from 'components/Preferences/PreferencesSidebar';
|
import PreferencesSidebar from 'components/Preferences/PreferencesSidebar';
|
||||||
|
|
||||||
|
|
||||||
export default function PreferencesPage() {
|
export default function PreferencesPage() {
|
||||||
return (
|
return (
|
||||||
<div class="preferences-page">
|
<div class="preferences-page">
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Route, Switch } from 'react-router-dom';
|
import { Route, Switch } from 'react-router-dom';
|
||||||
import DashboardTopbarUser from 'components/Dashboard/TopbarUser';
|
import DashboardTopbarUser from 'components/Dashboard/TopbarUser';
|
||||||
import UsersActions from 'containers/Preferences/UsersActions';
|
import UsersActions from 'containers/Preferences/Users/UsersActions';
|
||||||
import CurrenciesActions from 'containers/Preferences/CurrenciesActions';
|
import CurrenciesActions from 'containers/Preferences/Currencies/CurrenciesActions';
|
||||||
|
|
||||||
|
|
||||||
export default function PreferencesTopbar() {
|
export default function PreferencesTopbar() {
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import {
|
|
||||||
deleteManualJournal,
|
|
||||||
fetchManualJournalsTable,
|
|
||||||
publishManualJournal,
|
|
||||||
deleteBulkManualJournals,
|
|
||||||
} from 'store/manualJournals/manualJournals.actions';
|
|
||||||
import { getResourceViews } from 'store/customViews/customViews.selectors';
|
|
||||||
import t from 'store/types';
|
|
||||||
import {
|
|
||||||
getManualJournalsItems,
|
|
||||||
} from 'store/manualJournals/manualJournals.selectors'
|
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => ({
|
|
||||||
views: getResourceViews(state, 'manual_journals'),
|
|
||||||
manualJournals: getManualJournalsItems(state, state.manualJournals.currentViewId),
|
|
||||||
manualJournalsItems: state.manualJournals.items,
|
|
||||||
tableQuery: state.manualJournals.tableQuery,
|
|
||||||
manualJournalsLoading: state.manualJournals.loading,
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapActionsToProps = (dispatch) => ({
|
|
||||||
requestDeleteManualJournal: (id) => dispatch(deleteManualJournal({ id })),
|
|
||||||
changeCurrentView: (id) =>
|
|
||||||
dispatch({
|
|
||||||
type: t.MANUAL_JOURNALS_SET_CURRENT_VIEW,
|
|
||||||
currentViewId: parseInt(id, 10),
|
|
||||||
}),
|
|
||||||
addManualJournalsTableQueries: (queries) =>
|
|
||||||
dispatch({
|
|
||||||
type: t.MANUAL_JOURNALS_TABLE_QUERIES_ADD,
|
|
||||||
queries,
|
|
||||||
}),
|
|
||||||
fetchManualJournalsTable: (query = {}) =>
|
|
||||||
dispatch(fetchManualJournalsTable({ query: { ...query } })),
|
|
||||||
|
|
||||||
requestPublishManualJournal: (id) => dispatch(publishManualJournal({ id })),
|
|
||||||
requestDeleteBulkManualJournals: (ids) => dispatch(deleteBulkManualJournals({ ids })),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapActionsToProps);
|
|
||||||
13
client/src/containers/Currencies/withCurrencies.js
Normal file
13
client/src/containers/Currencies/withCurrencies.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
export default (mapState) => {
|
||||||
|
const mapStateToProps = (state, props) => {
|
||||||
|
const mapped = {
|
||||||
|
currencies: state.currencies.data,
|
||||||
|
currenciesList: Object.values(state.currencies.data),
|
||||||
|
};
|
||||||
|
return mapState ? mapState(mapped, state, props) : mapped;
|
||||||
|
};
|
||||||
|
|
||||||
|
return connect(mapStateToProps);
|
||||||
|
}
|
||||||
17
client/src/containers/Currencies/withCurrenciesActions.js
Normal file
17
client/src/containers/Currencies/withCurrenciesActions.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
import {
|
||||||
|
fetchCurrencies,
|
||||||
|
submitCurrencies,
|
||||||
|
deleteCurrency,
|
||||||
|
editCurrency,
|
||||||
|
} from 'store/currencies/currencies.actions';
|
||||||
|
|
||||||
|
|
||||||
|
export const mapDispatchToProps = (dispatch) => ({
|
||||||
|
requestFetchCurrencies: () => dispatch(fetchCurrencies({})),
|
||||||
|
requestSubmitCurrencies: (form) => dispatch(submitCurrencies({ form })),
|
||||||
|
requestEditCurrency: (id, form) => dispatch(editCurrency({ id, form })),
|
||||||
|
requestDeleteCurrency: (currency_code) => dispatch(deleteCurrency({ currency_code })),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(null, mapDispatchToProps);
|
||||||
16
client/src/containers/Currencies/withCurrency.js
Normal file
16
client/src/containers/Currencies/withCurrency.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
import {
|
||||||
|
getCurrencyById,
|
||||||
|
getCurrencyByCode,
|
||||||
|
} from 'store/currencies/currencies.selector';
|
||||||
|
|
||||||
|
|
||||||
|
const mapStateToProps = (state, props) => ({
|
||||||
|
...(props.currencyId) ? {
|
||||||
|
currency: getCurrencyById(state.currencies.data, props.currencyId),
|
||||||
|
} : (props.currencyCode) ? {
|
||||||
|
currency: getCurrencyByCode(state.currencies.data, props.currencyCode),
|
||||||
|
} : {},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useMemo, useCallback } from 'react';
|
import React, { useMemo, useCallback } from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Classes,
|
Classes,
|
||||||
@@ -9,26 +9,40 @@ import {
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { useFormik } from 'formik';
|
import { useFormik } from 'formik';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
import Dialog from 'components/Dialog';
|
import Dialog from 'components/Dialog';
|
||||||
import useAsync from 'hooks/async';
|
|
||||||
import AppToaster from 'components/AppToaster';
|
import AppToaster from 'components/AppToaster';
|
||||||
import DialogConnect from 'connectors/Dialog.connector';
|
import DialogConnect from 'connectors/Dialog.connector';
|
||||||
import DialogReduxConnect from 'components/DialogReduxConnect';
|
import DialogReduxConnect from 'components/DialogReduxConnect';
|
||||||
import CurrencyFromDialogConnect from 'connectors/CurrencyFromDialog.connect';
|
import withCurrency from 'containers/Currencies/withCurrency';
|
||||||
|
import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions';
|
||||||
|
|
||||||
import ErrorMessage from 'components/ErrorMessage';
|
import ErrorMessage from 'components/ErrorMessage';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
|
import { getDialogPayload } from 'store/dashboard/dashboard.reducer';
|
||||||
|
|
||||||
|
|
||||||
function CurrencyDialog({
|
function CurrencyDialog({
|
||||||
name,
|
name,
|
||||||
payload,
|
payload,
|
||||||
isOpen,
|
isOpen,
|
||||||
|
|
||||||
|
// #withDialog
|
||||||
closeDialog,
|
closeDialog,
|
||||||
|
|
||||||
|
// #withCurrency
|
||||||
|
currencyCode,
|
||||||
|
currency,
|
||||||
|
|
||||||
|
// #wihtCurrenciesActions
|
||||||
requestFetchCurrencies,
|
requestFetchCurrencies,
|
||||||
requestSubmitCurrencies,
|
requestSubmitCurrencies,
|
||||||
requestEditCurrency,
|
requestEditCurrency,
|
||||||
editCurrency,
|
|
||||||
}) {
|
}) {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
@@ -40,70 +54,72 @@ function CurrencyDialog({
|
|||||||
.max(4)
|
.max(4)
|
||||||
.required(intl.formatMessage({ id: 'required' })),
|
.required(intl.formatMessage({ id: 'required' })),
|
||||||
});
|
});
|
||||||
const initialValues = useMemo(
|
const initialValues = useMemo(() => ({
|
||||||
() => ({
|
currency_name: '',
|
||||||
currency_name: '',
|
currency_code: '',
|
||||||
currency_code: '',
|
}), []);
|
||||||
}),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const formik = useFormik({
|
const {
|
||||||
|
values,
|
||||||
|
errors,
|
||||||
|
touched,
|
||||||
|
setFieldValue,
|
||||||
|
getFieldProps,
|
||||||
|
isSubmitting,
|
||||||
|
handleSubmit,
|
||||||
|
resetForm,
|
||||||
|
} = useFormik({
|
||||||
enableReinitialize: true,
|
enableReinitialize: true,
|
||||||
|
|
||||||
initialValues: {
|
initialValues: {
|
||||||
...(payload.action === 'edit' &&
|
...(payload.action === 'edit' &&
|
||||||
pick(editCurrency, Object.keys(initialValues))),
|
pick(currency, Object.keys(initialValues))),
|
||||||
},
|
},
|
||||||
|
|
||||||
validationSchema: ValidationSchema,
|
validationSchema: ValidationSchema,
|
||||||
onSubmit: (values, { setSubmitting }) => {
|
onSubmit: (values, { setSubmitting }) => {
|
||||||
if (payload.action === 'edit') {
|
if (payload.action === 'edit') {
|
||||||
requestEditCurrency(editCurrency.id, values)
|
requestEditCurrency(currency.id, values).then((response) => {
|
||||||
.then((response) => {
|
closeDialog(name);
|
||||||
closeDialog(name);
|
AppToaster.show({
|
||||||
AppToaster.show({
|
message: 'the_currency_has_been_edited',
|
||||||
message: 'the_currency_has_been_edited',
|
intent: Intent.SUCCESS,
|
||||||
});
|
|
||||||
setSubmitting(false);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setSubmitting(false);
|
|
||||||
});
|
});
|
||||||
|
setSubmitting(false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setSubmitting(false);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
requestSubmitCurrencies(values)
|
requestSubmitCurrencies(values).then((response) => {
|
||||||
.then((response) => {
|
closeDialog(name);
|
||||||
closeDialog(name);
|
AppToaster.show({
|
||||||
AppToaster.show({
|
message: 'the_currency_has_been_submit',
|
||||||
message: 'the_currency_has_been_submit',
|
intent: Intent.SUCCESS,
|
||||||
});
|
|
||||||
setSubmitting(false);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setSubmitting(false);
|
|
||||||
});
|
});
|
||||||
|
setSubmitting(false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setSubmitting(false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { values, errors, touched } = useMemo(() => formik, [formik]);
|
|
||||||
|
|
||||||
const handleClose = useCallback(() => {
|
const handleClose = useCallback(() => {
|
||||||
closeDialog(name);
|
closeDialog(name);
|
||||||
}, [name, closeDialog]);
|
}, [name, closeDialog]);
|
||||||
|
|
||||||
const fetchHook = useAsync(async () => {
|
const fetchCurrencies = useQuery('currencies',
|
||||||
await Promise.all([requestFetchCurrencies()]);
|
() => { requestFetchCurrencies(); },
|
||||||
});
|
{ manual: true });
|
||||||
|
|
||||||
const onDialogOpening = useCallback(() => {
|
const onDialogOpening = useCallback(() => {
|
||||||
fetchHook.execute();
|
fetchCurrencies.refetch();
|
||||||
}, [fetchHook]);
|
}, [fetchCurrencies]);
|
||||||
|
|
||||||
const onDialogClosed = useCallback(() => {
|
const onDialogClosed = useCallback(() => {
|
||||||
formik.resetForm();
|
resetForm();
|
||||||
closeDialog(name);
|
closeDialog(name);
|
||||||
}, [formik, closeDialog, name]);
|
}, [closeDialog, name]);
|
||||||
|
|
||||||
const requiredSpan = useMemo(() => <span className={'required'}>*</span>, []);
|
const requiredSpan = useMemo(() => <span className={'required'}>*</span>, []);
|
||||||
|
|
||||||
@@ -113,59 +129,53 @@ function CurrencyDialog({
|
|||||||
title={payload.action === 'edit' ? 'Edit Currency' : ' New Currency'}
|
title={payload.action === 'edit' ? 'Edit Currency' : ' New Currency'}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
{
|
{
|
||||||
'dialog--loading': fetchHook.pending,
|
'dialog--loading': fetchCurrencies.isFetching,
|
||||||
},
|
},
|
||||||
'dialog--currency-form'
|
'dialog--currency-form'
|
||||||
)}
|
)}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onClosed={onDialogClosed}
|
onClosed={onDialogClosed}
|
||||||
onOpening={onDialogOpening}
|
onOpening={onDialogOpening}
|
||||||
isLoading={fetchHook.pending}
|
isLoading={fetchCurrencies.isFetching}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
>
|
>
|
||||||
<form onSubmit={formik.handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<div className={Classes.DIALOG_BODY}>
|
<div className={Classes.DIALOG_BODY}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={'Currency Name'}
|
label={'Currency Name'}
|
||||||
labelInfo={requiredSpan}
|
labelInfo={requiredSpan}
|
||||||
className={'form-group--currency-name'}
|
className={'form-group--currency-name'}
|
||||||
intent={
|
intent={(errors.currency_name && touched.currency_name) && Intent.DANGER}
|
||||||
errors.currency_name && touched.currency_name && Intent.DANGER
|
helperText={<ErrorMessage name='currency_name' {...{errors, touched}} />}
|
||||||
}
|
|
||||||
helperText={<ErrorMessage name='currency_name' {...formik} />}
|
|
||||||
inline={true}
|
inline={true}
|
||||||
>
|
>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
medium={true}
|
medium={true}
|
||||||
intent={
|
intent={(errors.currency_name && touched.currency_name) && Intent.DANGER}
|
||||||
errors.currency_name && touched.currency_name && Intent.DANGER
|
{...getFieldProps('currency_name')}
|
||||||
}
|
|
||||||
{...formik.getFieldProps('currency_name')}
|
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={'Currency Code'}
|
label={'Currency Code'}
|
||||||
labelInfo={requiredSpan}
|
labelInfo={requiredSpan}
|
||||||
className={'form-group--currency-code'}
|
className={'form-group--currency-code'}
|
||||||
intent={
|
intent={(errors.currency_code && touched.currency_code) && Intent.DANGER}
|
||||||
errors.currency_code && touched.currency_code && Intent.DANGER
|
helperText={<ErrorMessage name='currency_code' {...{errors, touched}} />}
|
||||||
}
|
|
||||||
helperText={<ErrorMessage name='currency_code' {...formik} />}
|
|
||||||
inline={true}
|
inline={true}
|
||||||
>
|
>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
medium={true}
|
medium={true}
|
||||||
intent={
|
intent={(errors.currency_code && touched.currency_code) && Intent.DANGER}
|
||||||
errors.currency_code && touched.currency_code && Intent.DANGER
|
{...getFieldProps('currency_code')}
|
||||||
}
|
|
||||||
{...formik.getFieldProps('currency_code')}
|
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={Classes.DIALOG_FOOTER}>
|
<div className={Classes.DIALOG_FOOTER}>
|
||||||
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||||
<Button onClick={handleClose}>Close</Button>
|
<Button onClick={handleClose}>Close</Button>
|
||||||
<Button intent={Intent.PRIMARY} type='submit'>
|
<Button intent={Intent.PRIMARY} type='submit' disabled={isSubmitting}>
|
||||||
{payload.action === 'edit' ? 'Edit' : 'Submit'}
|
{payload.action === 'edit' ? 'Edit' : 'Submit'}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -175,8 +185,22 @@ function CurrencyDialog({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state, props) => {
|
||||||
|
const dialogPayload = getDialogPayload(state, 'currency-form');
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: 'currency-form',
|
||||||
|
payload: { action: 'new', currencyCode: null, ...dialogPayload },
|
||||||
|
currencyCode: dialogPayload?.currencyCode || null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const withCurrencyFormDialog = connect(mapStateToProps);
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
CurrencyFromDialogConnect,
|
withCurrencyFormDialog,
|
||||||
DialogConnect,
|
DialogConnect,
|
||||||
DialogReduxConnect
|
DialogReduxConnect,
|
||||||
|
withCurrenciesActions,
|
||||||
|
withCurrency,
|
||||||
)(CurrencyDialog);
|
)(CurrencyDialog);
|
||||||
|
|||||||
@@ -4,41 +4,53 @@ import {
|
|||||||
Popover,
|
Popover,
|
||||||
Menu,
|
Menu,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
MenuDivider,
|
|
||||||
Position,
|
Position,
|
||||||
Classes,
|
|
||||||
Tooltip,
|
|
||||||
Alert,
|
Alert,
|
||||||
Intent,
|
Intent,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
|
||||||
import Icon from 'components/Icon';
|
import Icon from 'components/Icon';
|
||||||
import { snakeCase } from 'lodash';
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
import CurrencyFromDialogConnect from 'connectors/CurrencyFromDialog.connect';
|
|
||||||
import DialogConnect from 'connectors/Dialog.connector';
|
import DialogConnect from 'connectors/Dialog.connector';
|
||||||
import DashboardConnect from 'connectors/Dashboard.connector';
|
|
||||||
import LoadingIndicator from 'components/LoadingIndicator';
|
import LoadingIndicator from 'components/LoadingIndicator';
|
||||||
import DataTable from 'components/DataTable';
|
import DataTable from 'components/DataTable';
|
||||||
import AppToaster from 'components/AppToaster';
|
import AppToaster from 'components/AppToaster';
|
||||||
|
|
||||||
|
import withDashboard from 'connectors/Dashboard.connector';
|
||||||
|
import withCurrencies from 'containers/Currencies/withCurrencies';
|
||||||
|
import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions';
|
||||||
|
|
||||||
|
|
||||||
function CurrenciesList({
|
function CurrenciesList({
|
||||||
currencies,
|
// #withCurrencies
|
||||||
|
currenciesList,
|
||||||
|
|
||||||
|
// #withCurrenciesActions
|
||||||
|
requestDeleteCurrency,
|
||||||
|
requestFetchCurrencies,
|
||||||
|
|
||||||
|
// #withDialog
|
||||||
openDialog,
|
openDialog,
|
||||||
onFetchData,
|
onFetchData,
|
||||||
requestDeleteCurrency,
|
|
||||||
}) {
|
}) {
|
||||||
const [deleteCurrencyState, setDeleteCurrencyState] = useState(false);
|
const [deleteCurrencyState, setDeleteCurrencyState] = useState(false);
|
||||||
|
|
||||||
const handleEditCurrency = (currency) => () => {
|
const fetchCurrencies = useQuery(['currencies-table'],
|
||||||
|
() => requestFetchCurrencies());
|
||||||
|
|
||||||
|
const handleEditCurrency = (currency) => {
|
||||||
openDialog('currency-form', {
|
openDialog('currency-form', {
|
||||||
action: 'edit',
|
action: 'edit',
|
||||||
currency_code: currency.currency_code,
|
currencyCode: currency.currency_code,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDeleteCurrency = (currency) => {
|
const onDeleteCurrency = (currency) => {
|
||||||
setDeleteCurrencyState(currency);
|
setDeleteCurrencyState(currency);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancelCurrencyDelete = () => {
|
const handleCancelCurrencyDelete = () => {
|
||||||
setDeleteCurrencyState(false);
|
setDeleteCurrencyState(false);
|
||||||
};
|
};
|
||||||
@@ -54,56 +66,51 @@ function CurrenciesList({
|
|||||||
);
|
);
|
||||||
}, [deleteCurrencyState]);
|
}, [deleteCurrencyState]);
|
||||||
|
|
||||||
const actionMenuList = useCallback(
|
const actionMenuList = useCallback((currency) => (
|
||||||
(currency) => (
|
<Menu>
|
||||||
<Menu>
|
<MenuItem
|
||||||
<MenuItem text='Edit Currency' onClick={handleEditCurrency(currency)} />
|
text='Edit Currency'
|
||||||
|
onClick={() => handleEditCurrency(currency)} />
|
||||||
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text='Delete Currency'
|
text='Delete Currency'
|
||||||
onClick={() => onDeleteCurrency(currency)}
|
onClick={() => onDeleteCurrency(currency)}
|
||||||
/>
|
/>
|
||||||
</Menu>
|
</Menu>
|
||||||
),
|
), []);
|
||||||
[]
|
|
||||||
);
|
const columns = useMemo(() => [
|
||||||
|
{
|
||||||
|
Header: 'Currency Name',
|
||||||
|
accessor: 'currency_name',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: '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]);
|
||||||
|
|
||||||
const columns = useMemo(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
id: 'currency_name',
|
|
||||||
Header: 'Currency Name',
|
|
||||||
accessor: 'currency_name',
|
|
||||||
width: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'currency_code',
|
|
||||||
Header: '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]
|
|
||||||
);
|
|
||||||
const handleDatatableFetchData = useCallback(() => {
|
const handleDatatableFetchData = useCallback(() => {
|
||||||
onFetchData && onFetchData();
|
onFetchData && onFetchData();
|
||||||
}, []);
|
}, []);
|
||||||
@@ -112,9 +119,9 @@ function CurrenciesList({
|
|||||||
<LoadingIndicator>
|
<LoadingIndicator>
|
||||||
<DataTable
|
<DataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={Object.values(currencies)}
|
data={currenciesList}
|
||||||
onFetchData={handleDatatableFetchData()}
|
loading={fetchCurrencies.isFetching}
|
||||||
selectionColumn={true}
|
selectionColumn={false}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Alert
|
<Alert
|
||||||
@@ -136,7 +143,10 @@ function CurrenciesList({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
CurrencyFromDialogConnect,
|
withCurrencies(({ currenciesList }) => ({
|
||||||
|
currenciesList,
|
||||||
|
})),
|
||||||
|
withCurrenciesActions,
|
||||||
DialogConnect,
|
DialogConnect,
|
||||||
DashboardConnect
|
withDashboard
|
||||||
)(CurrenciesList);
|
)(CurrenciesList);
|
||||||
@@ -9,27 +9,36 @@ import {
|
|||||||
MenuItem,
|
MenuItem,
|
||||||
Classes,
|
Classes,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
|
import classNames from 'classnames';
|
||||||
import { optionsMapToArray, momentFormatter, optionsArrayToMap } from 'utils';
|
|
||||||
import { TimezonePicker } from '@blueprintjs/timezone';
|
import { TimezonePicker } from '@blueprintjs/timezone';
|
||||||
import { Select } from '@blueprintjs/select';
|
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 { useIntl } from 'react-intl';
|
||||||
import useAsync from 'hooks/async';
|
import { useQuery } from 'react-query';
|
||||||
|
|
||||||
|
import { compose, optionsMapToArray } from 'utils';
|
||||||
|
|
||||||
|
import ErrorMessage from 'components/ErrorMessage';
|
||||||
|
import AppToaster from 'components/AppToaster';
|
||||||
|
|
||||||
|
import withSettings from 'containers/Settings/withSettings';
|
||||||
|
import withSettingsActions from 'containers/Settings/withSettingsActions';
|
||||||
|
|
||||||
|
|
||||||
function GeneralPreferences({
|
function GeneralPreferences({
|
||||||
|
// #withSettings
|
||||||
organizationSettings,
|
organizationSettings,
|
||||||
|
|
||||||
|
// #withSettingsActions
|
||||||
requestSubmitOptions,
|
requestSubmitOptions,
|
||||||
requestFetchOptions,
|
requestFetchOptions,
|
||||||
}) {
|
}) {
|
||||||
|
const intl = useIntl();
|
||||||
const [selectedItems, setSelectedItems] = useState({});
|
const [selectedItems, setSelectedItems] = useState({});
|
||||||
const [timeZone, setTimeZone] = useState('');
|
const [timeZone, setTimeZone] = useState('');
|
||||||
|
|
||||||
|
const fetchHook = useQuery(['settings'],
|
||||||
|
() => { requestFetchOptions(); });
|
||||||
|
|
||||||
const businessLocation = [
|
const businessLocation = [
|
||||||
{ id: 218, name: 'LIBYA', code: 'LY' },
|
{ id: 218, name: 'LIBYA', code: 'LY' },
|
||||||
{ id: 380, name: 'UKRAINE', code: 'UA' },
|
{ id: 380, name: 'UKRAINE', code: 'UA' },
|
||||||
@@ -55,8 +64,6 @@ function GeneralPreferences({
|
|||||||
{ id: 6, name: 'Saturday, Apr 11, 2020', format: 'EEEE, MMM d, yyyy' },
|
{ id: 6, name: 'Saturday, Apr 11, 2020', format: 'EEEE, MMM d, yyyy' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
const validationSchema = Yup.object().shape({
|
||||||
name: Yup.string().required(intl.formatMessage({ id: 'required' })),
|
name: Yup.string().required(intl.formatMessage({ id: 'required' })),
|
||||||
industry: Yup.string().required(intl.formatMessage({ id: 'required' })),
|
industry: Yup.string().required(intl.formatMessage({ id: 'required' })),
|
||||||
@@ -69,15 +76,22 @@ function GeneralPreferences({
|
|||||||
// time_zone: Yup.object().required(intl.formatMessage({ id: 'required' })),
|
// time_zone: Yup.object().required(intl.formatMessage({ id: 'required' })),
|
||||||
date_format: Yup.date().required(intl.formatMessage({ id: 'required' })),
|
date_format: Yup.date().required(intl.formatMessage({ id: 'required' })),
|
||||||
});
|
});
|
||||||
console.log(organizationSettings.name);
|
|
||||||
|
|
||||||
const formik = useFormik({
|
const {
|
||||||
|
errors,
|
||||||
|
values,
|
||||||
|
touched,
|
||||||
|
isSubmitting,
|
||||||
|
setFieldValue,
|
||||||
|
getFieldProps,
|
||||||
|
handleSubmit,
|
||||||
|
resetForm,
|
||||||
|
} = useFormik({
|
||||||
enableReinitialize: true,
|
enableReinitialize: true,
|
||||||
initialValues: {
|
initialValues: {
|
||||||
...organizationSettings,
|
...organizationSettings,
|
||||||
},
|
},
|
||||||
validationSchema: validationSchema,
|
validationSchema,
|
||||||
|
|
||||||
onSubmit: (values, { setSubmitting }) => {
|
onSubmit: (values, { setSubmitting }) => {
|
||||||
const options = optionsMapToArray(values).map((option) => {
|
const options = optionsMapToArray(values).map((option) => {
|
||||||
return { key: option.key, ...option, group: 'organization' };
|
return { key: option.key, ...option, group: 'organization' };
|
||||||
@@ -96,12 +110,6 @@ function GeneralPreferences({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { errors, values, touched } = useMemo(() => formik, [formik]);
|
|
||||||
|
|
||||||
const fetchHook = useAsync(async () => {
|
|
||||||
await Promise.all([requestFetchOptions()]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const businessLocationItem = (item, { handleClick }) => (
|
const businessLocationItem = (item, { handleClick }) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
className={'preferences-menu'}
|
className={'preferences-menu'}
|
||||||
@@ -156,7 +164,7 @@ function GeneralPreferences({
|
|||||||
...selectedItems,
|
...selectedItems,
|
||||||
[filedName]: filed,
|
[filedName]: filed,
|
||||||
});
|
});
|
||||||
formik.setFieldValue(filedName, filed.name);
|
setFieldValue(filedName, filed.name);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -170,30 +178,30 @@ function GeneralPreferences({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='preferences__inside-content--general'>
|
<div className='preferences__inside-content--general'>
|
||||||
<form onSubmit={formik.handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={'Organization Name'}
|
label={'Organization Name'}
|
||||||
inline={true}
|
inline={true}
|
||||||
intent={errors.name && touched.name && Intent.DANGER}
|
intent={(errors.name && touched.name) && Intent.DANGER}
|
||||||
helperText={<ErrorMessage name='name' {...formik} />}
|
helperText={<ErrorMessage name='name' {...{errors, touched}} />}
|
||||||
>
|
>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
medium={'true'}
|
medium={'true'}
|
||||||
intent={errors.name && touched.name && Intent.DANGER}
|
intent={(errors.name && touched.name) && Intent.DANGER}
|
||||||
{...formik.getFieldProps('name')}
|
{...getFieldProps('name')}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={'Organization Industry'}
|
label={'Organization Industry'}
|
||||||
inline={true}
|
inline={true}
|
||||||
intent={errors.industry && touched.industry && Intent.DANGER}
|
intent={(errors.industry && touched.industry) && Intent.DANGER}
|
||||||
helperText={<ErrorMessage name='industry' {...formik} />}
|
helperText={<ErrorMessage name='industry' {...{errors, touched}} />}
|
||||||
>
|
>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
medium={'true'}
|
medium={'true'}
|
||||||
intent={errors.industry && touched.industry && Intent.DANGER}
|
intent={(errors.industry && touched.industry) && Intent.DANGER}
|
||||||
{...formik.getFieldProps('industry')}
|
{...getFieldProps('industry')}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
@@ -205,8 +213,8 @@ function GeneralPreferences({
|
|||||||
Classes.FILL
|
Classes.FILL
|
||||||
)}
|
)}
|
||||||
inline={true}
|
inline={true}
|
||||||
helperText={<ErrorMessage name='location' {...formik} />}
|
helperText={<ErrorMessage name='location' {...{errors, touched}} />}
|
||||||
intent={errors.location && touched.location && Intent.DANGER}
|
intent={(errors.location && touched.location) && Intent.DANGER}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
items={businessLocation}
|
items={businessLocation}
|
||||||
@@ -234,10 +242,8 @@ function GeneralPreferences({
|
|||||||
Classes.FILL
|
Classes.FILL
|
||||||
)}
|
)}
|
||||||
inline={true}
|
inline={true}
|
||||||
helperText={<ErrorMessage name='base_currency' {...formik} />}
|
helperText={<ErrorMessage name='base_currency' {...{ errors, touched }} />}
|
||||||
intent={
|
intent={(errors.base_currency && touched.base_currency) && Intent.DANGER}
|
||||||
errors.base_currency && touched.base_currency && Intent.DANGER
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
items={currencies}
|
items={currencies}
|
||||||
@@ -265,8 +271,8 @@ function GeneralPreferences({
|
|||||||
Classes.FILL
|
Classes.FILL
|
||||||
)}
|
)}
|
||||||
inline={true}
|
inline={true}
|
||||||
helperText={<ErrorMessage name='fiscal_year' {...formik} />}
|
helperText={<ErrorMessage name='fiscal_year' {...{errors, touched}} />}
|
||||||
intent={errors.fiscal_year && touched.fiscal_year && Intent.DANGER}
|
intent={(errors.fiscal_year && touched.fiscal_year) && Intent.DANGER}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
items={fiscalYear}
|
items={fiscalYear}
|
||||||
@@ -294,8 +300,8 @@ function GeneralPreferences({
|
|||||||
'form-group--select-list',
|
'form-group--select-list',
|
||||||
Classes.FILL
|
Classes.FILL
|
||||||
)}
|
)}
|
||||||
intent={errors.language && touched.language && Intent.DANGER}
|
intent={(errors.language && touched.language) && Intent.DANGER}
|
||||||
helperText={<ErrorMessage name='language' {...formik} />}
|
helperText={<ErrorMessage name='language' {...{errors, touched}} />}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
items={languagesDisplay}
|
items={languagesDisplay}
|
||||||
@@ -321,8 +327,8 @@ function GeneralPreferences({
|
|||||||
'form-group--select-list',
|
'form-group--select-list',
|
||||||
Classes.FILL
|
Classes.FILL
|
||||||
)}
|
)}
|
||||||
intent={errors.time_zone && touched.time_zone && Intent.DANGER}
|
intent={(errors.time_zone && touched.time_zone) && Intent.DANGER}
|
||||||
helperText={<ErrorMessage name='time_zone' {...formik} />}
|
helperText={<ErrorMessage name='time_zone' {...{errors, touched}} />}
|
||||||
>
|
>
|
||||||
<TimezonePicker
|
<TimezonePicker
|
||||||
value={timeZone}
|
value={timeZone}
|
||||||
@@ -339,8 +345,8 @@ function GeneralPreferences({
|
|||||||
'form-group--select-list',
|
'form-group--select-list',
|
||||||
Classes.FILL
|
Classes.FILL
|
||||||
)}
|
)}
|
||||||
intent={errors.date_format && touched.date_format && Intent.DANGER}
|
intent={(errors.date_format && touched.date_format) && Intent.DANGER}
|
||||||
helperText={<ErrorMessage name='date_format' {...formik} />}
|
helperText={<ErrorMessage name='date_format' {...{errors, touched}} />}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
items={dateFormat}
|
items={dateFormat}
|
||||||
@@ -374,4 +380,7 @@ function GeneralPreferences({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(SettingsConnect)(GeneralPreferences);
|
export default compose(
|
||||||
|
withSettings,
|
||||||
|
withSettingsActions,
|
||||||
|
)(GeneralPreferences);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useMemo, useCallback } from 'react';
|
import React, { useState, useMemo, useCallback } from 'react';
|
||||||
import { useAsync } from 'react-use';
|
import { useQuery } from 'react-query';
|
||||||
import DataTable from 'components/DataTable';
|
import DataTable from 'components/DataTable';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
@@ -11,30 +11,42 @@ import {
|
|||||||
Position,
|
Position,
|
||||||
Intent,
|
Intent,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
|
import { snakeCase } from 'lodash';
|
||||||
|
|
||||||
import Icon from 'components/Icon';
|
import Icon from 'components/Icon';
|
||||||
import LoadingIndicator from 'components/LoadingIndicator';
|
import LoadingIndicator from 'components/LoadingIndicator';
|
||||||
import { snakeCase } from 'lodash';
|
|
||||||
import UserListConnect from 'connectors/UsersList.connector';
|
|
||||||
import AppToaster from 'components/AppToaster';
|
import AppToaster from 'components/AppToaster';
|
||||||
import { compose } from 'utils';
|
|
||||||
import DialogConnect from 'connectors/Dialog.connector';
|
import DialogConnect from 'connectors/Dialog.connector';
|
||||||
import DashboardConnect from 'connectors/Dashboard.connector';
|
import withDashboard from 'containers/Dashboard/withDashboard';
|
||||||
|
import withUsers from 'containers/Users/withUsers';
|
||||||
|
import withUsersActions from 'containers/Users/withUsersActions';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
|
||||||
function UsersListPreferences({
|
function UsersListPreferences({
|
||||||
requestFetchUsers,
|
// #withDialog
|
||||||
usersList,
|
|
||||||
openDialog,
|
openDialog,
|
||||||
closeDialog,
|
closeDialog,
|
||||||
|
|
||||||
|
// #withUsers
|
||||||
|
usersList,
|
||||||
|
|
||||||
|
// #withUsersActions
|
||||||
requestDeleteUser,
|
requestDeleteUser,
|
||||||
requestInactiveUser,
|
requestInactiveUser,
|
||||||
|
requestFetchUsers,
|
||||||
|
|
||||||
|
// #ownProps
|
||||||
onFetchData,
|
onFetchData,
|
||||||
}) {
|
}) {
|
||||||
const [deleteUserState, setDeleteUserState] = useState(false);
|
const [deleteUserState, setDeleteUserState] = useState(false);
|
||||||
const [inactiveUserState, setInactiveUserState] = useState(false);
|
const [inactiveUserState, setInactiveUserState] = useState(false);
|
||||||
|
|
||||||
const asyncHook = useAsync(async () => {
|
const fetchUsers = useQuery('users-table',
|
||||||
await Promise.all([requestFetchUsers()]);
|
() => requestFetchUsers());
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onInactiveUser = (user) => {
|
const onInactiveUser = (user) => {
|
||||||
setInactiveUserState(user);
|
setInactiveUserState(user);
|
||||||
@@ -49,7 +61,6 @@ function UsersListPreferences({
|
|||||||
const handleConfirmUserActive = useCallback(() => {
|
const handleConfirmUserActive = useCallback(() => {
|
||||||
requestInactiveUser(inactiveUserState.id).then(() => {
|
requestInactiveUser(inactiveUserState.id).then(() => {
|
||||||
setInactiveUserState(false);
|
setInactiveUserState(false);
|
||||||
requestFetchUsers();
|
|
||||||
AppToaster.show({ message: 'the_user_has_been_inactivated' });
|
AppToaster.show({ message: 'the_user_has_been_inactivated' });
|
||||||
});
|
});
|
||||||
}, [inactiveUserState, requestInactiveUser, requestFetchUsers]);
|
}, [inactiveUserState, requestInactiveUser, requestFetchUsers]);
|
||||||
@@ -105,50 +116,47 @@ function UsersListPreferences({
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = useMemo(() => [
|
||||||
() => [
|
{
|
||||||
{
|
id: 'full_name',
|
||||||
id: 'full_name',
|
Header: 'Full Name',
|
||||||
Header: 'Full Name',
|
accessor: 'full_name',
|
||||||
accessor: 'full_name',
|
width: 170,
|
||||||
width: 170,
|
},
|
||||||
},
|
{
|
||||||
{
|
id: 'email',
|
||||||
id: 'email',
|
Header: 'Email',
|
||||||
Header: 'Email',
|
accessor: 'email',
|
||||||
accessor: 'email',
|
width: 150,
|
||||||
width: 150,
|
},
|
||||||
},
|
{
|
||||||
{
|
id: 'phone_number',
|
||||||
id: 'phone_number',
|
Header: 'Phone Number',
|
||||||
Header: 'Phone Number',
|
accessor: 'phone_number',
|
||||||
accessor: 'phone_number',
|
width: 150,
|
||||||
width: 150,
|
},
|
||||||
},
|
{
|
||||||
{
|
id: 'active',
|
||||||
id: 'active',
|
Header: 'Status',
|
||||||
Header: 'Status',
|
accessor: (user) =>
|
||||||
accessor: (user) =>
|
user.active ? <span>Active</span> : <span>Inactivate</span>,
|
||||||
user.active ? <span>Active</span> : <span>Inactivate</span>,
|
width: 50,
|
||||||
width: 50,
|
},
|
||||||
},
|
{
|
||||||
{
|
id: 'actions',
|
||||||
id: 'actions',
|
Header: '',
|
||||||
Header: '',
|
Cell: ({ cell }) => (
|
||||||
Cell: ({ cell }) => (
|
<Popover
|
||||||
<Popover
|
content={actionMenuList(cell.row.original)}
|
||||||
content={actionMenuList(cell.row.original)}
|
position={Position.RIGHT_TOP}
|
||||||
position={Position.RIGHT_TOP}
|
>
|
||||||
>
|
<Button icon={<Icon icon='ellipsis-h' />} />
|
||||||
<Button icon={<Icon icon='ellipsis-h' />} />
|
</Popover>
|
||||||
</Popover>
|
),
|
||||||
),
|
className: 'actions',
|
||||||
className: 'actions',
|
width: 50,
|
||||||
width: 50,
|
},
|
||||||
},
|
], [actionMenuList]);
|
||||||
],
|
|
||||||
[actionMenuList]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handelDataTableFetchData = useCallback(() => {
|
const handelDataTableFetchData = useCallback(() => {
|
||||||
onFetchData && onFetchData();
|
onFetchData && onFetchData();
|
||||||
@@ -160,6 +168,7 @@ function UsersListPreferences({
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
data={usersList}
|
data={usersList}
|
||||||
onFetchData={handelDataTableFetchData()}
|
onFetchData={handelDataTableFetchData()}
|
||||||
|
loading={fetchUsers.isFetching}
|
||||||
manualSortBy={true}
|
manualSortBy={true}
|
||||||
expandable={false}
|
expandable={false}
|
||||||
/>
|
/>
|
||||||
@@ -198,7 +207,8 @@ function UsersListPreferences({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
UserListConnect,
|
|
||||||
DialogConnect,
|
DialogConnect,
|
||||||
DashboardConnect
|
withDashboard,
|
||||||
|
withUsers,
|
||||||
|
withUsersActions,
|
||||||
)(UsersListPreferences);
|
)(UsersListPreferences);
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
export const mapStateToProps = (state, props) => {
|
|
||||||
return {
|
|
||||||
usersList: state.users.list.results,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps);
|
|
||||||
7
client/src/containers/Settings/withSettings.js
Normal file
7
client/src/containers/Settings/withSettings.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
export const mapStateToProps = (state, props) => ({
|
||||||
|
organizationSettings: state.settings.data.organization,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps);
|
||||||
12
client/src/containers/Settings/withSettingsActions.js
Normal file
12
client/src/containers/Settings/withSettingsActions.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
import {
|
||||||
|
FetchOptions,
|
||||||
|
submitOptions,
|
||||||
|
} from 'store/settings/settings.actions';
|
||||||
|
|
||||||
|
export const mapDispatchToProps = (dispatch) => ({
|
||||||
|
requestSubmitOptions: (form) => dispatch(submitOptions({ form })),
|
||||||
|
requestFetchOptions: () => dispatch(FetchOptions({})),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(null, mapDispatchToProps);
|
||||||
7
client/src/containers/Users/withUsers.js
Normal file
7
client/src/containers/Users/withUsers.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
export const mapStateToProps = (state, props) => ({
|
||||||
|
usersList: state.users.list.results,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps);
|
||||||
@@ -5,35 +5,30 @@ const BASE_URL = '/auth';
|
|||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
path: `${BASE_URL}/login`,
|
path: `${BASE_URL}/login`,
|
||||||
name: 'auth.login',
|
|
||||||
component: LazyLoader({
|
component: LazyLoader({
|
||||||
loader: () => import('containers/Authentication/Login'),
|
loader: () => import('containers/Authentication/Login'),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `${BASE_URL}/register`,
|
path: `${BASE_URL}/register`,
|
||||||
name: 'auth.register',
|
|
||||||
component: LazyLoader({
|
component: LazyLoader({
|
||||||
loader: () => import('containers/Authentication/Register'),
|
loader: () => import('containers/Authentication/Register'),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `${BASE_URL}/send_reset_password`,
|
path: `${BASE_URL}/send_reset_password`,
|
||||||
name: 'auth.reset_password',
|
|
||||||
component: LazyLoader({
|
component: LazyLoader({
|
||||||
loader: () => import('containers/Authentication/SendResetPassword'),
|
loader: () => import('containers/Authentication/SendResetPassword'),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `${BASE_URL}/reset_password/:token`,
|
path: `${BASE_URL}/reset_password/:token`,
|
||||||
name: 'auth.send.reset_password',
|
|
||||||
component: LazyLoader({
|
component: LazyLoader({
|
||||||
loader: () => import('containers/Authentication/ResetPassword'),
|
loader: () => import('containers/Authentication/ResetPassword'),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `${BASE_URL}/invite/:token/accept`,
|
path: `${BASE_URL}/invite/:token/accept`,
|
||||||
name: 'auth.invite.accept',
|
|
||||||
component: LazyLoader({
|
component: LazyLoader({
|
||||||
loader: () => import('containers/Authentication/InviteAccept'),
|
loader: () => import('containers/Authentication/InviteAccept'),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,21 +1,19 @@
|
|||||||
import General from 'containers/Preferences/General';
|
import General from 'containers/Preferences/General/General';
|
||||||
import Users from 'containers/Preferences/Users';
|
import Users from 'containers/Preferences/Users/Users';
|
||||||
import Accountant from 'containers/Preferences/Accountant';
|
import Accountant from 'containers/Preferences/Accountant/Accountant';
|
||||||
import Accounts from 'containers/Preferences/Accounts';
|
import Accounts from 'containers/Preferences/Accounts/Accounts';
|
||||||
import CurrenciesList from 'containers/Preferences/CurrenciesList'
|
import CurrenciesList from 'containers/Preferences/Currencies/CurrenciesList'
|
||||||
|
|
||||||
const BASE_URL = '/dashboard/preferences';
|
const BASE_URL = '/dashboard/preferences';
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
path: `${BASE_URL}/general`,
|
path: `${BASE_URL}/general`,
|
||||||
name: 'dashboard.preferences.general',
|
|
||||||
component: General,
|
component: General,
|
||||||
exact: true,
|
exact: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `${BASE_URL}/users`,
|
path: `${BASE_URL}/users`,
|
||||||
name: 'dashboard.preferences.users',
|
|
||||||
component: Users,
|
component: Users,
|
||||||
exact: true,
|
exact: true,
|
||||||
},
|
},
|
||||||
@@ -26,13 +24,11 @@ export default [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `${BASE_URL}/accountant`,
|
path: `${BASE_URL}/accountant`,
|
||||||
name: 'dashboard.preferences.accountant',
|
|
||||||
component: Accountant,
|
component: Accountant,
|
||||||
exact: true,
|
exact: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `${BASE_URL}/accounts`,
|
path: `${BASE_URL}/accounts`,
|
||||||
name: 'dashboard.preferences.accounts',
|
|
||||||
component: Accounts,
|
component: Accounts,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
import AccountsCustomFields from "containers/Preferences/AccountsCustomFields";
|
// import AccountsCustomFields from "containers/Preferences/AccountsCustomFields";
|
||||||
import UsersList from 'containers/Preferences/UsersList';
|
import UsersList from 'containers/Preferences/Users/UsersList';
|
||||||
import RolesList from 'containers/Preferences/RolesList';
|
import RolesList from 'containers/Preferences/Users/RolesList';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
accounts: [
|
accounts: [
|
||||||
{
|
// {
|
||||||
path: '',
|
// path: '',
|
||||||
component: AccountsCustomFields,
|
// component: AccountsCustomFields,
|
||||||
exact: true,
|
// exact: true,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: 'dashboard.preferences.accounts.custom_fields',
|
// path: 'custom_fields',
|
||||||
path: 'custom_fields',
|
// component: AccountsCustomFields,
|
||||||
component: AccountsCustomFields,
|
// exact: true,
|
||||||
exact: true,
|
// },
|
||||||
},
|
|
||||||
],
|
],
|
||||||
users: [
|
users: [
|
||||||
{
|
{
|
||||||
@@ -23,7 +22,6 @@ export default {
|
|||||||
exact: true,
|
exact: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'dashboard.preferences.users.roles',
|
|
||||||
path: '/roles',
|
path: '/roles',
|
||||||
component: RolesList,
|
component: RolesList,
|
||||||
exact: true,
|
exact: true,
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import { createReducer } from '@reduxjs/toolkit';
|
|||||||
import t from 'store/types';
|
import t from 'store/types';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
preferences: {
|
data: {},
|
||||||
currencies: [],
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default createReducer(initialState, {
|
export default createReducer(initialState, {
|
||||||
@@ -14,8 +12,8 @@ export default createReducer(initialState, {
|
|||||||
action.currencies.forEach((currency) => {
|
action.currencies.forEach((currency) => {
|
||||||
_currencies[currency.currency_code] = currency;
|
_currencies[currency.currency_code] = currency;
|
||||||
});
|
});
|
||||||
state.preferences.currencies = {
|
state.data = {
|
||||||
...state.preferences.currencies,
|
...state.data,
|
||||||
..._currencies,
|
..._currencies,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
export const getCurrencyById = (items, id) => {
|
// @flow
|
||||||
return items[id] || null;
|
|
||||||
|
export const getCurrencyById = (currencies: Object, id: Integer) => {
|
||||||
|
return Object.values(currencies).find(c => c.id == id) || null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getCurrencyByCode = (currencies: Object, currencyCode: String) => {
|
||||||
|
return currencies[currencyCode] || null;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user