mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 06:40:31 +00:00
refactoring: migrating to react-query to manage service-side state.
This commit is contained in:
@@ -1,21 +1,18 @@
|
||||
import React, { useMemo, useCallback, useState } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import Icon from 'components/Icon';
|
||||
import {
|
||||
Button,
|
||||
NavbarGroup,
|
||||
Classes,
|
||||
NavbarDivider,
|
||||
MenuItem,
|
||||
Menu,
|
||||
Popover,
|
||||
PopoverInteractionKind,
|
||||
Position,
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import classNames from 'classnames';
|
||||
import { useRouteMatch, useHistory } from 'react-router-dom';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import FilterDropdown from 'components/FilterDropdown';
|
||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
||||
@@ -23,8 +20,7 @@ import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
|
||||
import { If, DashboardActionViewsList } from 'components';
|
||||
|
||||
import withResourceDetail from 'containers/Resources/withResourceDetails';
|
||||
import withExpenses from 'containers/Expenses/withExpenses';
|
||||
import { useExpensesListContext } from './ExpensesListProvider';
|
||||
import withExpensesActions from 'containers/Expenses/withExpensesActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
@@ -33,53 +29,24 @@ import { compose } from 'utils';
|
||||
* Expenses actions bar.
|
||||
*/
|
||||
function ExpensesActionsBar({
|
||||
// #withResourceDetail
|
||||
resourceFields,
|
||||
|
||||
//#withExpenses
|
||||
expensesViews,
|
||||
|
||||
//#withExpensesActions
|
||||
addExpensesTableQueries,
|
||||
changeExpensesView,
|
||||
|
||||
onFilterChanged,
|
||||
selectedRows,
|
||||
onBulkDelete,
|
||||
}) {
|
||||
const [filterCount, setFilterCount] = useState(0);
|
||||
const history = useHistory();
|
||||
|
||||
const { expensesViews } = useExpensesListContext();
|
||||
|
||||
const onClickNewExpense = useCallback(() => {
|
||||
history.push('/expenses/new');
|
||||
}, [history]);
|
||||
|
||||
const filterDropdown = FilterDropdown({
|
||||
initialCondition: {
|
||||
fieldKey: 'reference_no',
|
||||
compatator: 'contains',
|
||||
value: '',
|
||||
},
|
||||
fields: resourceFields,
|
||||
onFilterChange: (filterConditions) => {
|
||||
addExpensesTableQueries({
|
||||
filter_roles: filterConditions || '',
|
||||
});
|
||||
onFilterChanged && onFilterChanged(filterConditions);
|
||||
},
|
||||
});
|
||||
|
||||
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [
|
||||
selectedRows,
|
||||
]);
|
||||
|
||||
// Handle delete button click.
|
||||
const handleBulkDelete = useCallback(() => {
|
||||
onBulkDelete && onBulkDelete(selectedRows.map((r) => r.id));
|
||||
}, [onBulkDelete, selectedRows]);
|
||||
const handleBulkDelete = () => {
|
||||
|
||||
};
|
||||
|
||||
const handleTabChange = (viewId) => {
|
||||
changeExpensesView(viewId.id || -1);
|
||||
addExpensesTableQueries({
|
||||
custom_view_id: viewId.id || null,
|
||||
});
|
||||
@@ -93,6 +60,7 @@ function ExpensesActionsBar({
|
||||
onChange={handleTabChange}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="plus" />}
|
||||
@@ -101,7 +69,7 @@ function ExpensesActionsBar({
|
||||
/>
|
||||
<Popover
|
||||
minimal={true}
|
||||
content={filterDropdown}
|
||||
content={''}
|
||||
interactionKind={PopoverInteractionKind.CLICK}
|
||||
position={Position.BOTTOM_LEFT}
|
||||
>
|
||||
@@ -114,7 +82,7 @@ function ExpensesActionsBar({
|
||||
/>
|
||||
</Popover>
|
||||
|
||||
<If condition={hasSelectedRows}>
|
||||
<If condition={false}>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||
@@ -144,20 +112,7 @@ function ExpensesActionsBar({
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
resourceName: 'expenses',
|
||||
});
|
||||
|
||||
const withExpensesActionsBar = connect(mapStateToProps);
|
||||
|
||||
export default compose(
|
||||
withExpensesActionsBar,
|
||||
withDialogActions,
|
||||
withResourceDetail(({ resourceFields }) => ({
|
||||
resourceFields,
|
||||
})),
|
||||
withExpenses(({ expensesViews }) => ({
|
||||
expensesViews,
|
||||
})),
|
||||
withExpensesActions,
|
||||
)(ExpensesActionsBar);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useCallback, useMemo } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import {
|
||||
Intent,
|
||||
Button,
|
||||
@@ -11,17 +11,17 @@ import {
|
||||
Position,
|
||||
Tag,
|
||||
} from '@blueprintjs/core';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { withRouter } from 'react-router';
|
||||
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import moment from 'moment';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import Icon from 'components/Icon';
|
||||
import { compose, saveInvoke } from 'utils';
|
||||
import { useIsValuePassed } from 'hooks';
|
||||
|
||||
import { If, Money, Choose, LoadingIndicator } from 'components';
|
||||
import { useExpensesListContext } from './ExpensesListProvider';
|
||||
|
||||
import { If, Money, Choose } from 'components';
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
import DataTable from 'components/DataTable';
|
||||
@@ -29,54 +29,26 @@ import ExpensesEmptyStatus from './ExpensesEmptyStatus';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withViewDetails from 'containers/Views/withViewDetails';
|
||||
import withExpenses from 'containers/Expenses/withExpenses';
|
||||
import withExpensesActions from 'containers/Expenses/withExpensesActions';
|
||||
import withCurrentView from 'containers/Views/withCurrentView';
|
||||
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
|
||||
/**
|
||||
* Expenses datatable.
|
||||
*/
|
||||
function ExpensesDataTable({
|
||||
// #withExpenes
|
||||
expensesCurrentPage,
|
||||
expensesLoading,
|
||||
expensesPagination,
|
||||
expensesTableQuery,
|
||||
expensesCurrentViewId,
|
||||
|
||||
// #withExpensesActions
|
||||
addExpensesTableQueries,
|
||||
|
||||
// #withDashboardActions
|
||||
changeCurrentView,
|
||||
changePageSubtitle,
|
||||
setTopbarEditView,
|
||||
|
||||
// #withView
|
||||
viewMeta,
|
||||
|
||||
|
||||
// #ownProps
|
||||
onEditExpense,
|
||||
onDeleteExpense,
|
||||
onPublishExpense,
|
||||
onSelectedRowsChange,
|
||||
}) {
|
||||
const { custom_view_id: customViewId } = useParams();
|
||||
const isLoadedBefore = useIsValuePassed(expensesLoading, false);
|
||||
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
useEffect(() => {
|
||||
if (customViewId) {
|
||||
changeCurrentView(customViewId);
|
||||
setTopbarEditView(customViewId);
|
||||
}
|
||||
changePageSubtitle(customViewId && viewMeta ? viewMeta.name : '');
|
||||
}, [
|
||||
customViewId,
|
||||
changeCurrentView,
|
||||
changePageSubtitle,
|
||||
setTopbarEditView,
|
||||
viewMeta,
|
||||
]);
|
||||
const { expenses, isExpensesLoading } = useExpensesListContext();
|
||||
|
||||
// Handle fetch data of manual jouranls datatable.
|
||||
const handleFetchData = useCallback(
|
||||
@@ -187,7 +159,9 @@ function ExpensesDataTable({
|
||||
{
|
||||
id: 'total_amount',
|
||||
Header: formatMessage({ id: 'full_amount' }),
|
||||
accessor: (r) => <Money amount={r.total_amount} currency={r.currency_code} />,
|
||||
accessor: (r) => (
|
||||
<Money amount={r.total_amount} currency={r.currency_code} />
|
||||
),
|
||||
className: 'total_amount',
|
||||
width: 150,
|
||||
},
|
||||
@@ -270,64 +244,42 @@ function ExpensesDataTable({
|
||||
[onSelectedRowsChange],
|
||||
);
|
||||
|
||||
const showEmptyStatus = [
|
||||
expensesCurrentViewId === -1,
|
||||
expensesCurrentPage.length === 0,
|
||||
].every((condition) => condition === true);
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<LoadingIndicator loading={expensesLoading && !isLoadedBefore}>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<ExpensesEmptyStatus />
|
||||
</Choose.When>
|
||||
<Choose>
|
||||
<Choose.When condition={false}>
|
||||
<ExpensesEmptyStatus />
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={expensesCurrentPage}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
onFetchData={handleFetchData}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={expensesPagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
initialPageSize={expensesTableQuery.page_size}
|
||||
initialPageIndex={expensesTableQuery.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={expenses}
|
||||
loading={isExpensesLoading}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
onFetchData={handleFetchData}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
pagination={true}
|
||||
// pagesCount={expensesPagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
// initialPageSize={expensesTableQuery.page_size}
|
||||
// initialPageIndex={expensesTableQuery.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withRouter,
|
||||
withCurrentView,
|
||||
withDialogActions,
|
||||
withDashboardActions,
|
||||
withExpensesActions,
|
||||
withExpenses(
|
||||
({
|
||||
expensesCurrentPage,
|
||||
expensesLoading,
|
||||
expensesPagination,
|
||||
expensesTableQuery,
|
||||
expensesCurrentViewId,
|
||||
}) => ({
|
||||
expensesCurrentPage,
|
||||
expensesLoading,
|
||||
expensesPagination,
|
||||
expensesTableQuery,
|
||||
expensesCurrentViewId,
|
||||
}),
|
||||
),
|
||||
withViewDetails(),
|
||||
)(ExpensesDataTable);
|
||||
|
||||
@@ -29,10 +29,7 @@ export default function ExpenseFloatingFooter({
|
||||
const { submitForm, resetForm } = useFormikContext();
|
||||
|
||||
const handleSubmitPublishBtnClick = (event) => {
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: true,
|
||||
publish: true,
|
||||
});
|
||||
saveInvoke(onSubmitClick, event, { redirect: true, publish: true});
|
||||
};
|
||||
|
||||
const handleSubmitPublishAndNewBtnClick = (event) => {
|
||||
@@ -46,17 +43,11 @@ export default function ExpenseFloatingFooter({
|
||||
|
||||
const handleSubmitPublishContinueEditingBtnClick = (event) => {
|
||||
submitForm();
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: false,
|
||||
publish: true,
|
||||
});
|
||||
saveInvoke(onSubmitClick, event, { redirect: false, publish: true });
|
||||
};
|
||||
|
||||
const handleSubmitDraftBtnClick = (event) => {
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: true,
|
||||
publish: false,
|
||||
});
|
||||
saveInvoke(onSubmitClick, event, { redirect: true, publish: false });
|
||||
};
|
||||
|
||||
const handleSubmitDraftAndNewBtnClick = (event) => {
|
||||
@@ -70,10 +61,7 @@ export default function ExpenseFloatingFooter({
|
||||
|
||||
const handleSubmitDraftContinueEditingBtnClick = (event) => {
|
||||
submitForm();
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: false,
|
||||
publish: false,
|
||||
});
|
||||
saveInvoke(onSubmitClick, event, { redirect: false, publish: false });
|
||||
};
|
||||
|
||||
const handleCancelBtnClick = (event) => {
|
||||
@@ -81,9 +69,9 @@ export default function ExpenseFloatingFooter({
|
||||
};
|
||||
|
||||
const handleClearBtnClick = (event) => {
|
||||
// saveInvoke(onClearClick, event);
|
||||
resetForm();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
|
||||
{/* ----------- Save And Publish ----------- */}
|
||||
@@ -92,7 +80,6 @@ export default function ExpenseFloatingFooter({
|
||||
<Button
|
||||
disabled={isSubmitting}
|
||||
intent={Intent.PRIMARY}
|
||||
type="submit"
|
||||
onClick={handleSubmitPublishBtnClick}
|
||||
text={<T id={'save_publish'} />}
|
||||
/>
|
||||
@@ -125,7 +112,6 @@ export default function ExpenseFloatingFooter({
|
||||
<Button
|
||||
disabled={isSubmitting}
|
||||
className={'ml1'}
|
||||
type="submit"
|
||||
onClick={handleSubmitDraftBtnClick}
|
||||
text={<T id={'save_as_draft'} />}
|
||||
/>
|
||||
@@ -159,7 +145,6 @@ export default function ExpenseFloatingFooter({
|
||||
<Button
|
||||
disabled={isSubmitting}
|
||||
intent={Intent.PRIMARY}
|
||||
type="submit"
|
||||
onClick={handleSubmitPublishBtnClick}
|
||||
text={<T id={'save'} />}
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useMemo, useEffect,useState,useCallback } from 'react';
|
||||
import React, { useMemo, useEffect, useState, useCallback } from 'react';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { defaultTo, pick } from 'lodash';
|
||||
import { defaultTo, pick, sumBy } from 'lodash';
|
||||
import { Formik, Form } from 'formik';
|
||||
import moment from 'moment';
|
||||
import classNames from 'classnames';
|
||||
@@ -13,9 +13,8 @@ import ExpenseFormBody from './ExpenseFormBody';
|
||||
import ExpenseFloatingFooter from './ExpenseFloatingActions';
|
||||
import ExpenseFormFooter from './ExpenseFormFooter';
|
||||
|
||||
import withExpensesActions from 'containers/Expenses/withExpensesActions';
|
||||
import withExpenseDetail from 'containers/Expenses/withExpenseDetail';
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
import { useExpenseFormContext } from './ExpenseFormPageProvider';
|
||||
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withMediaActions from 'containers/Media/withMediaActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
@@ -45,7 +44,7 @@ const defaultInitialValues = {
|
||||
description: '',
|
||||
reference_no: '',
|
||||
currency_code: '',
|
||||
publish:'',
|
||||
publish: '',
|
||||
categories: [...repeatValue(defaultCategory, MIN_LINES_NUMBER)],
|
||||
};
|
||||
|
||||
@@ -57,36 +56,26 @@ function ExpenseForm({
|
||||
requestSubmitMedia,
|
||||
requestDeleteMedia,
|
||||
|
||||
// #withExpensesActions
|
||||
requestSubmitExpense,
|
||||
requestEditExpense,
|
||||
requestFetchExpensesTable,
|
||||
|
||||
// #withDashboard
|
||||
changePageTitle,
|
||||
changePageSubtitle,
|
||||
|
||||
// #withExpenseDetail
|
||||
expense,
|
||||
|
||||
// #withSettings
|
||||
baseCurrency,
|
||||
preferredPaymentAccount,
|
||||
|
||||
// #ownProps
|
||||
expenseId,
|
||||
onFormSubmit,
|
||||
onCancelForm,
|
||||
}) {
|
||||
const {
|
||||
editExpenseMutate,
|
||||
createExpenseMutate,
|
||||
expense,
|
||||
expenseId,
|
||||
} = useExpenseFormContext();
|
||||
|
||||
const isNewMode = !expenseId;
|
||||
const [submitPayload, setSubmitPayload] = useState({});
|
||||
|
||||
const { formatMessage } = useIntl();
|
||||
const history = useHistory();
|
||||
|
||||
const validationSchema = isNewMode
|
||||
? CreateExpenseFormSchema
|
||||
: EditExpenseFormSchema;
|
||||
|
||||
useEffect(() => {
|
||||
if (isNewMode) {
|
||||
changePageTitle(formatMessage({ id: 'new_expense' }));
|
||||
@@ -104,10 +93,6 @@ function ExpenseForm({
|
||||
...expense.categories.map((category) => ({
|
||||
...pick(category, Object.keys(defaultCategory)),
|
||||
})),
|
||||
// ...repeatValue(
|
||||
// defaultCategory,
|
||||
// Math.max(MIN_LINES_NUMBER - expense.categories.length, 0),
|
||||
// ),
|
||||
],
|
||||
}
|
||||
: {
|
||||
@@ -120,11 +105,10 @@ function ExpenseForm({
|
||||
[expense, baseCurrency, preferredPaymentAccount],
|
||||
);
|
||||
|
||||
// Handle form submit.
|
||||
const handleSubmit = (values, { setSubmitting, setErrors, resetForm }) => {
|
||||
setSubmitting(true);
|
||||
const totalAmount = values.categories.reduce((total, item) => {
|
||||
return total + item.amount;
|
||||
}, 0);
|
||||
const totalAmount = sumBy(values.categories, 'amount');
|
||||
|
||||
if (totalAmount <= 0) {
|
||||
AppToaster.show({
|
||||
@@ -135,7 +119,6 @@ function ExpenseForm({
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const categories = values.categories.filter(
|
||||
(category) =>
|
||||
category.amount && category.index && category.expense_account_id,
|
||||
@@ -175,9 +158,9 @@ function ExpenseForm({
|
||||
setSubmitting(false);
|
||||
};
|
||||
if (isNewMode) {
|
||||
requestSubmitExpense(form).then(handleSuccess).catch(handleError);
|
||||
createExpenseMutate(form).then(handleSuccess).catch(handleError);
|
||||
} else {
|
||||
requestEditExpense(expense.id, form)
|
||||
editExpenseMutate(expense.id, form)
|
||||
.then(handleSuccess)
|
||||
.catch(handleError);
|
||||
}
|
||||
@@ -202,7 +185,9 @@ function ExpenseForm({
|
||||
)}
|
||||
>
|
||||
<Formik
|
||||
validationSchema={validationSchema}
|
||||
validationSchema={isNewMode
|
||||
? CreateExpenseFormSchema
|
||||
: EditExpenseFormSchema}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
@@ -226,11 +211,8 @@ function ExpenseForm({
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withExpensesActions,
|
||||
withAccountsActions,
|
||||
withDashboardActions,
|
||||
withMediaActions,
|
||||
withExpenseDetail(),
|
||||
withSettings(({ organizationSettings, expenseSettings }) => ({
|
||||
baseCurrency: organizationSettings?.baseCurrency,
|
||||
preferredPaymentAccount: parseInt(
|
||||
|
||||
@@ -6,7 +6,6 @@ import { omit } from 'lodash';
|
||||
import { DataTableEditable, Icon } from 'components';
|
||||
import { Hint } from 'components';
|
||||
import {
|
||||
compose,
|
||||
formattedAmount,
|
||||
transformUpdatedRows,
|
||||
saveInvoke,
|
||||
@@ -16,7 +15,7 @@ import {
|
||||
MoneyFieldCell,
|
||||
InputGroupCell,
|
||||
} from 'components/DataTableCells';
|
||||
import withAccounts from 'containers/Accounts/withAccounts';
|
||||
import { useExpenseFormContext } from './ExpenseFormPageProvider';
|
||||
|
||||
const ExpenseCategoryHeaderCell = () => {
|
||||
return (
|
||||
@@ -88,10 +87,7 @@ const TotalAmountCellRenderer = (chainedComponent, type) => (props) => {
|
||||
return chainedComponent(props);
|
||||
};
|
||||
|
||||
function ExpenseTable({
|
||||
// #withAccounts
|
||||
accountsList,
|
||||
|
||||
export default function ExpenseTable({
|
||||
// #ownPorps
|
||||
onClickRemoveRow,
|
||||
onClickAddNewRow,
|
||||
@@ -104,6 +100,8 @@ function ExpenseTable({
|
||||
const [rows, setRows] = useState([]);
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const { accounts } = useExpenseFormContext();
|
||||
|
||||
useEffect(() => {
|
||||
setRows([...entries.map((e) => ({ ...e, rowType: 'editor' }))]);
|
||||
}, [entries]);
|
||||
@@ -230,7 +228,7 @@ function ExpenseTable({
|
||||
rowClassNames={rowClassNames}
|
||||
sticky={true}
|
||||
payload={{
|
||||
accounts: accountsList,
|
||||
accounts: accounts,
|
||||
errors: error,
|
||||
updateData: handleUpdateData,
|
||||
removeRow: handleRemoveRow,
|
||||
@@ -258,10 +256,4 @@ function ExpenseTable({
|
||||
totalRow={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAccounts(({ accountsList }) => ({
|
||||
accountsList,
|
||||
})),
|
||||
)(ExpenseTable);
|
||||
}
|
||||
@@ -20,21 +20,16 @@ import {
|
||||
FieldRequiredHint,
|
||||
Hint,
|
||||
} from 'components';
|
||||
import withCurrencies from 'containers/Currencies/withCurrencies';
|
||||
import withAccounts from 'containers/Accounts/withAccounts';
|
||||
import withCustomers from 'containers/Customers/withCustomers';
|
||||
|
||||
function ExpenseFormHeader({
|
||||
//withCurrencies
|
||||
currenciesList,
|
||||
import { ACCOUNT_PARENT_TYPE } from 'common/accountTypes';
|
||||
import { useExpenseFormContext } from './ExpenseFormPageProvider';
|
||||
|
||||
// #withAccounts
|
||||
accountsList,
|
||||
accountsTypes,
|
||||
/**
|
||||
* Expense form header.
|
||||
*/
|
||||
export default function ExpenseFormHeader({}) {
|
||||
const { currencies, accounts, customers } = useExpenseFormContext();
|
||||
|
||||
// #withCustomers
|
||||
customers,
|
||||
}) {
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||
<FastField name={'payment_date'}>
|
||||
@@ -74,13 +69,13 @@ function ExpenseFormHeader({
|
||||
inline={true}
|
||||
>
|
||||
<AccountsSelectList
|
||||
accounts={accountsList}
|
||||
accounts={accounts}
|
||||
onAccountSelected={(account) => {
|
||||
form.setFieldValue('payment_account_id', account.id);
|
||||
}}
|
||||
defaultSelectText={<T id={'select_payment_account'} />}
|
||||
selectedAccountId={value}
|
||||
filterByTypes={['current_asset']}
|
||||
filterByParentTypes={[ACCOUNT_PARENT_TYPE.CURRENT_ASSET]}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
@@ -100,7 +95,7 @@ function ExpenseFormHeader({
|
||||
inline={true}
|
||||
>
|
||||
<CurrencySelectList
|
||||
currenciesList={currenciesList}
|
||||
currenciesList={currencies}
|
||||
selectedCurrencyCode={value}
|
||||
onCurrencySelected={(currencyItem) => {
|
||||
form.setFieldValue('currency_code', currencyItem.currency_code);
|
||||
@@ -149,16 +144,3 @@ function ExpenseFormHeader({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAccounts(({ accountsList, accountsTypes }) => ({
|
||||
accountsList,
|
||||
accountsTypes,
|
||||
})),
|
||||
withCurrencies(({ currenciesList }) => ({
|
||||
currenciesList,
|
||||
})),
|
||||
withCustomers(({ customers }) => ({
|
||||
customers,
|
||||
})),
|
||||
)(ExpenseFormHeader);
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useParams, useHistory } from 'react-router-dom';
|
||||
import { useQuery } from 'react-query';
|
||||
|
||||
import ExpenseForm from './ExpenseForm';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import { ExpenseFormPageProvider } from './ExpenseFormPageProvider';
|
||||
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
import withExpensesActions from 'containers/Expenses/withExpensesActions';
|
||||
import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions';
|
||||
import withCustomersActions from 'containers/Customers/withCustomersActions';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
@@ -19,19 +14,6 @@ import 'style/pages/Expense/PageForm.scss';
|
||||
* Expense page form.
|
||||
*/
|
||||
function ExpenseFormPage({
|
||||
// #withwithAccountsActions
|
||||
requestFetchAccounts,
|
||||
requestFetchAccountTypes,
|
||||
|
||||
// #withExpensesActions
|
||||
requestFetchExpense,
|
||||
|
||||
// #wihtCurrenciesActions
|
||||
requestFetchCurrencies,
|
||||
|
||||
// #withCustomersActions
|
||||
requestFetchCustomers,
|
||||
|
||||
// #withDashboardActions
|
||||
setSidebarShrink,
|
||||
resetSidebarPreviousExpand,
|
||||
@@ -54,25 +36,6 @@ function ExpenseFormPage({
|
||||
};
|
||||
}, [resetSidebarPreviousExpand, setSidebarShrink, setDashboardBackLink]);
|
||||
|
||||
const fetchAccounts = useQuery('accounts-list', (key) =>
|
||||
requestFetchAccounts(),
|
||||
);
|
||||
|
||||
const fetchExpense = useQuery(
|
||||
['expense', id],
|
||||
(key, _id) => requestFetchExpense(_id),
|
||||
{ enabled: !!id },
|
||||
);
|
||||
|
||||
const fetchCurrencies = useQuery('currencies', () =>
|
||||
requestFetchCurrencies(),
|
||||
);
|
||||
|
||||
// Handle fetch customers data table or list
|
||||
const fetchCustomers = useQuery('customers-table', () =>
|
||||
requestFetchCustomers({}),
|
||||
);
|
||||
|
||||
const handleFormSubmit = useCallback(
|
||||
(payload) => {
|
||||
payload.redirect && history.push('/expenses-list');
|
||||
@@ -85,28 +48,16 @@ function ExpenseFormPage({
|
||||
}, [history]);
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={
|
||||
fetchExpense.isFetching ||
|
||||
fetchAccounts.isFetching ||
|
||||
fetchCurrencies.isFetching ||
|
||||
fetchCustomers.isFetching
|
||||
}
|
||||
name={'expense-form'}
|
||||
>
|
||||
<ExpenseFormPageProvider expenseId={id}>
|
||||
<ExpenseForm
|
||||
onFormSubmit={handleFormSubmit}
|
||||
expenseId={id}
|
||||
onCancelForm={handleCancel}
|
||||
/>
|
||||
</DashboardInsider>
|
||||
</ExpenseFormPageProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAccountsActions,
|
||||
withCurrenciesActions,
|
||||
withExpensesActions,
|
||||
withCustomersActions,
|
||||
withDashboardActions,
|
||||
)(ExpenseFormPage);
|
||||
|
||||
71
client/src/containers/Expenses/ExpenseFormPageProvider.js
Normal file
71
client/src/containers/Expenses/ExpenseFormPageProvider.js
Normal file
@@ -0,0 +1,71 @@
|
||||
import React, { createContext } from 'react';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import {
|
||||
useCurrencies,
|
||||
useCustomers,
|
||||
useExpense,
|
||||
useAccounts,
|
||||
useCreateExpense,
|
||||
useEditExpense,
|
||||
} from 'hooks/query';
|
||||
|
||||
const ExpenseFormPageContext = createContext();
|
||||
|
||||
/**
|
||||
* Accounts chart data provider.
|
||||
*/
|
||||
function ExpenseFormPageProvider({ expenseId, ...props }) {
|
||||
const { data: currencies, isFetching: isCurrenciesLoading } = useCurrencies();
|
||||
|
||||
// Fetches customers list.
|
||||
const {
|
||||
data: { customers },
|
||||
isFetching: isFieldsLoading,
|
||||
} = useCustomers();
|
||||
|
||||
// Fetch the expense details.
|
||||
const { data: expense, isFetching: isExpenseLoading } = useExpense(expenseId);
|
||||
|
||||
// Fetch accounts list.
|
||||
const { data: accounts, isFetching: isAccountsLoading } = useAccounts();
|
||||
|
||||
// Create and edit expense mutate.
|
||||
const { mutateAsync: createExpenseMutate } = useCreateExpense();
|
||||
const { mutateAsync: editExpenseMutate } = useEditExpense();
|
||||
|
||||
// Provider payload.
|
||||
const provider = {
|
||||
expenseId,
|
||||
|
||||
currencies,
|
||||
customers,
|
||||
expense,
|
||||
accounts,
|
||||
|
||||
isCurrenciesLoading,
|
||||
isExpenseLoading,
|
||||
isFieldsLoading,
|
||||
isAccountsLoading,
|
||||
|
||||
createExpenseMutate,
|
||||
editExpenseMutate,
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={
|
||||
isCurrenciesLoading ||
|
||||
isExpenseLoading ||
|
||||
isFieldsLoading ||
|
||||
isAccountsLoading
|
||||
}
|
||||
name={'expense-form'}
|
||||
>
|
||||
<ExpenseFormPageContext.Provider value={provider} {...props} />
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
const useExpenseFormContext = () => React.useContext(ExpenseFormPageContext);
|
||||
|
||||
export { ExpenseFormPageProvider, useExpenseFormContext };
|
||||
@@ -1,16 +1,13 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { useHistory } from 'react-router';
|
||||
import React from 'react';
|
||||
import { Alignment, Navbar, NavbarGroup } from '@blueprintjs/core';
|
||||
import { useParams, withRouter } from 'react-router-dom';
|
||||
import { connect } from 'react-redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { pick } from 'lodash';
|
||||
|
||||
import { DashboardViewsTabs } from 'components';
|
||||
|
||||
import withExpenses from './withExpenses';
|
||||
import { useExpensesListContext } from './ExpensesListProvider';
|
||||
|
||||
import withExpensesActions from './withExpensesActions';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withViewDetails from 'containers/Views/withViewDetails';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
@@ -18,38 +15,19 @@ import { compose } from 'utils';
|
||||
* Expesne views tabs.
|
||||
*/
|
||||
function ExpenseViewTabs({
|
||||
// #withExpenses
|
||||
expensesViews,
|
||||
|
||||
// #withViewDetails
|
||||
viewItem,
|
||||
|
||||
// #withExpensesActions
|
||||
addExpensesTableQueries,
|
||||
changeExpensesView,
|
||||
|
||||
// #withDashboardActions
|
||||
setTopbarEditView,
|
||||
changePageSubtitle,
|
||||
|
||||
// props
|
||||
customViewChanged,
|
||||
onViewChanged,
|
||||
addExpensesTableQueries,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { expensesViews } = useExpensesListContext();
|
||||
|
||||
const { custom_view_id: customViewId = null } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
setTopbarEditView(customViewId);
|
||||
changePageSubtitle(customViewId && viewItem ? viewItem.name : '');
|
||||
}, [customViewId]);
|
||||
|
||||
const handleTabChange = (viewId) => {
|
||||
changeExpensesView(viewId || -1);
|
||||
addExpensesTableQueries({
|
||||
custom_view_id: viewId || null,
|
||||
});
|
||||
};
|
||||
|
||||
const tabs = expensesViews.map((view) => ({
|
||||
...pick(view, ['name', 'id']),
|
||||
}));
|
||||
@@ -72,19 +50,7 @@ function ExpenseViewTabs({
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
viewId: ownProps.match.params.custom_view_id,
|
||||
});
|
||||
|
||||
const withExpensesViewTabs = connect(mapStateToProps);
|
||||
|
||||
|
||||
export default compose(
|
||||
withRouter,
|
||||
withExpensesViewTabs,
|
||||
withExpensesActions,
|
||||
withDashboardActions,
|
||||
withViewDetails(),
|
||||
withExpenses(({ expensesViews }) => ({
|
||||
expensesViews,
|
||||
})),
|
||||
)(ExpenseViewTabs);
|
||||
|
||||
17
client/src/containers/Expenses/ExpensesAlerts.js
Normal file
17
client/src/containers/Expenses/ExpensesAlerts.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import ExpenseDeleteAlert from 'alerts/expenses/ExpenseDeleteAlert';
|
||||
import ExpensePublishAlert from 'alerts/expenses/ExpensePublishAlert';
|
||||
|
||||
/**
|
||||
* Accounts alert.
|
||||
*/
|
||||
export default function ExpensesAlerts({
|
||||
|
||||
}) {
|
||||
return (
|
||||
<div class="expenses-alerts">
|
||||
<ExpenseDeleteAlert name={'expense-delete'} />
|
||||
<ExpensePublishAlert name={'expense-publish'} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,263 +1,45 @@
|
||||
import React, { useEffect, useState, useMemo, useCallback } from 'react';
|
||||
import { Route, Switch, useHistory, useParams } from 'react-router-dom';
|
||||
import { useQuery, queryCache } from 'react-query';
|
||||
import { Alert, Intent } from '@blueprintjs/core';
|
||||
import AppToaster from 'components/AppToaster';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import { useIntl } from 'react-intl';
|
||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
|
||||
import ExpenseViewTabs from 'containers/Expenses/ExpenseViewTabs';
|
||||
import ExpenseDataTable from 'containers/Expenses/ExpenseDataTable';
|
||||
import ExpenseActionsBar from 'containers/Expenses/ExpenseActionsBar';
|
||||
import ExpensesViewPage from './ExpensesViewPage';
|
||||
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withResourceActions from 'containers/Resources/withResourcesActions';
|
||||
import withExpenses from 'containers/Expenses/withExpenses';
|
||||
import withExpensesActions from 'containers/Expenses/withExpensesActions';
|
||||
import withViewsActions from 'containers/Views/withViewsActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
import { ExpensesListProvider } from './ExpensesListProvider';
|
||||
|
||||
/**
|
||||
* Expenses list.
|
||||
*/
|
||||
function ExpensesList({
|
||||
// #withDashboardActions
|
||||
changePageTitle,
|
||||
|
||||
// #withViewsActions
|
||||
requestFetchResourceViews,
|
||||
requestFetchResourceFields,
|
||||
|
||||
// #withExpenses
|
||||
expensesTableQuery,
|
||||
|
||||
//#withExpensesActions
|
||||
requestFetchExpensesTable,
|
||||
requestDeleteExpense,
|
||||
requestPublishExpense,
|
||||
requestDeleteBulkExpenses,
|
||||
addExpensesTableQueries,
|
||||
requestFetchExpense,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { id } = useParams();
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const [deleteExpense, setDeleteExpense] = useState(false);
|
||||
const [selectedRows, setSelectedRows] = useState([]);
|
||||
const [bulkDelete, setBulkDelete] = useState(false);
|
||||
const [publishExpense, setPublishExpense] = useState(false);
|
||||
|
||||
const fetchResourceViews = useQuery(
|
||||
['resource-views', 'expenses'],
|
||||
(key, resourceName) => requestFetchResourceViews(resourceName),
|
||||
);
|
||||
|
||||
const fetchResourceFields = useQuery(
|
||||
['resource-fields', 'expenses'],
|
||||
(key, resourceName) => requestFetchResourceFields(resourceName),
|
||||
);
|
||||
|
||||
const fetchExpenses = useQuery(['expenses-table', expensesTableQuery], () =>
|
||||
requestFetchExpensesTable(),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
changePageTitle(formatMessage({ id: 'expenses_list' }));
|
||||
}, [changePageTitle, formatMessage]);
|
||||
|
||||
// Handle delete expense click.
|
||||
const handleDeleteExpense = useCallback(
|
||||
(expnese) => {
|
||||
setDeleteExpense(expnese);
|
||||
},
|
||||
[setDeleteExpense],
|
||||
);
|
||||
|
||||
// Handle cancel expense journal.
|
||||
const handleCancelExpenseDelete = useCallback(() => {
|
||||
setDeleteExpense(false);
|
||||
}, [setDeleteExpense]);
|
||||
|
||||
// Handle confirm delete expense.
|
||||
const handleConfirmExpenseDelete = useCallback(() => {
|
||||
requestDeleteExpense(deleteExpense.id).then(() => {
|
||||
AppToaster.show({
|
||||
message: formatMessage(
|
||||
{ id: 'the_expense_has_been_deleted_successfully' },
|
||||
{ number: deleteExpense.payment_account_id },
|
||||
),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
setDeleteExpense(false);
|
||||
});
|
||||
}, [deleteExpense, requestDeleteExpense, formatMessage]);
|
||||
|
||||
// Calculates the selected rows count.
|
||||
const selectedRowsCount = useMemo(() => Object.values(selectedRows).length, [
|
||||
selectedRows,
|
||||
]);
|
||||
|
||||
const handleBulkDelete = useCallback(
|
||||
(accountsIds) => {
|
||||
setBulkDelete(accountsIds);
|
||||
},
|
||||
[setBulkDelete],
|
||||
);
|
||||
|
||||
// Handle confirm journals bulk delete.
|
||||
const handleConfirmBulkDelete = useCallback(() => {
|
||||
requestDeleteBulkExpenses(bulkDelete)
|
||||
.then(() => {
|
||||
AppToaster.show({
|
||||
message: formatMessage(
|
||||
{ id: 'the_expenses_have_been_deleted_successfully' },
|
||||
{ count: selectedRowsCount },
|
||||
),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
setBulkDelete(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
setBulkDelete(false);
|
||||
});
|
||||
}, [requestDeleteBulkExpenses, bulkDelete, formatMessage, selectedRowsCount]);
|
||||
|
||||
// Handle cancel bulk delete alert.
|
||||
const handleCancelBulkDelete = useCallback(() => {
|
||||
setBulkDelete(false);
|
||||
}, []);
|
||||
|
||||
const handleEidtExpense = useCallback(
|
||||
(expense) => {
|
||||
history.push(`/expenses/${expense.id}/edit`);
|
||||
},
|
||||
[history],
|
||||
);
|
||||
|
||||
// Handle filter change to re-fetch data-table.
|
||||
const handleFilterChanged = useCallback(() => {}, []);
|
||||
|
||||
// const fetchExpenses = useQuery(['expenses-table', expensesTableQuery], () =>
|
||||
// requestFetchExpensesTable(),
|
||||
// );
|
||||
|
||||
const handlePublishExpense = useCallback((expense) => {
|
||||
setPublishExpense(expense);
|
||||
}, []);
|
||||
|
||||
const handleCancelPublishExpense = useCallback(() => {
|
||||
setPublishExpense(false);
|
||||
});
|
||||
|
||||
// Handle publish expense confirm.
|
||||
const handleConfirmPublishExpense = useCallback(() => {
|
||||
requestPublishExpense(publishExpense.id)
|
||||
.then(() => {
|
||||
setPublishExpense(false);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_expense_has_been_published',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('expenses-table');
|
||||
})
|
||||
.catch((error) => {
|
||||
setPublishExpense(false);
|
||||
});
|
||||
}, [publishExpense, requestPublishExpense, formatMessage]);
|
||||
|
||||
// Handle selected rows change.
|
||||
const handleSelectedRowsChange = useCallback(
|
||||
(accounts) => {
|
||||
setSelectedRows(accounts);
|
||||
},
|
||||
[setSelectedRows],
|
||||
);
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={fetchResourceViews.isFetching || fetchResourceFields.isFetching}
|
||||
name={'expenses'}
|
||||
>
|
||||
<ExpenseActionsBar
|
||||
onBulkDelete={handleBulkDelete}
|
||||
selectedRows={selectedRows}
|
||||
onFilterChanged={handleFilterChanged}
|
||||
/>
|
||||
<ExpensesListProvider query={expensesTableQuery}>
|
||||
<ExpenseActionsBar />
|
||||
|
||||
<DashboardPageContent>
|
||||
<Switch>
|
||||
<Route
|
||||
exact={true}
|
||||
// path={[
|
||||
// '/expenses/:custom_view_id/custom_view',
|
||||
// 'expenses',
|
||||
// ]}
|
||||
>
|
||||
<ExpenseViewTabs />
|
||||
|
||||
<ExpenseDataTable
|
||||
onDeleteExpense={handleDeleteExpense}
|
||||
onEditExpense={handleEidtExpense}
|
||||
onPublishExpense={handlePublishExpense}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={<T id={'delete'} />}
|
||||
icon="trash"
|
||||
intent={Intent.DANGER}
|
||||
isOpen={deleteExpense}
|
||||
onCancel={handleCancelExpenseDelete}
|
||||
onConfirm={handleConfirmExpenseDelete}
|
||||
>
|
||||
<p>
|
||||
<T id={'once_delete_this_expense_you_will_able_to_restore_it'} />
|
||||
</p>
|
||||
</Alert>
|
||||
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={
|
||||
<T id={'delete_count'} values={{ count: selectedRowsCount }} />
|
||||
}
|
||||
icon="trash"
|
||||
intent={Intent.DANGER}
|
||||
isOpen={bulkDelete}
|
||||
onCancel={handleCancelBulkDelete}
|
||||
onConfirm={handleConfirmBulkDelete}
|
||||
>
|
||||
<p>
|
||||
<T
|
||||
id={'once_delete_these_expenses_you_will_not_able_restore_them'}
|
||||
/>
|
||||
</p>
|
||||
</Alert>
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={<T id={'publish'} />}
|
||||
intent={Intent.WARNING}
|
||||
isOpen={publishExpense}
|
||||
onCancel={handleCancelPublishExpense}
|
||||
onConfirm={handleConfirmPublishExpense}
|
||||
>
|
||||
<p>
|
||||
<T id={'are_sure_to_publish_this_expense'} />
|
||||
</p>
|
||||
</Alert>
|
||||
<ExpensesViewPage />
|
||||
</DashboardPageContent>
|
||||
</DashboardInsider>
|
||||
</ExpensesListProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withExpensesActions,
|
||||
withDashboardActions,
|
||||
withViewsActions,
|
||||
withResourceActions,
|
||||
withExpenses(({ expensesTableQuery }) => ({ expensesTableQuery })),
|
||||
)(ExpensesList);
|
||||
|
||||
44
client/src/containers/Expenses/ExpensesListProvider.js
Normal file
44
client/src/containers/Expenses/ExpensesListProvider.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import React, { createContext } from 'react';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import { useExpenses, useResourceViews } from 'hooks/query';
|
||||
|
||||
const ExpensesListContext = createContext();
|
||||
|
||||
/**
|
||||
* Accounts chart data provider.
|
||||
*/
|
||||
function ExpensesListProvider({ query, ...props }) {
|
||||
// Fetch accounts resource views and fields.
|
||||
const { data: expensesViews, isFetching: isViewsLoading } = useResourceViews(
|
||||
'expenses',
|
||||
);
|
||||
|
||||
const {
|
||||
data: { expenses, pagination },
|
||||
isFetching: isExpensesLoading,
|
||||
} = useExpenses();
|
||||
|
||||
// Provider payload.
|
||||
const provider = {
|
||||
expensesViews,
|
||||
expenses,
|
||||
pagination,
|
||||
|
||||
isViewsLoading,
|
||||
isExpensesLoading
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={isViewsLoading}
|
||||
name={'expenses'}
|
||||
>
|
||||
<ExpensesListContext.Provider value={provider} {...props} />
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
const useExpensesListContext = () =>
|
||||
React.useContext(ExpensesListContext);
|
||||
|
||||
export { ExpensesListProvider, useExpensesListContext };
|
||||
37
client/src/containers/Expenses/ExpensesViewPage.js
Normal file
37
client/src/containers/Expenses/ExpensesViewPage.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
|
||||
import ExpenseViewTabs from 'containers/Expenses/ExpenseViewTabs';
|
||||
import ExpenseDataTable from './ExpenseDataTable';
|
||||
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Expenses inner page.
|
||||
*/
|
||||
function ExpensesViewPage() {
|
||||
return (
|
||||
<Switch>
|
||||
<Route
|
||||
exact={true}
|
||||
path={['/expenses/:custom_view_id/custom_view', '/expenses']}
|
||||
>
|
||||
<ExpenseViewTabs />
|
||||
<ExpenseDataTable />
|
||||
{/* // onDeleteExpense={handleDeleteExpense}
|
||||
// onEditExpense={handleEidtExpense}
|
||||
// onPublishExpense={handlePublishExpense}
|
||||
// onSelectedRowsChange={handleSelectedRowsChange}
|
||||
// /> */}
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAlertsActions,
|
||||
withDialogActions,
|
||||
)(ExpensesViewPage);
|
||||
Reference in New Issue
Block a user