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:
@@ -10,72 +10,64 @@ import {
|
||||
MenuItem,
|
||||
} from '@blueprintjs/core';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import classNames from 'classnames';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { saveInvoke } from 'utils';
|
||||
import { If, Icon } from 'components';
|
||||
import { useBillFormContext } from './BillFormProvider';
|
||||
|
||||
/**
|
||||
* Bill floating actions bar.
|
||||
*/
|
||||
export default function BillFloatingActions({
|
||||
isSubmitting,
|
||||
onSubmitClick,
|
||||
onCancelClick,
|
||||
bill,
|
||||
}) {
|
||||
const { resetForm, submitForm } = useFormikContext();
|
||||
export default function BillFloatingActions() {
|
||||
const history = useHistory();
|
||||
|
||||
// Formik context.
|
||||
const { resetForm, submitForm, isSubmitting } = useFormikContext();
|
||||
|
||||
// Bill form context.
|
||||
const { bill, setSubmitPayload } = useBillFormContext();
|
||||
|
||||
// Handle submit as open button click.
|
||||
const handleSubmitOpenBtnClick = (event) => {
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: true,
|
||||
status: true,
|
||||
});
|
||||
setSubmitPayload({ redirect: true, status: true });
|
||||
submitForm();
|
||||
};
|
||||
|
||||
// Handle submit, open and anothe new button click.
|
||||
const handleSubmitOpenAndNewBtnClick = (event) => {
|
||||
setSubmitPayload({ redirect: false, status: true, resetForm: true });
|
||||
submitForm();
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: false,
|
||||
status: true,
|
||||
resetForm: true,
|
||||
});
|
||||
};
|
||||
|
||||
// Handle submit as open & continue editing button click.
|
||||
const handleSubmitOpenContinueEditingBtnClick = (event) => {
|
||||
setSubmitPayload({ redirect: false, status: true });
|
||||
submitForm();
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: false,
|
||||
status: true,
|
||||
});
|
||||
};
|
||||
|
||||
// Handle submit as draft button click.
|
||||
const handleSubmitDraftBtnClick = (event) => {
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: true,
|
||||
status: false,
|
||||
});
|
||||
setSubmitPayload({ redirect: true, status: false });
|
||||
submitForm();
|
||||
};
|
||||
|
||||
// handle submit as draft & new button click.
|
||||
const handleSubmitDraftAndNewBtnClick = (event) => {
|
||||
setSubmitPayload({ redirect: false, status: false, resetForm: true });
|
||||
submitForm();
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: false,
|
||||
status: false,
|
||||
resetForm: true,
|
||||
});
|
||||
};
|
||||
|
||||
// Handle submit as draft & continue editing button click.
|
||||
const handleSubmitDraftContinueEditingBtnClick = (event) => {
|
||||
setSubmitPayload({ redirect: false, status: false, });
|
||||
submitForm();
|
||||
saveInvoke(onSubmitClick, event, {
|
||||
redirect: false,
|
||||
status: false,
|
||||
});
|
||||
};
|
||||
|
||||
// Handle cancel button click.
|
||||
const handleCancelBtnClick = (event) => {
|
||||
saveInvoke(onCancelClick, event);
|
||||
history.goBack();
|
||||
};
|
||||
|
||||
const handleClearBtnClick = (event) => {
|
||||
@@ -89,6 +81,7 @@ export default function BillFloatingActions({
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
disabled={isSubmitting}
|
||||
loading={isSubmitting}
|
||||
intent={Intent.PRIMARY}
|
||||
type="submit"
|
||||
onClick={handleSubmitOpenBtnClick}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, { useState, useMemo, useCallback, useEffect } from 'react';
|
||||
import React, { useMemo, useCallback, useEffect } from 'react';
|
||||
import { Formik, Form } from 'formik';
|
||||
import moment from 'moment';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import classNames from 'classnames';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { pick, sumBy, omit } from 'lodash';
|
||||
import { pick, sumBy, isEmpty, omit } from 'lodash';
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
import { EditBillFormSchema, CreateBillFormSchema } from './BillForm.schema';
|
||||
@@ -13,17 +13,14 @@ import BillFormHeader from './BillFormHeader';
|
||||
import BillFloatingActions from './BillFloatingActions';
|
||||
import BillFormFooter from './BillFormFooter';
|
||||
|
||||
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withMediaActions from 'containers/Media/withMediaActions';
|
||||
import withBillActions from './withBillActions';
|
||||
import withBillDetail from './withBillDetail';
|
||||
|
||||
import { AppToaster } from 'components';
|
||||
|
||||
import { ERROR } from 'common/errors';
|
||||
import { compose, repeatValue, defaultToTransform, orderingLinesIndexes } from 'utils';
|
||||
import { compose, repeatValue, orderingLinesIndexes } from 'utils';
|
||||
import BillFormBody from './BillFormBody';
|
||||
import { useBillFormContext } from './BillFormProvider';
|
||||
|
||||
const MIN_LINES_NUMBER = 5;
|
||||
|
||||
@@ -43,7 +40,7 @@ const defaultInitialValues = {
|
||||
due_date: moment(new Date()).format('YYYY-MM-DD'),
|
||||
reference_no: '',
|
||||
note: '',
|
||||
open:'',
|
||||
open: '',
|
||||
entries: [...repeatValue(defaultBill, MIN_LINES_NUMBER)],
|
||||
};
|
||||
|
||||
@@ -51,31 +48,21 @@ const defaultInitialValues = {
|
||||
* Bill form.
|
||||
*/
|
||||
function BillForm({
|
||||
//#WithMedia
|
||||
requestSubmitMedia,
|
||||
requestDeleteMedia,
|
||||
|
||||
//#withBillActions
|
||||
requestSubmitBill,
|
||||
requestEditBill,
|
||||
setBillNumberChanged,
|
||||
|
||||
//#withDashboard
|
||||
changePageTitle,
|
||||
changePageSubtitle,
|
||||
|
||||
//#withBillDetail
|
||||
bill,
|
||||
|
||||
//#Own Props
|
||||
billId,
|
||||
onFormSubmit,
|
||||
onCancelForm,
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
const history = useHistory();
|
||||
|
||||
const [submitPayload, setSubmitPayload] = useState({});
|
||||
const {
|
||||
bill,
|
||||
billId,
|
||||
submitPayload,
|
||||
createBillMutate,
|
||||
editBillMutate,
|
||||
} = useBillFormContext();
|
||||
|
||||
const isNewMode = !billId;
|
||||
|
||||
useEffect(() => {
|
||||
@@ -89,7 +76,7 @@ function BillForm({
|
||||
// Initial values in create and edit mode.
|
||||
const initialValues = useMemo(
|
||||
() => ({
|
||||
...(bill
|
||||
...(!isEmpty(bill)
|
||||
? {
|
||||
...pick(bill, Object.keys(defaultInitialValues)),
|
||||
entries: [
|
||||
@@ -139,10 +126,9 @@ function BillForm({
|
||||
setSubmitting(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const form = {
|
||||
...values,
|
||||
open:submitPayload.status,
|
||||
open: submitPayload.status,
|
||||
entries: entries.map((entry) => ({ ...omit(entry, ['total']) })),
|
||||
};
|
||||
// Handle the request success.
|
||||
@@ -151,8 +137,8 @@ function BillForm({
|
||||
message: formatMessage(
|
||||
{
|
||||
id: isNewMode
|
||||
? 'the_bill_has_been_created_successfully' :
|
||||
'the_bill_has_been_edited_successfully',
|
||||
? 'the_bill_has_been_created_successfully'
|
||||
: 'the_bill_has_been_edited_successfully',
|
||||
},
|
||||
{ number: values.bill_number },
|
||||
),
|
||||
@@ -175,9 +161,9 @@ function BillForm({
|
||||
setSubmitting(false);
|
||||
};
|
||||
if (bill && bill.id) {
|
||||
requestEditBill(bill.id, form).then(onSuccess).catch(onError);
|
||||
editBillMutate(bill.id, form).then(onSuccess).catch(onError);
|
||||
} else {
|
||||
requestSubmitBill(form).then(onSuccess).catch(onError);
|
||||
createBillMutate(form).then(onSuccess).catch(onError);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -189,60 +175,28 @@ function BillForm({
|
||||
[changePageSubtitle],
|
||||
);
|
||||
|
||||
// Clear page subtitle once unmount bill form page.
|
||||
useEffect(
|
||||
() => () => {
|
||||
changePageSubtitle('');
|
||||
},
|
||||
[changePageSubtitle],
|
||||
);
|
||||
|
||||
const handleSubmitClick = useCallback(
|
||||
(event, payload) => {
|
||||
setSubmitPayload({ ...payload });
|
||||
},
|
||||
[setSubmitPayload],
|
||||
);
|
||||
|
||||
const handleCancelClick = useCallback(() => {
|
||||
history.goBack();
|
||||
}, [history]);
|
||||
|
||||
return (
|
||||
<div className={classNames(
|
||||
CLASSES.PAGE_FORM,
|
||||
CLASSES.PAGE_FORM_STRIP_STYLE,
|
||||
CLASSES.PAGE_FORM_BILL,
|
||||
)}>
|
||||
<div
|
||||
className={classNames(
|
||||
CLASSES.PAGE_FORM,
|
||||
CLASSES.PAGE_FORM_STRIP_STYLE,
|
||||
CLASSES.PAGE_FORM_BILL,
|
||||
)}
|
||||
>
|
||||
<Formik
|
||||
validationSchema={isNewMode ? CreateBillFormSchema : EditBillFormSchema}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
{({ isSubmitting}) => (
|
||||
<Form>
|
||||
<BillFormHeader onBillNumberChanged={handleBillNumberChanged} />
|
||||
<BillFormBody defaultBill={defaultBill} />
|
||||
<BillFormFooter
|
||||
oninitialFiles={[]}
|
||||
// onDropFiles={handleDeleteFile}
|
||||
/>
|
||||
<BillFloatingActions
|
||||
isSubmitting={isSubmitting}
|
||||
bill={bill}
|
||||
onSubmitClick={handleSubmitClick}
|
||||
onCancelClick={handleCancelClick}
|
||||
/>
|
||||
</Form>
|
||||
)}
|
||||
<Form>
|
||||
<BillFormHeader onBillNumberChanged={handleBillNumberChanged} />
|
||||
<BillFormBody defaultBill={defaultBill} />
|
||||
<BillFormFooter />
|
||||
<BillFloatingActions />
|
||||
</Form>
|
||||
</Formik>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withBillActions,
|
||||
withBillDetail(),
|
||||
withDashboardActions,
|
||||
withMediaActions,
|
||||
)(BillForm);
|
||||
export default compose(withDashboardActions)(BillForm);
|
||||
|
||||
@@ -2,11 +2,15 @@ import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import EditableItemsEntriesTable from 'containers/Entries/EditableItemsEntriesTable';
|
||||
import { useBillFormContext } from './BillFormProvider';
|
||||
|
||||
export default function BillFormBody({ defaultBill }) {
|
||||
const { items } = useBillFormContext();
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_BODY)}>
|
||||
<EditableItemsEntriesTable
|
||||
items={items}
|
||||
defaultEntry={defaultBill}
|
||||
filterPurchasableItems={true}
|
||||
/>
|
||||
|
||||
@@ -9,10 +9,7 @@ import Dragzone from 'components/Dragzone';
|
||||
import { inputIntent } from 'utils';
|
||||
|
||||
// Bill form floating actions.
|
||||
export default function BillFormFooter({
|
||||
oninitialFiles,
|
||||
onDropFiles,
|
||||
}) {
|
||||
export default function BillFormFooter() {
|
||||
return (
|
||||
<div class={classNames(CLASSES.PAGE_FORM_FOOTER)}>
|
||||
<Row>
|
||||
@@ -32,9 +29,9 @@ export default function BillFormFooter({
|
||||
|
||||
<Col md={4}>
|
||||
<Dragzone
|
||||
initialFiles={oninitialFiles}
|
||||
onDrop={onDropFiles}
|
||||
onDeleteFile={onDropFiles}
|
||||
initialFiles={[]}
|
||||
// onDrop={onDropFiles}
|
||||
// onDeleteFile={onDropFiles}
|
||||
hint={'Attachments: Maxiumum size: 20MB'}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
@@ -8,10 +8,8 @@ import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { ContactSelecetList, FieldRequiredHint, Icon } from 'components';
|
||||
|
||||
import withVendors from 'containers/Vendors/withVendors';
|
||||
import withAccounts from 'containers/Accounts/withAccounts';
|
||||
import { useBillFormContext } from './BillFormProvider';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
|
||||
import {
|
||||
momentFormatter,
|
||||
compose,
|
||||
@@ -26,10 +24,10 @@ import {
|
||||
*/
|
||||
function BillFormHeader({
|
||||
onBillNumberChanged,
|
||||
|
||||
//#withVendors
|
||||
vendorItems,
|
||||
}) {
|
||||
// Bill form context.
|
||||
const { vendors } = useBillFormContext();
|
||||
|
||||
const handleBillNumberBlur = (event) => {
|
||||
saveInvoke(onBillNumberChanged, event.currentTarget.value);
|
||||
};
|
||||
@@ -48,7 +46,7 @@ function BillFormHeader({
|
||||
helperText={<ErrorMessage name={'vendor_id'} />}
|
||||
>
|
||||
<ContactSelecetList
|
||||
contactsList={vendorItems}
|
||||
contactsList={vendors}
|
||||
selectedContactId={value}
|
||||
defaultSelectText={<T id={'select_vender_account'} />}
|
||||
onContactSelected={(contact) => {
|
||||
@@ -151,11 +149,5 @@ function BillFormHeader({
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withVendors(({ vendorItems }) => ({
|
||||
vendorItems,
|
||||
})),
|
||||
withAccounts(({ accountsList }) => ({
|
||||
accountsList,
|
||||
})),
|
||||
withDialogActions,
|
||||
)(BillFormHeader);
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useParams, useHistory } from 'react-router-dom';
|
||||
import { useQuery } from 'react-query';
|
||||
|
||||
import BillForm from './BillForm';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
|
||||
import withVendorActions from 'containers/Vendors/withVendorActions';
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
import withItemsActions from 'containers/Items/withItemsActions';
|
||||
import withBillActions from './withBillActions';
|
||||
import withSettingsActions from 'containers/Settings/withSettingsActions';
|
||||
import { BillFormProvider } from './BillFormProvider';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
@@ -17,27 +11,11 @@ import { compose } from 'utils';
|
||||
import 'style/pages/Bills/PageForm.scss';
|
||||
|
||||
function BillFormPage({
|
||||
// #withwithAccountsActions
|
||||
requestFetchAccounts,
|
||||
|
||||
// #withVendorActions
|
||||
requestFetchVendorsTable,
|
||||
|
||||
// #withItemsActions
|
||||
requestFetchItems,
|
||||
|
||||
// #withBilleActions
|
||||
requestFetchBill,
|
||||
|
||||
// #withSettingsActions
|
||||
requestFetchOptions,
|
||||
|
||||
// #withDashboardActions
|
||||
setSidebarShrink,
|
||||
resetSidebarPreviousExpand,
|
||||
setDashboardBackLink
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { id } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -54,62 +32,14 @@ function BillFormPage({
|
||||
};
|
||||
}, [resetSidebarPreviousExpand, setSidebarShrink, setDashboardBackLink]);
|
||||
|
||||
// Handle fetch accounts
|
||||
const fetchAccounts = useQuery('accounts-list', (key) =>
|
||||
requestFetchAccounts(),
|
||||
);
|
||||
|
||||
// Handle fetch customers data table
|
||||
const fetchVendors = useQuery('vendors-list', () =>
|
||||
requestFetchVendorsTable({}),
|
||||
);
|
||||
|
||||
// Handle fetch Items data table or list
|
||||
const fetchItems = useQuery('items-list', () => requestFetchItems({}));
|
||||
|
||||
const fetchSettings = useQuery(['settings'], () => requestFetchOptions({}));
|
||||
|
||||
const handleFormSubmit = useCallback(
|
||||
(payload) => {
|
||||
payload.redirect && history.push('/bills');
|
||||
},
|
||||
[history],
|
||||
);
|
||||
|
||||
const handleCancel = useCallback(() => {
|
||||
history.goBack();
|
||||
}, [history]);
|
||||
|
||||
const fetchBill = useQuery(
|
||||
['bill', id],
|
||||
(key, _id) => requestFetchBill(_id),
|
||||
{ enabled: !!id },
|
||||
);
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={
|
||||
fetchVendors.isFetching ||
|
||||
fetchItems.isFetching ||
|
||||
fetchAccounts.isFetching ||
|
||||
fetchBill.isFetching
|
||||
}
|
||||
name={'bill-form'}
|
||||
>
|
||||
<BillForm
|
||||
onFormSubmit={handleFormSubmit}
|
||||
billId={id}
|
||||
onCancelForm={handleCancel}
|
||||
/>
|
||||
</DashboardInsider>
|
||||
<BillFormProvider billId={id}>
|
||||
<BillForm />
|
||||
</BillFormProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withBillActions,
|
||||
withVendorActions,
|
||||
withItemsActions,
|
||||
withAccountsActions,
|
||||
withSettingsActions,
|
||||
|
||||
withDashboardActions
|
||||
)(BillFormPage);
|
||||
|
||||
81
client/src/containers/Purchases/Bill/BillFormProvider.js
Normal file
81
client/src/containers/Purchases/Bill/BillFormProvider.js
Normal file
@@ -0,0 +1,81 @@
|
||||
import React, { createContext, useState } from 'react';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import {
|
||||
useAccounts,
|
||||
useVendors,
|
||||
useItems,
|
||||
useBill,
|
||||
useSettings,
|
||||
useCreateBill,
|
||||
useEditBill
|
||||
} from 'hooks/query';
|
||||
|
||||
const BillFormContext = createContext();
|
||||
|
||||
/**
|
||||
* Bill form provider.
|
||||
*/
|
||||
function BillFormProvider({ billId, ...props }) {
|
||||
// Handle fetch accounts.
|
||||
const { data: accounts, isFetching: isAccountsLoading } = useAccounts();
|
||||
|
||||
// Handle fetch vendors data table
|
||||
const {
|
||||
data: { vendors },
|
||||
isFetching: isVendorsLoading,
|
||||
} = useVendors();
|
||||
|
||||
// Handle fetch Items data table or list
|
||||
const {
|
||||
data: { items },
|
||||
isFetching: isItemsLoading,
|
||||
} = useItems();
|
||||
|
||||
// Handle fetch bill details.
|
||||
const { data: bill, isFetching: isBillLoading } = useBill(billId, {
|
||||
enabled: !!billId,
|
||||
});
|
||||
|
||||
// Handle fetching bill settings.
|
||||
const { isFetching: isSettingLoading } = useSettings();
|
||||
|
||||
// Form submit payload.
|
||||
const [submitPayload, setSubmitPayload] = useState({});
|
||||
|
||||
// Create and edit bills mutations.
|
||||
const { mutateAsync: createBillMutate } = useCreateBill();
|
||||
const { mutateAsync: editBillMutate } = useEditBill();
|
||||
|
||||
const provider = {
|
||||
accounts,
|
||||
vendors,
|
||||
items,
|
||||
bill,
|
||||
submitPayload,
|
||||
|
||||
isSettingLoading,
|
||||
isBillLoading,
|
||||
isAccountsLoading,
|
||||
isItemsLoading,
|
||||
isVendorsLoading,
|
||||
|
||||
createBillMutate,
|
||||
editBillMutate,
|
||||
setSubmitPayload
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={
|
||||
isVendorsLoading || isItemsLoading || isAccountsLoading || isBillLoading
|
||||
}
|
||||
name={'bill-form'}
|
||||
>
|
||||
<BillFormContext.Provider value={provider} {...props} />
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
const useBillFormContext = () => React.useContext(BillFormContext);
|
||||
|
||||
export { BillFormProvider, useBillFormContext };
|
||||
@@ -1,59 +1,32 @@
|
||||
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 { pick, debounce } from 'lodash';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { pick } from 'lodash';
|
||||
|
||||
import { DashboardViewsTabs } from 'components';
|
||||
import { useUpdateEffect } from 'hooks';
|
||||
|
||||
import withBills from './withBills';
|
||||
import { useBillsListContext } from './BillsListProvider';
|
||||
import withBillActions from './withBillActions';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withViewDetails from 'containers/Views/withViewDetails';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Bills view tabs.
|
||||
*/
|
||||
function BillViewTabs({
|
||||
//#withBills
|
||||
billsViews,
|
||||
|
||||
// #withViewDetails
|
||||
viewItem,
|
||||
|
||||
//#withBillActions
|
||||
changeBillView,
|
||||
addBillsTableQueries,
|
||||
|
||||
// #withDashboardActions
|
||||
setTopbarEditView,
|
||||
changePageSubtitle,
|
||||
|
||||
// #ownProps
|
||||
customViewChanged,
|
||||
onViewChanged,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { custom_view_id: customViewId = null } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
setTopbarEditView(customViewId);
|
||||
changePageSubtitle(customViewId && viewItem ? viewItem.name : '');
|
||||
}, [customViewId]);
|
||||
|
||||
// Handle click a new view tab.
|
||||
const handleClickNewView = () => {
|
||||
setTopbarEditView(null);
|
||||
history.push('/custom_views/invoices/new');
|
||||
};
|
||||
// Bills list context.
|
||||
const { billsViews } = useBillsListContext();
|
||||
|
||||
const handleTabsChange = (viewId) => {
|
||||
changeBillView(viewId || -1);
|
||||
addBillsTableQueries({
|
||||
custom_view_id: customViewId || null,
|
||||
});
|
||||
setTopbarEditView(viewId);
|
||||
};
|
||||
|
||||
const tabs = billsViews.map((view) => ({
|
||||
@@ -67,7 +40,6 @@ function BillViewTabs({
|
||||
initialViewId={customViewId}
|
||||
resourceName={'bills'}
|
||||
tabs={tabs}
|
||||
onNewViewTabClick={handleClickNewView}
|
||||
onChange={handleTabsChange}
|
||||
/>
|
||||
</NavbarGroup>
|
||||
@@ -75,19 +47,4 @@ function BillViewTabs({
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
viewId: ownProps.match.params.custom_view_id,
|
||||
});
|
||||
|
||||
const withBillsViewTabs = connect(mapStateToProps);
|
||||
|
||||
export default compose(
|
||||
withRouter,
|
||||
withBillsViewTabs,
|
||||
withBillActions,
|
||||
withDashboardActions,
|
||||
withViewDetails(),
|
||||
withBills(({ billsViews }) => ({
|
||||
billsViews,
|
||||
})),
|
||||
)(BillViewTabs);
|
||||
export default compose(withBillActions)(BillViewTabs);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useState, useMemo } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import Icon from 'components/Icon';
|
||||
import {
|
||||
Button,
|
||||
@@ -15,66 +15,40 @@ import classNames from 'classnames';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import FilterDropdown from 'components/FilterDropdown';
|
||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
||||
|
||||
import { If, DashboardActionViewsList } from 'components';
|
||||
|
||||
import withResourceDetail from 'containers/Resources/withResourceDetails';
|
||||
import withBillActions from './withBillActions';
|
||||
import withBills from './withBills';
|
||||
import { useBillsListContext } from './BillsListProvider';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Bills actions bar.
|
||||
*/
|
||||
function BillActionsBar({
|
||||
// #withResourceDetail
|
||||
resourceFields,
|
||||
|
||||
//#withBills
|
||||
billsViews,
|
||||
|
||||
//#withBillActions
|
||||
addBillsTableQueries,
|
||||
changeBillView,
|
||||
// #own Porps
|
||||
onFilterChanged,
|
||||
selectedRows = [],
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const [filterCount, setFilterCount] = useState(0);
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
// Bills list context.
|
||||
const { billsViews } = useBillsListContext();
|
||||
|
||||
const [filterCount] = useState(0);
|
||||
|
||||
const handleClickNewBill = useCallback(() => {
|
||||
// Handle click a new bill.
|
||||
const handleClickNewBill = () => {
|
||||
history.push('/bills/new');
|
||||
}, [history]);
|
||||
|
||||
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [
|
||||
selectedRows,
|
||||
]);
|
||||
|
||||
};
|
||||
// Handle tab change.
|
||||
const handleTabChange = (viewId) => {
|
||||
changeBillView(viewId.id || -1);
|
||||
addBillsTableQueries({
|
||||
custom_view_id: viewId.id || null,
|
||||
});
|
||||
};
|
||||
|
||||
// const FilterDropdown = FilterDropdown({
|
||||
// initialCondition: {
|
||||
// fieldKey: '',
|
||||
// compatator: '',
|
||||
// value: '',
|
||||
// },
|
||||
// fields: resourceFields,
|
||||
// onFilterChange: (filterConditions) => {
|
||||
// addBillsTableQueries({
|
||||
// filter_roles: filterConditions || '',
|
||||
// });
|
||||
// onFilterChanged && onFilterChanged(filterConditions);
|
||||
// },
|
||||
// });
|
||||
|
||||
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
@@ -99,7 +73,7 @@ function BillActionsBar({
|
||||
<Button
|
||||
className={classNames(Classes.MINIMAL)}
|
||||
text={
|
||||
filterCount <= 0 ? (
|
||||
true ? (
|
||||
<T id={'filter'} />
|
||||
) : (
|
||||
`${filterCount} ${formatMessage({ id: 'filters_applied' })}`
|
||||
@@ -108,7 +82,7 @@ function BillActionsBar({
|
||||
icon={<Icon icon={'filter-16'} iconSize={16} />}
|
||||
/>
|
||||
</Popover>
|
||||
<If condition={hasSelectedRows}>
|
||||
<If condition={false}>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon={'trash-16'} iconSize={16} />}
|
||||
@@ -137,18 +111,6 @@ function BillActionsBar({
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
resourceName: 'bills',
|
||||
});
|
||||
const withBillActionsBar = connect(mapStateToProps);
|
||||
|
||||
export default compose(
|
||||
withBillActionsBar,
|
||||
withResourceDetail(({ resourceFields }) => ({
|
||||
resourceFields,
|
||||
})),
|
||||
withBills(({ billsViews }) => ({
|
||||
billsViews,
|
||||
})),
|
||||
withBillActions,
|
||||
)(BillActionsBar);
|
||||
12
client/src/containers/Purchases/Bill/BillsAlerts.js
Normal file
12
client/src/containers/Purchases/Bill/BillsAlerts.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import BillOpenAlert from 'containers/Alerts/Bills/BillOpenAlert';
|
||||
import BillDeleteAlert from 'containers/Alerts/Bills/BillDeleteAlert';
|
||||
|
||||
export default function BillsAlerts() {
|
||||
return (
|
||||
<div class="bills-alerts">
|
||||
<BillDeleteAlert name={'bill-delete'} />
|
||||
<BillOpenAlert name={'bill-open'} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useCallback, useMemo } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import {
|
||||
Intent,
|
||||
Button,
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
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';
|
||||
@@ -65,7 +64,6 @@ function BillsDataTable({
|
||||
onSelectedRowsChange,
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
const isLoadedBefore = useIsValuePassed(billsLoading, false);
|
||||
|
||||
const handleFetchData = useCallback(
|
||||
({ pageIndex, pageSize, sortBy }) => {
|
||||
@@ -243,31 +241,29 @@ function BillsDataTable({
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<LoadingIndicator loading={billsLoading && !isLoadedBefore} mount={false}>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<BillsEmptyStatus />
|
||||
</Choose.When>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<BillsEmptyStatus />
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={billsCurrentPage}
|
||||
onFetchData={handleFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={billsPageination.pagesCount}
|
||||
initialPageSize={billsPageination.pageSize}
|
||||
initialPageIndex={billsPageination.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={billsCurrentPage}
|
||||
onFetchData={handleFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={billsPageination.pagesCount}
|
||||
initialPageSize={billsPageination.pageSize}
|
||||
initialPageIndex={billsPageination.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,16 @@
|
||||
import React, { useEffect, useCallback, useMemo, useState } from 'react';
|
||||
import { Route, Switch, useHistory } from 'react-router-dom';
|
||||
import { useQuery, queryCache } from 'react-query';
|
||||
import { Alert, Intent } from '@blueprintjs/core';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import AppToaster from 'components/AppToaster';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import { useIntl } from 'react-intl';
|
||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
|
||||
import { BillsListProvider } from './BillsListProvider';
|
||||
import BillsDataTable from './BillsDataTable';
|
||||
import BillActionsBar from './BillActionsBar';
|
||||
import BillViewTabs from './BillViewTabs';
|
||||
import BillsActionsBar from './BillsActionsBar';
|
||||
import BillsAlerts from './BillsAlerts';
|
||||
import BillsViewPage from './BillsViewPage';
|
||||
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withResourceActions from 'containers/Resources/withResourcesActions';
|
||||
|
||||
import withBills from './withBills';
|
||||
import withBillActions from './withBillActions';
|
||||
import withViewsActions from 'containers/Views/withViewsActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
@@ -28,170 +21,29 @@ function BillsList({
|
||||
// #withDashboardActions
|
||||
changePageTitle,
|
||||
|
||||
// #withViewsActions
|
||||
requestFetchResourceViews,
|
||||
requestFetchResourceFields,
|
||||
|
||||
//#withBills
|
||||
// #withBills
|
||||
billsTableQuery,
|
||||
|
||||
//#withBillActions
|
||||
requestFetchBillsTable,
|
||||
requestDeleteBill,
|
||||
requestOpenBill,
|
||||
addBillsTableQueries,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { formatMessage } = useIntl();
|
||||
const [deleteBill, setDeleteBill] = useState(false);
|
||||
const [openBill, setOpenBill] = useState(false);
|
||||
const [selectedRows, setSelectedRows] = useState([]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
changePageTitle(formatMessage({ id: 'bills_list' }));
|
||||
}, [changePageTitle, formatMessage]);
|
||||
|
||||
const fetchResourceViews = useQuery(
|
||||
['resource-views', 'bills'],
|
||||
(key, resourceName) => requestFetchResourceViews(resourceName),
|
||||
);
|
||||
|
||||
const fetchResourceFields = useQuery(
|
||||
['resource-fields', 'bills'],
|
||||
(key, resourceName) => requestFetchResourceFields(resourceName),
|
||||
);
|
||||
|
||||
const fetchBills = useQuery(['bills-table', billsTableQuery], (key, query) =>
|
||||
requestFetchBillsTable({ ...query }),
|
||||
);
|
||||
|
||||
//handle dalete Bill
|
||||
const handleDeleteBill = useCallback(
|
||||
(bill) => {
|
||||
setDeleteBill(bill);
|
||||
},
|
||||
[setDeleteBill],
|
||||
);
|
||||
|
||||
// handle cancel Bill
|
||||
const handleCancelBillDelete = useCallback(() => {
|
||||
setDeleteBill(false);
|
||||
}, [setDeleteBill]);
|
||||
|
||||
// handleConfirm delete invoice
|
||||
const handleConfirmBillDelete = useCallback(() => {
|
||||
requestDeleteBill(deleteBill.id).then(() => {
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_bill_has_been_deleted_successfully',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
setDeleteBill(false);
|
||||
});
|
||||
}, [deleteBill, requestDeleteBill, formatMessage]);
|
||||
|
||||
// Handle cancel/confirm bill open.
|
||||
const handleOpenBill = useCallback((bill) => {
|
||||
setOpenBill(bill);
|
||||
}, []);
|
||||
|
||||
// Handle cancel open bill alert.
|
||||
const handleCancelOpenBill = useCallback(() => {
|
||||
setOpenBill(false);
|
||||
}, []);
|
||||
|
||||
// Handle confirm bill open.
|
||||
const handleConfirmBillOpen = useCallback(() => {
|
||||
requestOpenBill(openBill.id)
|
||||
.then(() => {
|
||||
setOpenBill(false);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_bill_has_been_opened_successfully',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('bills-table');
|
||||
})
|
||||
.catch((error) => {});
|
||||
}, [openBill, requestOpenBill, formatMessage]);
|
||||
|
||||
const handleEditBill = useCallback((bill) => {
|
||||
history.push(`/bills/${bill.id}/edit`);
|
||||
});
|
||||
|
||||
// Handle selected rows change.
|
||||
const handleSelectedRowsChange = useCallback(
|
||||
(_invoices) => {
|
||||
setSelectedRows(_invoices);
|
||||
},
|
||||
[setSelectedRows],
|
||||
);
|
||||
|
||||
// Handle filter change to re-fetch data-table.
|
||||
const handleFilterChanged = useCallback((filterConditions) => {}, []);
|
||||
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={fetchResourceViews.isFetching || fetchResourceFields.isFetching}
|
||||
name={'bills'}
|
||||
>
|
||||
<BillActionsBar
|
||||
// onBulkDelete={}
|
||||
selectedRows={selectedRows}
|
||||
onFilterChanged={handleFilterChanged}
|
||||
/>
|
||||
<BillsListProvider query={billsTableQuery}>
|
||||
<BillsActionsBar />
|
||||
|
||||
<DashboardPageContent>
|
||||
<Switch>
|
||||
<Route
|
||||
exact={true}
|
||||
path={['/bills/:custom_view_id/custom_view', '/bills']}
|
||||
>
|
||||
<BillViewTabs />
|
||||
<BillsDataTable
|
||||
onDeleteBill={handleDeleteBill}
|
||||
onEditBill={handleEditBill}
|
||||
onOpenBill={handleOpenBill}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={<T id={'delete'} />}
|
||||
icon={'trash'}
|
||||
intent={Intent.DANGER}
|
||||
isOpen={deleteBill}
|
||||
onCancel={handleCancelBillDelete}
|
||||
onConfirm={handleConfirmBillDelete}
|
||||
>
|
||||
<p>
|
||||
<T id={'once_delete_this_bill_you_will_able_to_restore_it'} />
|
||||
</p>
|
||||
</Alert>
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={<T id={'open'} />}
|
||||
intent={Intent.WARNING}
|
||||
isOpen={openBill}
|
||||
onCancel={handleCancelOpenBill}
|
||||
onConfirm={handleConfirmBillOpen}
|
||||
>
|
||||
<p>
|
||||
<T id={'are_sure_to_open_this_bill'} />
|
||||
</p>
|
||||
</Alert>
|
||||
<BillsViewPage />
|
||||
<BillsAlerts />
|
||||
</DashboardPageContent>
|
||||
</DashboardInsider>
|
||||
</BillsListProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withResourceActions,
|
||||
withBillActions,
|
||||
withDashboardActions,
|
||||
withViewsActions,
|
||||
withBills(({ billsTableQuery }) => ({
|
||||
billsTableQuery,
|
||||
})),
|
||||
|
||||
52
client/src/containers/Purchases/Bill/BillsListProvider.js
Normal file
52
client/src/containers/Purchases/Bill/BillsListProvider.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import React, { createContext } from 'react';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import { useResourceViews, useResourceFields, useBills } from 'hooks/query';
|
||||
|
||||
const BillsListContext = createContext();
|
||||
|
||||
/**
|
||||
* Accounts chart data provider.
|
||||
*/
|
||||
function BillsListProvider({ query, ...props }) {
|
||||
// Fetch accounts resource views and fields.
|
||||
const { data: billsViews, isFetching: isViewsLoading } = useResourceViews(
|
||||
'bills',
|
||||
);
|
||||
|
||||
// Fetch the accounts resource fields.
|
||||
const {
|
||||
data: billsFields,
|
||||
isFetching: isFieldsLoading,
|
||||
} = useResourceFields('bills');
|
||||
|
||||
// Fetch accounts list according to the given custom view id.
|
||||
const {
|
||||
data: { bills, pagination },
|
||||
isFetching: isBillsLoading,
|
||||
} = useBills(query);
|
||||
|
||||
// Provider payload.
|
||||
const provider = {
|
||||
bills,
|
||||
pagination,
|
||||
billsFields,
|
||||
billsViews,
|
||||
|
||||
isBillsLoading,
|
||||
isFieldsLoading,
|
||||
isViewsLoading,
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={isViewsLoading || isFieldsLoading}
|
||||
name={'bills'}
|
||||
>
|
||||
<BillsListContext.Provider value={provider} {...props} />
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
const useBillsListContext = () => React.useContext(BillsListContext);
|
||||
|
||||
export { BillsListProvider, useBillsListContext };
|
||||
49
client/src/containers/Purchases/Bill/BillsViewPage.js
Normal file
49
client/src/containers/Purchases/Bill/BillsViewPage.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import { Switch, Route, useHistory } from 'react-router-dom';
|
||||
import BillViewTabs from './BillViewTabs';
|
||||
import BillsDataTable from './BillsDataTable';
|
||||
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
function BillsViewPage() {
|
||||
const history = useHistory();
|
||||
|
||||
const handleEditBill = useCallback((bill) => {
|
||||
history.push(`/bills/${bill.id}/edit`);
|
||||
});
|
||||
|
||||
const handleDeleteBill = () => {
|
||||
|
||||
};
|
||||
|
||||
|
||||
const handleOpenBill = () => {
|
||||
|
||||
};
|
||||
|
||||
const handleSelectedRowsChange = () => {
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Route
|
||||
exact={true}
|
||||
path={['/bills/:custom_view_id/custom_view', '/bills']}
|
||||
>
|
||||
<BillViewTabs />
|
||||
{/* <BillsDataTable
|
||||
onDeleteBill={handleDeleteBill}
|
||||
onEditBill={handleEditBill}
|
||||
onOpenBill={handleOpenBill}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
/> */}
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
export default compose(withAlertsActions, withDialogActions)(BillsViewPage);
|
||||
@@ -1,10 +1,8 @@
|
||||
import React, { useCallback, useState, useMemo } from 'react';
|
||||
import React from 'react';
|
||||
import Icon from 'components/Icon';
|
||||
import {
|
||||
Button,
|
||||
Classes,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Popover,
|
||||
NavbarDivider,
|
||||
NavbarGroup,
|
||||
@@ -14,69 +12,41 @@ import {
|
||||
} from '@blueprintjs/core';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { useRouteMatch, useHistory } from 'react-router-dom';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import FilterDropdown from 'components/FilterDropdown';
|
||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
||||
|
||||
import { If, DashboardActionViewsList } from 'components';
|
||||
|
||||
import withResourceDetail from 'containers/Resources/withResourceDetails';
|
||||
import withPaymentMade from './withPaymentMade';
|
||||
import withPaymentMadeActions from './withPaymentMadeActions';
|
||||
import { usePaymentMadesListContext } from './PaymentMadesListProvider';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Payment made actions bar.
|
||||
*/
|
||||
function PaymentMadeActionsBar({
|
||||
//#withResourceDetail
|
||||
resourceFields,
|
||||
|
||||
//#withPaymentMades
|
||||
paymentMadeViews,
|
||||
|
||||
//#withPaymentMadesActions
|
||||
addPaymentMadesTableQueries,
|
||||
|
||||
// #own Porps
|
||||
onFilterChanged,
|
||||
selectedRows = [],
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { path } = useRouteMatch();
|
||||
const [filterCount, setFilterCount] = useState(0);
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const handleClickNewPaymentMade = useCallback(() => {
|
||||
// Payment receives list context.
|
||||
const { paymentMadesViews } = usePaymentMadesListContext();
|
||||
|
||||
// Handle new payment made button click.
|
||||
const handleClickNewPaymentMade = () => {
|
||||
history.push('/payment-mades/new');
|
||||
}, [history]);
|
||||
|
||||
// const filterDropdown = FilterDropdown({
|
||||
// initialCondition: {
|
||||
// fieldKey: '',
|
||||
// compatator: 'contains',
|
||||
// value: '',
|
||||
// },
|
||||
// fields: resourceFields,
|
||||
// onFilterChange: (filterConditions) => {
|
||||
// addPaymentMadesTableQueries({
|
||||
// filter_roles: filterConditions || '',
|
||||
// });
|
||||
// onFilterChanged && onFilterChanged(filterConditions);
|
||||
// },
|
||||
// });
|
||||
|
||||
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [
|
||||
selectedRows,
|
||||
]);
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<DashboardActionViewsList
|
||||
resourceName={'bill_payments'}
|
||||
views={paymentMadeViews}
|
||||
views={paymentMadesViews}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
<Button
|
||||
@@ -94,16 +64,16 @@ function PaymentMadeActionsBar({
|
||||
<Button
|
||||
className={classNames(Classes.MINIMAL)}
|
||||
text={
|
||||
filterCount <= 0 ? (
|
||||
true ? (
|
||||
<T id={'filter'} />
|
||||
) : (
|
||||
`${filterCount} ${formatMessage({ id: 'filters_applied' })}`
|
||||
`${0} ${formatMessage({ id: 'filters_applied' })}`
|
||||
)
|
||||
}
|
||||
icon={<Icon icon={'filter-16'} iconSize={16} />}
|
||||
/>
|
||||
</Popover>
|
||||
<If condition={hasSelectedRows}>
|
||||
<If condition={false}>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon={'trash-16'} iconSize={16} />}
|
||||
@@ -132,19 +102,4 @@ function PaymentMadeActionsBar({
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
resourceName: 'bill_payments',
|
||||
});
|
||||
|
||||
const withPaymentMadeActionsBar = connect(mapStateToProps);
|
||||
|
||||
export default compose(
|
||||
withPaymentMadeActionsBar,
|
||||
withResourceDetail(({ resourceFields }) => ({
|
||||
resourceFields,
|
||||
})),
|
||||
withPaymentMade(({ paymentMadeViews }) => ({
|
||||
paymentMadeViews,
|
||||
})),
|
||||
withPaymentMadeActions,
|
||||
)(PaymentMadeActionsBar);
|
||||
export default compose(withPaymentMadeActions)(PaymentMadeActionsBar);
|
||||
|
||||
@@ -1,164 +1,47 @@
|
||||
import React, { useEffect, useCallback, useMemo, useState } from 'react';
|
||||
import { Route, Switch, useHistory } from 'react-router-dom';
|
||||
import { useQuery, queryCache } from 'react-query';
|
||||
import { Alert, Intent } from '@blueprintjs/core';
|
||||
|
||||
import AppToaster from 'components/AppToaster';
|
||||
import React, { useEffect } from 'react';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
|
||||
import PaymentMadeDataTable from './PaymentMadeDataTable';
|
||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
import PaymentMadeActionsBar from './PaymentMadeActionsBar';
|
||||
import PaymentMadeViewTabs from './PaymentMadeViewTabs';
|
||||
import PaymentMadesAlerts from './PaymentMadesAlerts';
|
||||
import { PaymentMadesListProvider } from './PaymentMadesListProvider';
|
||||
import PaymentMadesView from './PaymentMadesView';
|
||||
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withResourceActions from 'containers/Resources/withResourcesActions';
|
||||
import withPaymentMades from './withPaymentMade';
|
||||
import withPaymentMadeActions from './withPaymentMadeActions';
|
||||
import withViewsActions from 'containers/Views/withViewsActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Payment mades list.
|
||||
*/
|
||||
function PaymentMadeList({
|
||||
//#withDashboardActions
|
||||
// #withDashboardActions
|
||||
changePageTitle,
|
||||
|
||||
//#withViewsActions
|
||||
requestFetchResourceViews,
|
||||
requestFetchResourceFields,
|
||||
|
||||
//#withPaymentMades
|
||||
// #withPaymentMades
|
||||
paymentMadeTableQuery,
|
||||
|
||||
//#withPaymentMadesActions
|
||||
requestFetchPaymentMadesTable,
|
||||
requestDeletePaymentMade,
|
||||
addPaymentMadesTableQueries,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { formatMessage } = useIntl();
|
||||
const [deletePaymentMade, setDeletePaymentMade] = useState(false);
|
||||
const [selectedRows, setSelectedRows] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
changePageTitle(formatMessage({ id: 'payment_made_list' }));
|
||||
}, [changePageTitle, formatMessage]);
|
||||
|
||||
const fetchResourceViews = useQuery(
|
||||
['resource-views', 'bill_payments'],
|
||||
(key, resourceName) => requestFetchResourceViews(resourceName),
|
||||
);
|
||||
|
||||
const fetchResourceFields = useQuery(
|
||||
['resource-fields', 'bill_payments'],
|
||||
(key, resourceName) => requestFetchResourceFields(resourceName),
|
||||
);
|
||||
|
||||
const fetchPaymentMades = useQuery(
|
||||
['paymantMades-table', paymentMadeTableQuery],
|
||||
() => requestFetchPaymentMadesTable(),
|
||||
);
|
||||
|
||||
//handle dalete Payment Made
|
||||
const handleDeletePaymentMade = useCallback(
|
||||
(paymentMade) => {
|
||||
setDeletePaymentMade(paymentMade);
|
||||
},
|
||||
[setDeletePaymentMade],
|
||||
);
|
||||
|
||||
// handle cancel Payment Made
|
||||
const handleCancelPaymentMadeDelete = useCallback(() => {
|
||||
setDeletePaymentMade(false);
|
||||
}, [setDeletePaymentMade]);
|
||||
|
||||
// handleConfirm delete payment made
|
||||
const handleConfirmPaymentMadeDelete = useCallback(() => {
|
||||
requestDeletePaymentMade(deletePaymentMade.id).then(() => {
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_payment_made_has_been_deleted_successfully',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
setDeletePaymentMade(false);
|
||||
});
|
||||
}, [deletePaymentMade, requestDeletePaymentMade, formatMessage]);
|
||||
|
||||
const handleEditPaymentMade = useCallback((payment) => {
|
||||
history.push(`/payment-mades/${payment.id}/edit`);
|
||||
});
|
||||
|
||||
// Calculates the selected rows count.
|
||||
const selectedRowsCount = useMemo(() => Object.values(selectedRows).length, [
|
||||
selectedRows,
|
||||
]);
|
||||
|
||||
// Handle filter change to re-fetch data-table.
|
||||
const handleFilterChanged = useCallback(() => {}, [fetchPaymentMades]);
|
||||
|
||||
// Handle selected rows change.
|
||||
const handleSelectedRowsChange = useCallback(
|
||||
(payment) => {
|
||||
setSelectedRows(payment);
|
||||
},
|
||||
[setSelectedRows],
|
||||
);
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
// loading={fetchResourceViews.isFetching || fetchResourceFields.isFetching}
|
||||
name={'payment_made'}
|
||||
>
|
||||
<PaymentMadeActionsBar
|
||||
// onBulkDelete={}
|
||||
selectedRows={selectedRows}
|
||||
onFilterChanged={handleFilterChanged}
|
||||
/>
|
||||
<DashboardPageContent>
|
||||
<Switch>
|
||||
<Route
|
||||
exact={true}
|
||||
path={[
|
||||
'/payment-mades/:custom_view_id/custom_view',
|
||||
'/payment-mades',
|
||||
]}
|
||||
>
|
||||
<PaymentMadeViewTabs />
|
||||
<PaymentMadeDataTable
|
||||
onDeletePaymentMade={handleDeletePaymentMade}
|
||||
onEditPaymentMade={handleEditPaymentMade}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
<PaymentMadesListProvider query={paymentMadeTableQuery}>
|
||||
<PaymentMadeActionsBar />
|
||||
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={<T id={'delete'} />}
|
||||
icon={'trash'}
|
||||
intent={Intent.DANGER}
|
||||
isOpen={deletePaymentMade}
|
||||
onCancel={handleCancelPaymentMadeDelete}
|
||||
onConfirm={handleConfirmPaymentMadeDelete}
|
||||
>
|
||||
<p>
|
||||
<T
|
||||
id={'once_delete_this_payment_made_you_will_able_to_restore_it'}
|
||||
/>
|
||||
</p>
|
||||
</Alert>
|
||||
<DashboardPageContent>
|
||||
<PaymentMadesView />
|
||||
<PaymentMadesAlerts />
|
||||
</DashboardPageContent>
|
||||
</DashboardInsider>
|
||||
</PaymentMadesListProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withResourceActions,
|
||||
withPaymentMadeActions,
|
||||
withDashboardActions,
|
||||
withViewsActions,
|
||||
withPaymentMades(({ paymentMadeTableQuery }) => ({
|
||||
paymentMadeTableQuery,
|
||||
})),
|
||||
|
||||
@@ -1,78 +1,38 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { Alignment, Navbar, NavbarGroup } from '@blueprintjs/core';
|
||||
import { useParams, withRouter } from 'react-router-dom';
|
||||
import { connect } from 'react-redux';
|
||||
import { pick, debounce } from 'lodash';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { pick } from 'lodash';
|
||||
|
||||
import { DashboardViewsTabs } from 'components';
|
||||
import { useUpdateEffect } from 'hooks';
|
||||
|
||||
import withPaymentMade from './withPaymentMade';
|
||||
import { usePaymentMadesListContext } from './PaymentMadesListProvider';
|
||||
import withPaymentMadeActions from './withPaymentMadeActions';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withViewDetails from 'containers/Views/withViewDetails';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
function PaymentMadeViewTabs({
|
||||
//#withPaymentMades
|
||||
paymentMadeViews,
|
||||
|
||||
//#withPaymentMadesActions
|
||||
changePaymentMadeView,
|
||||
addPaymentMadesTableQueries,
|
||||
|
||||
// #withViewDetails
|
||||
viewItem,
|
||||
|
||||
// #withDashboardActions
|
||||
setTopbarEditView,
|
||||
changePageSubtitle,
|
||||
|
||||
//#Own Props
|
||||
onViewChanged,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { custom_view_id: customViewId = null } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
changePaymentMadeView(customViewId || -1);
|
||||
setTopbarEditView(customViewId);
|
||||
changePageSubtitle(customViewId && viewItem ? viewItem.name : '');
|
||||
|
||||
addPaymentMadesTableQueries({
|
||||
custom_view_id: customViewId,
|
||||
});
|
||||
return () => {
|
||||
setTopbarEditView(null);
|
||||
changePageSubtitle('');
|
||||
changePaymentMadeView(null);
|
||||
};
|
||||
}, [customViewId, addPaymentMadesTableQueries, changePaymentMadeView]);
|
||||
|
||||
useUpdateEffect(() => {
|
||||
onViewChanged && onViewChanged(customViewId);
|
||||
}, [customViewId]);
|
||||
|
||||
const debounceChangeHistory = useRef(
|
||||
debounce((toUrl) => {
|
||||
history.push(toUrl);
|
||||
}, 250),
|
||||
);
|
||||
// Payment receives list context.
|
||||
const { paymentMadesViews } = usePaymentMadesListContext();
|
||||
|
||||
const handleTabsChange = (viewId) => {
|
||||
const toPath = viewId ? `${viewId}/custom_view` : '';
|
||||
debounceChangeHistory.current(`/payment-mades/${toPath}`);
|
||||
setTopbarEditView(viewId);
|
||||
addPaymentMadesTableQueries({
|
||||
custom_view_id: viewId || null,
|
||||
});
|
||||
};
|
||||
const tabs = paymentMadeViews.map((view) => ({
|
||||
|
||||
const tabs = paymentMadesViews.map((view) => ({
|
||||
...pick(view, ['name', 'id']),
|
||||
}));
|
||||
|
||||
const handleClickNewView = () => {
|
||||
setTopbarEditView(null);
|
||||
history.push('/custom_views/payment-mades/new');
|
||||
};
|
||||
|
||||
@@ -91,19 +51,4 @@ function PaymentMadeViewTabs({
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
viewId: ownProps.match.params.custom_view_id,
|
||||
});
|
||||
|
||||
const withPaymentMadesViewTabs = connect(mapStateToProps);
|
||||
|
||||
export default compose(
|
||||
withRouter,
|
||||
withPaymentMadesViewTabs,
|
||||
withPaymentMadeActions,
|
||||
withDashboardActions,
|
||||
withViewDetails(),
|
||||
withPaymentMade(({ paymentMadeViews }) => ({
|
||||
paymentMadeViews,
|
||||
})),
|
||||
)(PaymentMadeViewTabs);
|
||||
export default compose(withPaymentMadeActions)(PaymentMadeViewTabs);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import PaymentMadeDeleteAlert from 'containers/Alerts/PaymentMades/PaymentMadeDeleteAlert';
|
||||
|
||||
export default function PaymentMadesAlerts() {
|
||||
return (
|
||||
<div>
|
||||
<PaymentMadeDeleteAlert dialogName={'payment-made-delete'} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import React, { createContext } from 'react';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import {
|
||||
useResourceViews,
|
||||
useResourceFields,
|
||||
usePaymentReceives,
|
||||
} from 'hooks/query';
|
||||
|
||||
const PaymentMadesListContext = createContext();
|
||||
|
||||
/**
|
||||
* Accounts chart data provider.
|
||||
*/
|
||||
function PaymentMadesListProvider({ accountsTableQuery, ...props }) {
|
||||
// Fetch accounts resource views and fields.
|
||||
const {
|
||||
data: paymentMadesViews,
|
||||
isFetching: isViewsLoading,
|
||||
} = useResourceViews('bill_payments');
|
||||
|
||||
// Fetch the accounts resource fields.
|
||||
const {
|
||||
data: paymentMadesFields,
|
||||
isFetching: isFieldsLoading,
|
||||
} = useResourceFields('bill_payments');
|
||||
|
||||
// Fetch accounts list according to the given custom view id.
|
||||
const {
|
||||
data: { paymentMades, pagination },
|
||||
isFetching: isInvoicesLoading,
|
||||
} = usePaymentReceives(accountsTableQuery);
|
||||
|
||||
// Provider payload.
|
||||
const provider = {
|
||||
paymentMades,
|
||||
pagination,
|
||||
paymentMadesFields,
|
||||
paymentMadesViews,
|
||||
|
||||
isInvoicesLoading,
|
||||
isFieldsLoading,
|
||||
isViewsLoading,
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={isViewsLoading || isFieldsLoading}
|
||||
name={'payment-mades-list'}
|
||||
>
|
||||
<PaymentMadesListContext.Provider value={provider} {...props} />
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
const usePaymentMadesListContext = () =>
|
||||
React.useContext(PaymentMadesListContext);
|
||||
|
||||
export { PaymentMadesListProvider, usePaymentMadesListContext };
|
||||
@@ -0,0 +1,38 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { Switch, Route } from 'react-router-dom';
|
||||
|
||||
import PaymentMadeViewTabs from './PaymentMadeViewTabs';
|
||||
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Payment mades view page.
|
||||
*/
|
||||
function PaymentMadesViewPage({
|
||||
// #withAlertActions
|
||||
openAlert,
|
||||
}) {
|
||||
return (
|
||||
<Switch>
|
||||
<Route
|
||||
exact={true}
|
||||
path={['/payment-mades/:custom_view_id/custom_view', '/payment-mades']}
|
||||
>
|
||||
<PaymentMadeViewTabs />
|
||||
{/* <PaymentMadeDataTable
|
||||
onDeletePaymentMade={handleDeletePaymentMade}
|
||||
onEditPaymentMade={handleEditPaymentMade}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
/> */}
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAlertsActions,
|
||||
withDialogActions,
|
||||
)(PaymentMadesViewPage);
|
||||
@@ -0,0 +1,52 @@
|
||||
import React, { createContext } from 'react';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import { useResourceViews, useResourceFields, usePaymentMades } from 'hooks/query';
|
||||
|
||||
const PaymentMadesContext = createContext();
|
||||
|
||||
/**
|
||||
* Accounts chart data provider.
|
||||
*/
|
||||
function PaymentMadesProvider({ query, ...props }) {
|
||||
// Fetch accounts resource views and fields.
|
||||
const { data: paymentsViews, isFetching: isViewsLoading } = useResourceViews(
|
||||
'bill_payments',
|
||||
);
|
||||
|
||||
// Fetch the accounts resource fields.
|
||||
const {
|
||||
data: paymentsFields,
|
||||
isFetching: isFieldsLoading,
|
||||
} = useResourceFields('bill_payments');
|
||||
|
||||
// Fetch accounts list according to the given custom view id.
|
||||
const {
|
||||
data: { paymentMades, pagination },
|
||||
isFetching: isPaymentsLoading,
|
||||
} = usePaymentMades(query);
|
||||
|
||||
// Provider payload.
|
||||
const provider = {
|
||||
paymentMades,
|
||||
pagination,
|
||||
paymentsFields,
|
||||
paymentsViews,
|
||||
|
||||
isPaymentsLoading,
|
||||
isFieldsLoading,
|
||||
isViewsLoading,
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={isViewsLoading || isFieldsLoading}
|
||||
name={'payment_made'}
|
||||
>
|
||||
<PaymentMadesContext.Provider value={provider} {...props} />
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
const usePaymentMadesContext = () => React.useContext(PaymentMadesContext);
|
||||
|
||||
export { PaymentMadesProvider, usePaymentMadesContext };
|
||||
Reference in New Issue
Block a user