WIP / Fix_ExchangeRate / localize

This commit is contained in:
elforjani3
2020-05-11 04:12:23 +02:00
parent cceb4786c2
commit 98edc66dd2
20 changed files with 636 additions and 413 deletions

View File

@@ -21,14 +21,19 @@ import MediaConnect from 'connectors/Media.connect';
import useMedia from 'hooks/useMedia';
import {compose} from 'utils';
import { FormattedMessage as T, useIntl } from 'react-intl';
function MakeJournalEntriesForm({
// #withMedia
requestSubmitMedia,
requestDeleteMedia,
// #withJournalsActions
requestMakeJournalEntries,
requestEditManualJournal,
// #withDashboard
changePageTitle,
changePageSubtitle,
@@ -47,13 +52,14 @@ function MakeJournalEntriesForm({
const savedMediaIds = useRef([]);
const clearSavedMediaIds = () => { savedMediaIds.current = []; }
const {formatMessage} =useIntl()
useEffect(() => {
if (manualJournal && manualJournal.id) {
changePageTitle('Edit Journal');
changePageTitle(formatMessage({id:'edit_journal'}));
changePageSubtitle(`No. ${manualJournal.journal_number}`);
} else {
changePageTitle('New Journal');
changePageTitle(formatMessage({id:'new_journal'}));
}
}, [changePageTitle, changePageSubtitle, manualJournal]);
@@ -252,8 +258,6 @@ function MakeJournalEntriesForm({
}
export default compose(
// ManualJournalsConnect,
// MakeJournalEntriesConnect,
withJournalsActions,
withManualJournalDetail,
withAccountsActions,

View File

@@ -22,22 +22,24 @@ import { compose } from 'utils';
* Manual journals table.
*/
function ManualJournalsTable({
// #withDashboardActions
changePageTitle,
// #withViewsActions
requestFetchResourceViews,
// #withManualJournalsActions
requestFetchManualJournalsTable,
requestDeleteManualJournal,
requestPublishManualJournal,
requestDeleteBulkManualJournals,
addManualJournalsTableQueries,
}) {
const history = useHistory();
const [deleteManualJournal, setDeleteManualJournal] = useState(false);
const [selectedRows, setSelectedRows] = useState([]);
const [bulkDelete, setBulkDelete] = useState(false);
const { formatMessage } = useIntl();
const fetchViews = useQuery('journals-resource-views', () => {
return requestFetchResourceViews('manual_journals');
});
@@ -47,7 +49,7 @@ function ManualJournalsTable({
);
useEffect(() => {
changePageTitle('Manual Journals');
changePageTitle(formatMessage({id:'manual_journals'}));
}, [changePageTitle]);
// Handle delete manual journal click.
@@ -163,9 +165,7 @@ function ManualJournalsTable({
'/dashboard/accounting/manual-journals/:custom_view_id/custom_view',
'/dashboard/accounting/manual-journals',
]}
>
<ManualJournalsViewTabs onViewChanged={handleViewChanged} />
</Route>
></Route>
</Switch>
<ManualJournalsDataTable

View File

@@ -1,10 +1,7 @@
import React, { useEffect, useState, useCallback } from 'react';
import {
Route,
Switch,
} from 'react-router-dom';
import { Route, Switch } from 'react-router-dom';
import { Alert, Intent } from '@blueprintjs/core';
import { useQuery } from 'react-query'
import { useQuery } from 'react-query';
import AppToaster from 'components/AppToaster';
@@ -26,7 +23,6 @@ import { compose } from 'utils';
import { FormattedMessage as T, useIntl } from 'react-intl';
function AccountsChart({
// #withDashboard
changePageTitle,
@@ -54,7 +50,7 @@ function AccountsChart({
const [selectedRows, setSelectedRows] = useState([]);
const [tableLoading, setTableLoading] = useState(false);
const { formatMessage } = useIntl();
// Fetch accounts resource views and fields.
const fetchHook = useQuery('resource-accounts', () => {
return Promise.all([
@@ -64,38 +60,49 @@ function AccountsChart({
});
// Fetch accounts list according to the given custom view id.
const fetchAccountsHook = useQuery(['accounts-table', accountsTableQuery],
() => requestFetchAccountsTable());
const fetchAccountsHook = useQuery(
['accounts-table', accountsTableQuery],
() => requestFetchAccountsTable(),
{ refetchInterval: 3000 }
);
useEffect(() => {
changePageTitle('Chart of Accounts');
changePageTitle(formatMessage({ id: 'chart_of_accounts' }));
}, [changePageTitle]);
// Handle click and cancel/confirm account delete
const handleDeleteAccount = (account) => { setDeleteAccount(account); };
const handleDeleteAccount = (account) => {
setDeleteAccount(account);
};
// handle cancel delete account alert.
const handleCancelAccountDelete = useCallback(() => { setDeleteAccount(false); }, []);
const handleCancelAccountDelete = useCallback(() => {
setDeleteAccount(false);
}, []);
// Handle confirm account delete
const handleConfirmAccountDelete = useCallback(() => {
requestDeleteAccount(deleteAccount.id).then(() => {
setDeleteAccount(false);
AppToaster.show({ message: 'the_account_has_been_deleted' });
}).catch(errors => {
setDeleteAccount(false);
if (errors.find((e) => e.type === 'ACCOUNT.PREDEFINED')) {
AppToaster.show({
message: 'cannot_delete_predefined_account',
intent: Intent.DANGER,
});
}
if (errors.find((e) => e.type === 'ACCOUNT.HAS.ASSOCIATED.TRANSACTIONS')) {
AppToaster.show({
message: 'cannot_delete_account_has_associated_transactions'
});
}
});
requestDeleteAccount(deleteAccount.id)
.then(() => {
setDeleteAccount(false);
AppToaster.show({ message: 'the_account_has_been_deleted' });
})
.catch((errors) => {
setDeleteAccount(false);
if (errors.find((e) => e.type === 'ACCOUNT.PREDEFINED')) {
AppToaster.show({
message: 'cannot_delete_predefined_account',
intent: Intent.DANGER,
});
}
if (
errors.find((e) => e.type === 'ACCOUNT.HAS.ASSOCIATED.TRANSACTIONS')
) {
AppToaster.show({
message: 'cannot_delete_account_has_associated_transactions',
});
}
});
}, [deleteAccount, requestDeleteAccount]);
// Handle cancel/confirm account inactive.
@@ -117,43 +124,44 @@ function AccountsChart({
});
}, [inactiveAccount, requestFetchAccountsTable, requestInactiveAccount]);
const handleEditAccount = (account) => {};
const handleEditAccount = (account) => {
const handleRestoreAccount = (account) => {};
};
const handleRestoreAccount = (account) => {
};
const handleBulkDelete = useCallback((accountsIds) => {
setBulkDelete(accountsIds);
}, [setBulkDelete]);
const handleBulkDelete = useCallback(
(accountsIds) => {
setBulkDelete(accountsIds);
},
[setBulkDelete]
);
const handleConfirmBulkDelete = useCallback(() => {
requestDeleteBulkAccounts(bulkDelete).then(() => {
setBulkDelete(false);
AppToaster.show({ message: 'the_accounts_have_been_deleted' });
}).catch((error) => {
setBulkDelete(false);
});
requestDeleteBulkAccounts(bulkDelete)
.then(() => {
setBulkDelete(false);
AppToaster.show({ message: 'the_accounts_have_been_deleted' });
})
.catch((error) => {
setBulkDelete(false);
});
}, [requestDeleteBulkAccounts, bulkDelete]);
const handleCancelBulkDelete = useCallback(() => {
setBulkDelete(false);
}, []);
const handleBulkArchive = useCallback((accounts) => {
}, []);
const handleBulkArchive = useCallback((accounts) => {}, []);
// Handle selected rows change.
const handleSelectedRowsChange = useCallback((accounts) => {
setSelectedRows(accounts);
}, [setSelectedRows]);
const handleSelectedRowsChange = useCallback(
(accounts) => {
setSelectedRows(accounts);
},
[setSelectedRows]
);
// Refetches accounts data table when current custom view changed.
const handleFilterChanged = useCallback(() => {
const handleFilterChanged = useCallback(() => {
fetchAccountsHook.refetch();
}, [fetchAccountsHook]);
@@ -169,25 +177,29 @@ function AccountsChart({
}, [tableLoading, fetchAccountsHook.isFetching]);
// Handle fetch data of accounts datatable.
const handleFetchData = useCallback(({ pageIndex, pageSize, sortBy }) => {
addAccountsTableQueries({
...(sortBy.length > 0) ? {
column_sort_by: sortBy[0].id,
sort_order: sortBy[0].desc ? 'desc' : 'asc',
} : {},
});
fetchAccountsHook.refetch();
}, [fetchAccountsHook, addAccountsTableQueries]);
const handleFetchData = useCallback(
({ pageIndex, pageSize, sortBy }) => {
addAccountsTableQueries({
...(sortBy.length > 0
? {
column_sort_by: sortBy[0].id,
sort_order: sortBy[0].desc ? 'desc' : 'asc',
}
: {}),
});
fetchAccountsHook.refetch();
},
[fetchAccountsHook, addAccountsTableQueries]
);
return (
<DashboardInsider
loading={fetchHook.isFetching}
name={'accounts-chart'}>
<DashboardInsider loading={fetchHook.isFetching} name={'accounts-chart'}>
<DashboardActionsBar
selectedRows={selectedRows}
onFilterChanged={handleFilterChanged}
onBulkDelete={handleBulkDelete}
onBulkArchive={handleBulkArchive} />
onBulkArchive={handleBulkArchive}
/>
<DashboardPageContent>
<Switch>
@@ -196,9 +208,9 @@ function AccountsChart({
path={[
'/dashboard/accounts/:custom_view_id/custom_view',
'/dashboard/accounts',
]}>
<AccountsViewsTabs
onViewChanged={handleViewChanged} />
]}
>
<AccountsViewsTabs onViewChanged={handleViewChanged} />
<AccountsDataTable
onDeleteAccount={handleDeleteAccount}
@@ -207,49 +219,53 @@ function AccountsChart({
onEditAccount={handleEditAccount}
onFetchData={handleFetchData}
onSelectedRowsChange={handleSelectedRowsChange}
loading={tableLoading} />
loading={tableLoading}
/>
</Route>
</Switch>
<Alert
cancelButtonText="Cancel"
confirmButtonText="Move to Trash"
icon="trash"
cancelButtonText='Cancel'
confirmButtonText='Move to Trash'
icon='trash'
intent={Intent.DANGER}
isOpen={deleteAccount}
onCancel={handleCancelAccountDelete}
onConfirm={handleConfirmAccountDelete}>
onConfirm={handleConfirmAccountDelete}
>
<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>
<Alert
cancelButtonText={<T id={'cancel'}/>}
confirmButtonText={<T id={'inactivate'}/>}
icon="trash"
cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'inactivate'} />}
icon='trash'
intent={Intent.WARNING}
isOpen={inactiveAccount}
onCancel={handleCancelInactiveAccount}
onConfirm={handleConfirmAccountActive}>
onConfirm={handleConfirmAccountActive}
>
<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>
<Alert
cancelButtonText={<T id={'cancel'}/>}
confirmButtonText={<T id={'delete'}/>}
icon="trash"
cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'delete'} />}
icon='trash'
intent={Intent.DANGER}
isOpen={bulkDelete}
onCancel={handleCancelBulkDelete}
onConfirm={handleConfirmBulkDelete}>
onConfirm={handleConfirmBulkDelete}
>
<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>
</DashboardPageContent>
@@ -263,6 +279,7 @@ export default compose(
withViewsActions,
withResourceActions,
withDashboardActions,
withAccounts,
)(AccountsChart);
withAccounts(({ accountsTableQuery }) => ({
accountsTableQuery,
}))
)(AccountsChart);

View File

@@ -21,16 +21,15 @@ import withDashboardActions from 'containers/Dashboard/withDashboard';
import withAccountsActions from 'containers/Accounts/withAccountsActions';
import withAccounts from 'containers/Accounts/withAccounts';
import {If} from 'components';
import { FormattedMessage as T, useIntl } from 'react-intl';
function AccountsDataTable({
// # withAccounts
// #withAccounts
accounts,
accountsLoading,
// # withDialog.
// #withDialog.
openDialog,
// own properties
@@ -58,7 +57,7 @@ function AccountsDataTable({
const actionMenuList = useCallback((account) => (
<Menu>
<MenuItem text='View Details' />
<MenuItem text={<T id={'view_details'}/>} />
<MenuDivider />
<MenuItem
text={<T id={'edit_account'}/>}
@@ -166,9 +165,6 @@ function AccountsDataTable({
return (
<LoadingIndicator loading={loading} mount={false}>
<If condition={loading}>
asdasdsadsa
</If>
<DataTable
noInitialFetch={true}
columns={columns}
@@ -189,5 +185,8 @@ export default compose(
DialogConnect,
withDashboardActions,
withAccountsActions,
withAccounts,
withAccounts(({ accountsLoading, accounts }) => ({
accountsLoading,
accounts,
})),
)(AccountsDataTable);

View File

@@ -13,32 +13,36 @@ import * as Yup from 'yup';
import { FormattedMessage as T, useIntl } from 'react-intl';
import { useFormik } from 'formik';
import Dialog from 'components/Dialog';
import AppToaster from 'components/AppToaster';
import { useQuery, queryCache } from 'react-query';
import AppToaster from 'components/AppToaster';
import ErrorMessage from 'components/ErrorMessage';
import classNames from 'classnames';
import { Select } from '@blueprintjs/select';
import moment from 'moment';
import { DateInput } from '@blueprintjs/datetime';
import { momentFormatter } from 'utils';
import ExchangeRatesDialogConnect from 'connectors/ExchangeRatesFromDialog.connect';
import CurrencyFromDialogConnect from 'connectors/CurrencyFromDialog.connect'
import withExchangeRatesDialog from 'containers/FinancialStatements/ExchangeRates/withExchangeRateDialog';
import withExchangeRate from 'containers/FinancialStatements/ExchangeRates/withExchangeRates'
function ExchangeRateDialog({
name,
payload,
isOpen,
openDialog,
// #withDialog
closeDialog,
currencies,
// #withExchangeRatesActions
requestSubmitExchangeRate,
requestFetchExchangeRates,
requestEditExchangeRate,
requestFetchCurrencies,
editExchangeRate,
addExchangeRatesTableQueries,
}) {
const {formatMessage} = useIntl();
@@ -107,9 +111,14 @@ function ExchangeRateDialog({
closeDialog(name);
}, [name, closeDialog]);
const fetchHook = useQuery('exchange-rates-dialog', () => {
return Promise.all([requestFetchExchangeRates(), requestFetchCurrencies()]);
});
// const fetchHook = useQuery('exchange-rates-dialog', () => {
// return Promise.all([requestFetchExchangeRates(), requestFetchCurrencies()]);
// });
const fetchExchangeRatesDialog = useQuery('exchange-rates-dialog',
() => requestFetchExchangeRates(),
{ refetchInterval: 3000 });
const onDialogClosed = useCallback(() => {
formik.resetForm();
@@ -117,8 +126,8 @@ function ExchangeRateDialog({
}, [formik, closeDialog, name]);
const onDialogOpening = useCallback(() => {
fetchHook.refetch();
}, [fetchHook]);
fetchExchangeRatesDialog.refetch();
}, [fetchExchangeRatesDialog]);
const handleDateChange = useCallback(
(date) => {
@@ -185,14 +194,14 @@ function ExchangeRateDialog({
}
className={classNames(
{
'dialog--loading': fetchHook.pending,
'dialog--loading': fetchExchangeRatesDialog.pending,
},
'dialog--exchangeRate-form'
)}
isOpen={isOpen}
onClosed={onDialogClosed}
onOpening={onDialogOpening}
isLoading={fetchHook.pending}
isLoading={fetchExchangeRatesDialog.pending}
onClose={handleClose}
>
<form onSubmit={formik.handleSubmit}>
@@ -279,4 +288,4 @@ function ExchangeRateDialog({
);
}
export default ExchangeRatesDialogConnect(ExchangeRateDialog);
export default withExchangeRatesDialog(ExchangeRateDialog);

View File

@@ -4,6 +4,7 @@ import {useParams} from 'react-router-dom';
import Connector from 'connectors/ExpenseForm.connector';
import DashboardInsider from 'components/Dashboard/DashboardInsider';
import ExpenseForm from 'components/Expenses/ExpenseForm';
import { FormattedMessage as T, useIntl } from 'react-intl';
function ExpenseFormContainer({
fetchAccounts,
@@ -15,12 +16,12 @@ function ExpenseFormContainer({
currencies,
}) {
const { id } = useParams();
const { formatMessage } = useIntl();
useEffect(() => {
if (id) {
changePageTitle('Edit Expense Details');
changePageTitle(formatMessage({id:'edit_expense_details'}));
} else {
changePageTitle('New Expense');
changePageTitle(formatMessage({id:'new_expense'}));
}
}, []);

View File

@@ -18,8 +18,9 @@ function ExpensesList({
getResourceViews,
changePageTitle
}) {
const {formatMessage} =useIntl()
useEffect(() => {
changePageTitle('Expenses List');
changePageTitle(formatMessage({id:'expenses_list'}));
}, []);
const [deleteExpenseState, setDeleteExpense] = useState();

View File

@@ -18,9 +18,12 @@ import { compose } from 'utils';
import { FormattedMessage as T, useIntl } from 'react-intl';
function ExchangeRate({
views,
// #withDashboard
changePageTitle,
//#withExchangeRatesActions
requestFetchResourceFields,
requestFetchExchangeRates,
requestDeleteExchangeRate,
addExchangeRatesTableQueries,
@@ -28,15 +31,21 @@ function ExchangeRate({
const { id } = useParams();
const [deleteExchangeRate, setDeleteExchangeRate] = useState(false);
const [selectedRows, setSelectedRows] = useState([]);
const { formatMessage } = useIntl();
// const fetchExchangeRates = useQuery('exchange-rates-table', () => {
// return Promise.all([requestFetchExchangeRates()]);
// });
const fetchExchangeRates = useQuery('exchange-rates-table',
() => requestFetchExchangeRates(),
{ refetchInterval: 3000 });
const fetchHook = useQuery('exchange-rates', () => {
return Promise.all([requestFetchExchangeRates()]);
});
useEffect(() => {
id
? changePageTitle('Exchange Rate Details')
: changePageTitle('Exchange Rate List');
? changePageTitle(formatMessage({id:'exchange_rate_details'}))
: changePageTitle(formatMessage({id:'exchange_rate_list'}));
}, [id, changePageTitle]);
const handelDeleteExchangeRate = useCallback(
@@ -84,9 +93,8 @@ function ExchangeRate({
);
return (
<DashboardInsider loading={fetchHook.pending}>
<DashboardInsider>
<ExchangeRateActionsBar
views={views}
onDeleteExchangeRate={handelDeleteExchangeRate}
selectedRows={selectedRows}
/>
@@ -98,8 +106,8 @@ function ExchangeRate({
onSelectedRowsChange={handleSelectedRowsChange}
/>
<Alert
cancelButtonText={<T id={'cancel'}/>}
confirmButtonText={<T id={'move_to_trash'}/>}
cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'move_to_trash'} />}
icon='trash'
intent={Intent.DANGER}
isOpen={deleteExchangeRate}
@@ -118,5 +126,6 @@ function ExchangeRate({
export default compose(
withExchangeRatesActions,
withResourceActions,
withDashboardActions
)(ExchangeRate);

View File

@@ -1,6 +1,4 @@
import React, { useCallback, useState, useMemo } from 'react';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import { compose } from 'utils';
import {
NavbarGroup,
Button,
@@ -10,37 +8,39 @@ import {
Position,
PopoverInteractionKind,
} from '@blueprintjs/core';
import { connect } from 'react-redux';
import classNames from 'classnames';
import Icon from 'components/Icon';
import DashboardConnect from 'connectors/Dashboard.connector';
import { connect } from 'react-redux';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import DialogConnect from 'connectors/Dialog.connector';
import FilterDropdown from 'components/FilterDropdown';
import ExchangeRatesDialogConnect from 'connectors/ExchangeRatesFromDialog.connect';
import withResourceDetail from 'containers/Resources/withResourceDetails';
import withExchangeRates from 'containers/FinancialStatements/ExchangeRates/withExchangeRates';
import withExchangeRatesActions from 'containers/FinancialStatements/ExchangeRates/withExchangeRatesActions';
import withExchangeRateDialog from 'containers/FinancialStatements/ExchangeRates/withExchangeRateDialog';
import { compose } from 'utils';
import { FormattedMessage as T, useIntl } from 'react-intl';
function ExchangeRateActionsBar({
// #withDialog.
openDialog,
// #withResourceDetail
resourceFields,
selectedRows = [],
onDeleteExchangeRate,
onFilterChanged,
resourceFields,
selectedRows = [],
}) {
const onClickNewExchangeRate = useCallback(() => {
openDialog('exchangeRate-form', {});
}, [openDialog]);
const handelDeleteExchangeRate = useCallback(
(exchangeRate) => {
onDeleteExchangeRate(exchangeRate);
},
[selectedRows, onDeleteExchangeRate]
);
const [filterCount, setFilterCount] = useState(0);
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [
selectedRows,
]);
const onClickNewExchangeRate = () => {
openDialog('exchangeRate-form', {});
};
const filterDropdown = FilterDropdown({
fields: resourceFields,
@@ -51,13 +51,24 @@ function ExchangeRateActionsBar({
},
});
const handelDeleteExchangeRate = useCallback(
(exchangeRate) => {
onDeleteExchangeRate(exchangeRate);
},
[selectedRows, onDeleteExchangeRate]
);
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [
selectedRows,
]);
return (
<DashboardActionsBar>
<NavbarGroup>
<Button
className={Classes.MINIMAL}
icon={<Icon icon='plus' />}
text={<T id={'new_exchange_rate'}/>}
text={<T id={'new_exchange_rate'} />}
onClick={onClickNewExchangeRate}
/>
<Popover
@@ -69,7 +80,11 @@ function ExchangeRateActionsBar({
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={
filterCount <= 0 ? <T id={'filter'}/> : `${filterCount} filters applied`
filterCount <= 0 ? (
<T id={'filter'} />
) : (
`${filterCount} filters applied`
)
}
icon={<Icon icon='filter' />}
/>
@@ -78,7 +93,7 @@ function ExchangeRateActionsBar({
<Button
className={Classes.MINIMAL}
icon={<Icon icon='trash' iconSize={15} />}
text={<T id={'delete'}/>}
text={<T id={'delete'} />}
intent={Intent.DANGER}
onClick={handelDeleteExchangeRate}
/>
@@ -86,12 +101,12 @@ function ExchangeRateActionsBar({
<Button
className={Classes.MINIMAL}
icon={<Icon icon='file-import' />}
text={<T id={'import'}/>}
text={<T id={'import'} />}
/>
<Button
className={Classes.MINIMAL}
icon={<Icon icon='file-export' />}
text={<T id={'export'}/>}
text={<T id={'export'} />}
/>
</NavbarGroup>
</DashboardActionsBar>
@@ -106,7 +121,8 @@ const withExchangeRateActionBar = connect(mapStateToProps);
export default compose(
withExchangeRateActionBar,
DashboardConnect,
ExchangeRatesDialogConnect,
withResourceDetail
DialogConnect,
withResourceDetail(({ resourceFields }) => ({
resourceFields,
}))
)(ExchangeRateActionsBar);

View File

@@ -1,41 +1,40 @@
import React, { useCallback, useMemo } from 'react';
import React, { useCallback, useMemo,useState } from 'react';
import Icon from 'components/Icon';
import DialogConnect from 'connectors/Dialog.connector';
import LoadingIndicator from 'components/LoadingIndicator';
import DataTable from 'components/DataTable';
import { Button, Popover, Menu, MenuItem, Position } from '@blueprintjs/core';
import withExchangeRates from 'containers/FinancialStatements/ExchangeRates/withExchangeRates';
import withExchangeRatesActions from 'containers/FinancialStatements/ExchangeRates/withExchangeRatesActions';
import withExchangeRates from 'containers/FinancialStatements/ExchangeRates/withExchangeRates';
import { compose } from 'utils';
import { FormattedMessage as T, useIntl } from 'react-intl';
function ExchangeRateTable({
// #withExchangeRates
exchangeRatesList,
onFetchData,
exchangeRatesLoading,
// #withDialog.
openDialog,
// own properties
loading,
onFetchData,
onDeleteExchangeRate,
onEditExchangeRate,
onSelectedRowsChange,
}) {
const {formatMessage} = useIntl();
const [initialMount, setInitialMount] = useState(false);
const { formatMessage } = useIntl();
const handelEditExchangeRate = (exchange_rate) => () => {
openDialog('exchangeRate-form', { action: 'edit', id: exchange_rate.id });
onEditExchangeRate(exchange_rate.id);
};
// const handelEditExchangeRate = useCallback(
// (exchange_rate) => () => {
// openDialog('exchangeRate-form', { action: 'edit', id: exchange_rate.id });
// onEditExchangeRate(exchange_rate.id);
// },
// [openDialog]
// );
const handleDeleteExchangeRate = (exchange_rate) => () => {
onDeleteExchangeRate(exchange_rate);
@@ -45,36 +44,36 @@ function ExchangeRateTable({
(ExchangeRate) => (
<Menu>
<MenuItem
text={<T id={'edit_exchange_rate'}/>}
text={<T id={'edit_exchange_rate'} />}
onClick={handelEditExchangeRate(ExchangeRate)}
/>
<MenuItem
text={<T id={'delete_exchange_rate'}/>}
text={<T id={'delete_exchange_rate'} />}
onClick={handleDeleteExchangeRate(ExchangeRate)}
/>
</Menu>
),
[]
[handelEditExchangeRate, handleDeleteExchangeRate]
);
const columns = useMemo(
() => [
{
id: 'date',
Header: formatMessage({id:'date'}),
Header: formatMessage({ id: 'date' }),
// accessor: 'date',
width: 150,
},
{
id: 'currency_code',
Header: formatMessage({id:'currency_code'}),
Header: formatMessage({ id: 'currency_code' }),
accessor: 'currency_code',
className: 'currency_code',
width: 150,
},
{
id: 'exchange_rate',
Header: formatMessage({id:'exchange_rate'}),
Header: formatMessage({ id: 'exchange_rate' }),
accessor: 'exchange_rate',
className: 'exchange_rate',
width: 150,
@@ -126,6 +125,7 @@ function ExchangeRateTable({
columns={columns}
data={exchangeRatesList}
onFetchData={handelFetchData}
loading={exchangeRatesLoading && !initialMount}
manualSortBy={true}
selectionColumn={selectionColumn}
expandable={true}
@@ -139,5 +139,8 @@ function ExchangeRateTable({
export default compose(
DialogConnect,
withExchangeRatesActions,
withExchangeRates
withExchangeRates(({ exchangeRatesList ,exchangeRatesLoading }) => ({
exchangeRatesList,
exchangeRatesLoading
}))
)(ExchangeRateTable);

View File

@@ -0,0 +1,32 @@
import { connect } from 'react-redux';
import { compose } from 'utils';
import DialogConnect from 'connectors/Dialog.connector';
import DialogReduxConnect from 'components/DialogReduxConnect';
import {getDialogPayload} from 'store/dashboard/dashboard.reducer';
import withExchangeRatesActions from 'containers/FinancialStatements/ExchangeRates/withExchangeRatesActions';
import withExchangeRates from 'containers/FinancialStatements/ExchangeRates/withExchangeRates';
import CurrencyFromDialogConnect from 'connectors/CurrencyFromDialog.connect'
export const mapStateToProps = (state, props) => {
const dialogPayload = getDialogPayload(state, 'exchangeRate-form');
return {
name: 'exchangeRate-form',
payload: { action: 'new', id: null, ...dialogPayload },
editExchangeRate:
dialogPayload && dialogPayload.action === 'edit'
? state.exchangeRates.exchangeRates[dialogPayload.id]
: {},
};
};
const ExchangeRatesDialogConnect = connect(mapStateToProps);
export default compose(
CurrencyFromDialogConnect,
ExchangeRatesDialogConnect,
withExchangeRatesActions,
withExchangeRates(({ exchangeRatesList }) => ({
exchangeRatesList
})),
DialogReduxConnect,
DialogConnect
);

View File

@@ -1,8 +1,14 @@
import { connect } from 'react-redux';
import { getResourceViews } from 'store/customViews/customViews.selectors';
const mapStateToProps = (state, props) => ({
exchangeRatesList: Object.values(state.exchangeRates.exchangeRates),
});
export default (mapState) => {
const mapStateToProps = (state, props) => {
const mapped = {
exchangeRatesList: Object.values(state.exchangeRates.exchangeRates),
exchangeRatesLoading: state.exchangeRates.loading,
};
return mapState ? mapState(mapped, state, props) : mapped;
};
export default connect(mapStateToProps);
return connect(mapStateToProps);
};

View File

@@ -1,6 +1,6 @@
import React, { useEffect, useState, useCallback } from 'react';
import { useParams } from 'react-router-dom';
import useAsync from 'hooks/async';
import { useQuery } from 'react-query';
import DashboardInsider from 'components/Dashboard/DashboardInsider';
import ItemCategoriesDataTable from 'containers/Items/ItemCategoriesTable';
@@ -8,40 +8,46 @@ import ItemsCategoryActionsBar from 'containers/Items/ItemsCategoryActionsBar';
import withDashboardActions from 'containers/Dashboard/withDashboard';
import withItemCategoriesActions from 'containers/Items/withItemCategoriesActions';
import withItemCategories from 'containers/Items/withItemCategories';
import { compose } from 'utils';
import { FormattedMessage as T, useIntl } from 'react-intl';
const ItemCategoryList = ({
// #withDashboardActions
changePageTitle,
// #withItemCategoriesActions
requestFetchItemCategories,
}) => {
const { id } = useParams();
const [selectedRows, setSelectedRows] = useState([]);
const {formatMessage} =useIntl()
useEffect(() => {
id
? changePageTitle('Edit Category Details')
: changePageTitle('Category List');
? changePageTitle(formatMessage({id:'edit_category_details'}))
: changePageTitle(formatMessage({id:'category_list'}));
}, []);
const fetchCategories = useAsync(() => {
return Promise.all([
requestFetchItemCategories(),
]);
});
const fetchCategories = useQuery('items-categories-table',
() => { requestFetchItemCategories(); });
const handleFilterChanged = useCallback(() => {
}, []);
// Handle selected rows change.
const handleSelectedRowsChange = useCallback((itemCategories) => {
setSelectedRows(itemCategories);
}, [setSelectedRows]);
return (
<DashboardInsider name={'item-category-list'}>
<ItemsCategoryActionsBar
onFilterChanged={handleFilterChanged}
selectedRows={selectedRows} />
<ItemCategoriesDataTable />
<ItemCategoriesDataTable
onSelectedRowsChange={handleSelectedRowsChange} />
</DashboardInsider>
);
};
@@ -49,5 +55,4 @@ const ItemCategoryList = ({
export default compose(
withDashboardActions,
withItemCategoriesActions,
withItemCategories,
)(ItemCategoryList);

View File

@@ -10,6 +10,7 @@ import withAccountsActions from 'containers/Accounts/withAccountsActions';
import withItemCategoriesActions from 'containers/Items/withItemCategoriesActions';
import { compose } from 'utils';
import { FormattedMessage as T, useIntl } from 'react-intl';
const ItemFormContainer = ({
@@ -23,11 +24,11 @@ const ItemFormContainer = ({
requestFetchItemCategories,
}) => {
const { id } = useParams();
const {formatMessage} =useIntl()
useEffect(() => {
id ?
changePageTitle('Edit Item Details') :
changePageTitle('New Item');
changePageTitle(formatMessage({id:'edit_item_details'})) :
changePageTitle(formatMessage({id:'new_item'}));
}, [id, changePageTitle]);
const fetchAccounts = useQuery('accounts-list',

View File

@@ -1,6 +1,7 @@
import React, {useState, useEffect, useCallback, useMemo} from 'react';
import { useFormik } from "formik";
import {useIntl} from 'react-intl';
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { useFormik } from 'formik';
import { FormattedMessage as T, useIntl } from 'react-intl';
import { useParams, useHistory } from 'react-router-dom';
import {
InputGroup,
@@ -13,26 +14,24 @@ import {
Menu,
H5,
H6,
} from "@blueprintjs/core";
import {Row, Col} from 'react-grid-system';
} from '@blueprintjs/core';
import { Row, Col } from 'react-grid-system';
import { ReactSortable } from 'react-sortablejs';
import * as Yup from 'yup';
import {pick, get} from 'lodash';
import { pick, get } from 'lodash';
import Icon from 'components/Icon';
import ErrorMessage from 'components/ErrorMessage';
import AppToaster from 'components/AppToaster';
import { If } from 'components';
import ViewFormContainer from 'containers/Views/ViewForm.container.js';
function ViewForm({
function ViewForm({
requestSubmitView,
requestEditView,
onDelete,
viewId,
viewMeta,
viewItem,
resourceName,
resourceColumns,
@@ -52,20 +51,30 @@ function ViewForm({
}, []);
const [draggedColumns, setDraggedColumn] = useState([
...(viewMeta && viewMeta.columns) ? viewMeta.columns : []
...(viewMeta && viewMeta.columns ? viewMeta.columns : []),
]);
const draggedColumnsIds = useMemo(() => draggedColumns.map((c) => c.id), [
draggedColumns,
]);
const draggedColumnsIds = useMemo(() => draggedColumns.map(c => c.id), [draggedColumns]);
const [availableColumns, setAvailableColumns] = useState([
...(viewMeta && viewMeta.columns) ? resourceColumns.filter((column) =>
draggedColumnsIds.indexOf(column.id) === -1
) : resourceColumns,
...(viewMeta && viewMeta.columns
? resourceColumns.filter(
(column) => draggedColumnsIds.indexOf(column.id) === -1
)
: resourceColumns),
]);
const defaultViewRole = useMemo(() => ({
field_key: '', comparator: '', value: '', index: 1,
}), []);
const defaultViewRole = useMemo(
() => ({
field_key: '',
comparator: '',
value: '',
index: 1,
}),
[]
);
const validationSchema = Yup.object().shape({
resource_name: Yup.string().required(),
@@ -83,27 +92,33 @@ function ViewForm({
Yup.object().shape({
key: Yup.string().required(),
index: Yup.string().required(),
}),
})
),
});
const initialEmptyForm = useMemo(() => ({
resource_name: resourceName || '',
name: '',
logic_expression: '',
roles: [
defaultViewRole,
],
columns: [],
}), [defaultViewRole, resourceName]);
const initialEmptyForm = useMemo(
() => ({
resource_name: resourceName || '',
name: '',
logic_expression: '',
roles: [defaultViewRole],
columns: [],
}),
[defaultViewRole, resourceName]
);
const initialForm = useMemo(() => ({
...initialEmptyForm,
...viewMeta ? {
...viewMeta,
resource_name: viewMeta.resource?.name || resourceName,
} : {},
}), [initialEmptyForm, viewMeta, resourceName]);
const initialForm = useMemo(
() => ({
...initialEmptyForm,
...(viewMeta
? {
...viewMeta,
resource_name: viewMeta.resource?.name || resourceName,
}
: {}),
}),
[initialEmptyForm, viewMeta, resourceName]
);
const {
values,
@@ -136,7 +151,9 @@ function ViewForm({
message: 'the_view_has_been_edited',
intent: Intent.SUCCESS,
});
history.push(`${resourceMetadata.baseRoute}/${viewMeta.id}/custom_view`);
history.push(
`${resourceMetadata.baseRoute}/${viewMeta.id}/custom_view`
);
setSubmitting(false);
});
} else {
@@ -145,7 +162,9 @@ function ViewForm({
message: 'the_view_has_been_submit',
intent: Intent.SUCCESS,
});
history.push(`${resourceMetadata.baseRoute}/${viewMeta.id}/custom_view`);
history.push(
`${resourceMetadata.baseRoute}/${viewMeta.id}/custom_view`
);
setSubmitting(false);
});
}
@@ -153,39 +172,55 @@ function ViewForm({
});
useEffect(() => {
setFieldValue('columns',
setFieldValue(
'columns',
draggedColumns.map((column, index) => ({
index, key: column.key,
})));
index,
key: column.key,
}))
);
}, [setFieldValue, draggedColumns]);
const conditionalsItems = useMemo(() => ([
{ value: 'and', label: 'AND' },
{ value: 'or', label: 'OR' },
]), []);
const conditionalsItems = useMemo(
() => [
{ value: 'and', label: 'AND' },
{ value: 'or', label: 'OR' },
],
[]
);
const whenConditionalsItems = useMemo(() => ([
{ value: '', label: 'When' },
]), []);
const whenConditionalsItems = useMemo(
() => [{ value: '', label: 'When' }],
[]
);
// Compatotors items.
const compatatorsItems = useMemo(() => ([
{value: '', label: 'Compatator'},
{value: 'equals', label: 'Equals'},
{value: 'not_equal', label: 'Not Equal'},
{value: 'contain', label: 'Contain'},
{value: 'not_contain', label: 'Not Contain'},
]), []);
const compatatorsItems = useMemo(
() => [
{ value: '', label: 'Compatator' },
{ value: 'equals', label: 'Equals' },
{ value: 'not_equal', label: 'Not Equal' },
{ value: 'contain', label: 'Contain' },
{ value: 'not_contain', label: 'Not Contain' },
],
[]
);
// Resource fields.
const resourceFieldsOptions = useMemo(() => ([
{value: '', label: 'Select a field'},
...resourceFields.map((field) => ({ value: field.key, label: field.label_name, })),
]), [resourceFields]);
const resourceFieldsOptions = useMemo(
() => [
{ value: '', label: 'Select a field' },
...resourceFields.map((field) => ({
value: field.key,
label: field.label_name,
})),
],
[resourceFields]
);
// Account item of select accounts field.
const selectItem = (item, { handleClick, modifiers, query }) => {
return (<MenuItem text={item.label} key={item.key} onClick={handleClick} />)
return <MenuItem text={item.label} key={item.key} onClick={handleClick} />;
};
// Handle click new condition button.
const onClickNewRole = useCallback(() => {
@@ -194,219 +229,273 @@ function ViewForm({
{
...defaultViewRole,
index: values.roles.length + 1,
}
},
]);
}, [defaultViewRole, setFieldValue, values]);
// Handle click remove view role button.
const onClickRemoveRole = useCallback((viewRole, index) => {
let viewRoles = [...values.roles];
const onClickRemoveRole = useCallback(
(viewRole, index) => {
let viewRoles = [...values.roles];
// Can't continue if view roles equals or less than 1.
if (viewRoles.length > 1) {
viewRoles.splice(index, 1);
// Can't continue if view roles equals or less than 1.
if (viewRoles.length > 1) {
viewRoles.splice(index, 1);
setFieldValue(
'roles',
viewRoles.map((role) => {
return role;
})
);
}
},
[values, setFieldValue]
);
setFieldValue('roles', viewRoles.map((role) => {
return role;
}));
}
}, [values, setFieldValue]);
const onClickDeleteView = useCallback(() => {
onDelete && onDelete(viewMeta);
}, [onDelete, viewMeta]);
const hasError = (path) => get(errors, path) && get(touched, path);
const hasError = (path) => get(errors, path) && get(touched, path);
const handleClickCancelBtn = () => {
history.goBack();
};
return (
<div class="view-form">
<div class='view-form'>
<form onSubmit={handleSubmit}>
<div class="view-form--name-section">
<div class='view-form--name-section'>
<Row>
<Col sm={8}>
<FormGroup
label={intl.formatMessage({'id': 'View Name'})}
label={<T id={'view_name'} />}
className={'form-group--name'}
intent={(errors.name && touched.name) && Intent.DANGER}
helperText={<ErrorMessage {...{errors, touched}} name={'name'} />}
intent={errors.name && touched.name && Intent.DANGER}
helperText={
<ErrorMessage {...{ errors, touched }} name={'name'} />
}
inline={true}
fill={true}>
fill={true}
>
<InputGroup
intent={(errors.name && touched.name) && Intent.DANGER}
intent={errors.name && touched.name && Intent.DANGER}
fill={true}
{...getFieldProps('name')} />
{...getFieldProps('name')}
/>
</FormGroup>
</Col>
</Row>
</div>
<H5 className="mb2">Define the conditionals</H5>
<H5 className='mb2'>Define the conditionals</H5>
{values.roles.map((role, index) => (
<Row class="view-form__role-conditional">
<Col sm={2} class="flex">
<div class="mr2 pt1 condition-number">{ index + 1 }</div>
{(index === 0) ? (
<HTMLSelect options={whenConditionalsItems} className={Classes.FILL} />
<Row class='view-form__role-conditional'>
<Col sm={2} class='flex'>
<div class='mr2 pt1 condition-number'>{index + 1}</div>
{index === 0 ? (
<HTMLSelect
options={whenConditionalsItems}
className={Classes.FILL}
/>
) : (
<HTMLSelect options={conditionalsItems} className={Classes.FILL} />
<HTMLSelect
options={conditionalsItems}
className={Classes.FILL}
/>
)}
</Col>
<Col sm={2}>
<FormGroup
intent={hasError(`roles[${index}].field_key`) && Intent.DANGER}>
intent={hasError(`roles[${index}].field_key`) && Intent.DANGER}
>
<HTMLSelect
options={resourceFieldsOptions}
value={role.field_key}
className={Classes.FILL}
{...getFieldProps(`roles[${index}].field_key`)} />
{...getFieldProps(`roles[${index}].field_key`)}
/>
</FormGroup>
</Col>
<Col sm={2}>
<FormGroup
intent={hasError(`roles[${index}].comparator`) && Intent.DANGER}>
intent={hasError(`roles[${index}].comparator`) && Intent.DANGER}
>
<HTMLSelect
options={compatatorsItems}
value={role.comparator}
className={Classes.FILL}
{...getFieldProps(`roles[${index}].comparator`)} />
{...getFieldProps(`roles[${index}].comparator`)}
/>
</FormGroup>
</Col>
<Col sm={5} class="flex">
<Col sm={5} class='flex'>
<FormGroup
intent={hasError(`roles[${index}].value`) && Intent.DANGER}>
intent={hasError(`roles[${index}].value`) && Intent.DANGER}
>
<InputGroup
placeholder={intl.formatMessage({'id': 'value'})}
{...getFieldProps(`roles[${index}].value`)} />
placeholder={intl.formatMessage({ id: 'value' })}
{...getFieldProps(`roles[${index}].value`)}
/>
</FormGroup>
<Button
icon={<Icon icon="times-circle" iconSize={14} />}
<Button
icon={<Icon icon='times-circle' iconSize={14} />}
iconSize={14}
className="ml2"
minimal={true}
className='ml2'
minimal={true}
intent={Intent.DANGER}
onClick={() => onClickRemoveRole(role, index)} />
onClick={() => onClickRemoveRole(role, index)}
/>
</Col>
</Row>
))}
<div className={'view-form__role-conditions-actions'}>
<Button
minimal={true}
intent={Intent.PRIMARY}
onClick={onClickNewRole}>
New Conditional
</Button>
</div>
<div className={'view-form__role-conditions-actions'}>
<Button
minimal={true}
intent={Intent.PRIMARY}
onClick={onClickNewRole}
>
<T id={'new_conditional'} />
</Button>
</div>
<div class="view-form--logic-expression-section">
<Row>
<Col sm={8}>
<FormGroup
label={intl.formatMessage({'id': 'Logic Expression'})}
className={'form-group--logic-expression'}
intent={(errors.logic_expression && touched.logic_expression) && Intent.DANGER}
helperText={<ErrorMessage {...{errors, touched}} name='logic_expression' />}
inline={true}
fill={true}>
<div class='view-form--logic-expression-section'>
<Row>
<Col sm={8}>
<FormGroup
label={intl.formatMessage({ id: 'Logic Expression' })}
className={'form-group--logic-expression'}
intent={
errors.logic_expression &&
touched.logic_expression &&
Intent.DANGER
}
helperText={
<ErrorMessage
{...{ errors, touched }}
name='logic_expression'
/>
}
inline={true}
fill={true}
>
<InputGroup
intent={
errors.logic_expression &&
touched.logic_expression &&
Intent.DANGER
}
fill={true}
{...getFieldProps('logic_expression')}
/>
</FormGroup>
</Col>
</Row>
</div>
<H5 className={'mb2'}>Columns Preferences</H5>
<div class='dragable-columns'>
<Row gutterWidth={14}>
<Col sm={4} className='dragable-columns__column'>
<H6 className='dragable-columns__title'>Available Columns</H6>
<InputGroup
intent={(errors.logic_expression && touched.logic_expression) && Intent.DANGER}
fill={true}
{...getFieldProps('logic_expression')} />
</FormGroup>
</Col>
</Row>
</div>
placeholder={intl.formatMessage({ id: 'search' })}
leftIcon='search'
/>
<H5 className={'mb2'}>Columns Preferences</H5>
<div class="dragable-columns">
<Row gutterWidth={14}>
<Col sm={4} className="dragable-columns__column">
<H6 className="dragable-columns__title">Available Columns</H6>
<div class='dragable-columns__items'>
<Menu>
<ReactSortable
list={availableColumns}
setList={setAvailableColumns}
group='shared-group-name'
>
{availableColumns.map((field) => (
<MenuItem key={field.id} text={field.label} />
))}
</ReactSortable>
</Menu>
</div>
</Col>
<InputGroup
placeholder={intl.formatMessage({id: 'search'})}
leftIcon="search" />
<Col sm={1}>
<div class='dragable-columns__arrows'>
<div>
<Icon
icon='arrow-circle-left'
iconSize={30}
color='#cecece'
/>
</div>
<div class='mt2'>
<Icon
icon='arrow-circle-right'
iconSize={30}
color='#cecece'
/>
</div>
</div>
</Col>
<div class="dragable-columns__items">
<Menu>
<ReactSortable
list={availableColumns}
setList={setAvailableColumns}
group="shared-group-name">
{availableColumns.map((field) => (
<MenuItem key={field.id} text={field.label} />
))}
</ReactSortable>
</Menu>
</div>
</Col>
<Col sm={4} className='dragable-columns__column'>
<H6 className='dragable-columns__title'>Selected Columns</H6>
<InputGroup
placeholder={intl.formatMessage({ id: 'search' })}
leftIcon='search'
/>
<Col sm={1}>
<div class="dragable-columns__arrows">
<div><Icon icon="arrow-circle-left" iconSize={30} color="#cecece" /></div>
<div class="mt2"><Icon icon="arrow-circle-right" iconSize={30} color="#cecece" /></div>
</div>
</Col>
<div class='dragable-columns__items'>
<Menu>
<ReactSortable
list={draggedColumns}
setList={setDraggedColumn}
group='shared-group-name'
>
{draggedColumns.map((field) => (
<MenuItem key={field.id} text={field.label} />
))}
</ReactSortable>
</Menu>
</div>
</Col>
</Row>
</div>
<Col sm={4} className="dragable-columns__column">
<H6 className="dragable-columns__title">Selected Columns</H6>
<InputGroup placeholder={intl.formatMessage({id: 'search'})} leftIcon="search" />
<div class="dragable-columns__items">
<Menu>
<ReactSortable
list={draggedColumns}
setList={setDraggedColumn}
group="shared-group-name">
{draggedColumns.map((field) => (
<MenuItem key={field.id} text={field.label} />
))}
</ReactSortable>
</Menu>
</div>
</Col>
</Row>
</div>
<div class="form__floating-footer">
<Button
intent={Intent.PRIMARY}
type="submit"
disabled={isSubmitting}>
Submit
</Button>
<Button
intent={Intent.NONE}
className="ml1"
onClick={handleClickCancelBtn}>
Cancel
</Button>
<If condition={viewMeta && viewMeta.id}>
<Button
intent={Intent.DANGER}
onClick={onClickDeleteView}
className={"right mr2"}>
Delete
<div class='form__floating-footer'>
<Button intent={Intent.PRIMARY} type='submit' disabled={isSubmitting}>
<T id={'submit'} />
</Button>
</If>
</div>
</form>
</div>
<Button
intent={Intent.NONE}
className='ml1'
onClick={handleClickCancelBtn}
>
<T id={'cancel'} />
</Button>
<If condition={viewMeta && viewMeta.id}>
<Button
intent={Intent.DANGER}
onClick={onClickDeleteView}
className={'right mr2'}
>
<T id={'delete'} />
</Button>
</If>
</div>
</form>
</div>
);
}
export default ViewFormContainer(ViewForm);
export default ViewFormContainer(ViewForm);

View File

@@ -5,14 +5,17 @@ import { Intent, Alert } from '@blueprintjs/core';
import DashboardInsider from 'components/Dashboard/DashboardInsider';
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
import ViewForm from 'containers/Views/ViewForm';
import withResourcesActions from 'containers/Resources/withResourcesActions';
import withViewsActions from 'containers/Views/withViewsActions';
import withDashboard from 'containers/Dashboard/withDashboard';
import AppToaster from 'components/AppToaster';
import {compose} from 'utils';
import { If } from 'components';
import { FormattedMessage as T, useIntl } from 'react-intl';
import withResourcesActions from 'containers/Resources/withResourcesActions';
import withViewsActions from 'containers/Views/withViewsActions';
import withDashboard from 'containers/Dashboard/withDashboard';
// @flow
function ViewFormPage({
changePageTitle,
@@ -27,6 +30,7 @@ function ViewFormPage({
}) {
const { resource_slug: resourceSlug, view_id: viewId } = useParams();
const [stateDeleteView, setStateDeleteView] = useState(null);
const {formatMessage} =useIntl()
const fetchHook = useAsync(async () => {
return Promise.all([
@@ -44,9 +48,9 @@ function ViewFormPage({
useEffect(() => {
if (viewId) {
changePageTitle('Edit Custom View');
changePageTitle(formatMessage({id:'edit_custom_view'}));
} else {
changePageTitle('New Custom View');
changePageTitle(formatMessage({id:'new_custom_view'}));
}
return () => {
changePageTitle('');

View File

@@ -149,7 +149,22 @@ bulk_update:'Bulk Update',
all_accounts:'All accounts',
go_to_bigcapital_com:'← Go to bigcapital.com',
currency:'Currency',
new_conditional:'+ New Conditional'
new_conditional:'+ New Conditional',
chart_of_accounts:'Chart of Accounts',
exchange_rate_details:'Exchange Rate Details',
exchange_rate_list:'Exchange Rate List',
manual_journals:'Manual Journals',
edit_expense_details:'Edit Expense Details',
expenses_list:'Expenses List',
edit_category_details:'Edit Category Details',
category_list:'Category List',
edit_item_details:'Edit Item Details',
items_list:'Items List',
edit_custom_view:'Edit Custom View',
new_custom_view:'New Custom View',
view_name:'View Name',
new_conditional:'New Conditional'

View File

@@ -7,6 +7,10 @@ export const fetchExchangeRates = () => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_LOADING,
});
dispatch({
type: t.EXCHANGE_RATE_TABLE_LOADING,
loading: true,
});
ApiService.get('exchange_rates')
.then((response) => {
dispatch({
@@ -16,6 +20,10 @@ export const fetchExchangeRates = () => {
dispatch({
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
});
dispatch({
type: t.EXCHANGE_RATE_TABLE_LOADING,
loading: false,
});
resolve(response);
})
.catch((error) => {

View File

@@ -17,4 +17,7 @@ export default createReducer(initialState, {
..._exchangeRates,
};
},
[t.EXCHANGE_RATE_TABLE_LOADING]: (state, action) => {
state.loading = action.loading;
},
});

View File

@@ -4,4 +4,5 @@ export default {
EXCHANGE_RATE_LIST_SET: 'EXCHANGE_RATE_LIST_SET',
CLEAR_EXCHANGE_RATE_FORM_ERRORS: 'CLEAR_EXCHANGE_RATE_FORM_ERRORS',
ExchangeRates_TABLE_QUERIES_ADD: 'ExchangeRates_TABLE_QUERIES_ADD',
EXCHANGE_RATE_TABLE_LOADING:'EXCHANGE_RATE_TABLE_LOADING'
};