mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 13:20:31 +00:00
Merge remote-tracking branch 'origin/feature/Detail'
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
Button,
|
||||
NavbarGroup,
|
||||
Classes,
|
||||
NavbarDivider,
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
||||
|
||||
import { useBillDrawerContext } from './BillDrawerProvider';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||
|
||||
import { Icon, FormattedMessage as T } from 'components';
|
||||
|
||||
import { safeCallback, compose } from 'utils';
|
||||
|
||||
function BillDetailActionsBar({
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
|
||||
// #withAlertsActions
|
||||
openAlert,
|
||||
|
||||
// #withDrawerActions
|
||||
closeDrawer,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
const { billId } = useBillDrawerContext();
|
||||
|
||||
// Handle edit bill.
|
||||
const onEditBill = () => {
|
||||
return billId
|
||||
? (history.push(`/bills/${billId}/edit`), closeDrawer('bill-drawer'))
|
||||
: null;
|
||||
};
|
||||
|
||||
// Handle delete bill.
|
||||
const onDeleteBill = () => {
|
||||
return billId
|
||||
? (openAlert('bill-delete', { billId }), closeDrawer('bill-drawer'))
|
||||
: null;
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={<T id={'edit_bill'} />}
|
||||
onClick={safeCallback(onEditBill)}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon={'trash-16'} iconSize={16} />}
|
||||
text={<T id={'delete'} />}
|
||||
intent={Intent.DANGER}
|
||||
onClick={safeCallback(onDeleteBill)}
|
||||
/>
|
||||
</NavbarGroup>
|
||||
</DashboardActionsBar>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withDialogActions,
|
||||
withDrawerActions,
|
||||
withAlertsActions,
|
||||
)(BillDetailActionsBar);
|
||||
37
client/src/containers/Drawers/BillDrawer/BillDetailFooter.js
Normal file
37
client/src/containers/Drawers/BillDrawer/BillDetailFooter.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { TotalLines, TotalLine } from 'components';
|
||||
import BillDrawerCls from 'style/components/Drawers/BillDrawer.module.scss';
|
||||
import { useBillDrawerContext } from './BillDrawerProvider';
|
||||
|
||||
export function BillDetailFooter() {
|
||||
const { bill } = useBillDrawerContext();
|
||||
|
||||
return (
|
||||
<div className={clsx(BillDrawerCls.detail_panel_footer)}>
|
||||
<TotalLines>
|
||||
<TotalLine
|
||||
title={'Subtotal'}
|
||||
value={bill.amount}
|
||||
className={BillDrawerCls.total_line_subtotal}
|
||||
/>
|
||||
<TotalLine
|
||||
title={'TOTAL'}
|
||||
value={bill.amount}
|
||||
className={BillDrawerCls.total_line_total}
|
||||
/>
|
||||
<TotalLine
|
||||
title={'Payment made'}
|
||||
value={bill.payment_amount}
|
||||
className={BillDrawerCls.total_line_payment}
|
||||
/>
|
||||
<TotalLine
|
||||
title={'Due amount'}
|
||||
value={bill.formatted_due_amount}
|
||||
className={BillDrawerCls.total_line_dueAmount}
|
||||
/>
|
||||
</TotalLines>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
55
client/src/containers/Drawers/BillDrawer/BillDetailHeader.js
Normal file
55
client/src/containers/Drawers/BillDrawer/BillDetailHeader.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { defaultTo } from 'lodash';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { DetailsMenu, DetailItem } from 'components';
|
||||
|
||||
import { useBillDrawerContext } from './BillDrawerProvider';
|
||||
import BillDrawerCls from 'style/components/Drawers/BillDrawer.module.scss';
|
||||
|
||||
/**
|
||||
* Bill detail header.
|
||||
*/
|
||||
export default function BillDetailHeader() {
|
||||
const { bill } = useBillDrawerContext();
|
||||
|
||||
return (
|
||||
<div className={clsx(BillDrawerCls.detail_panel_header)}>
|
||||
<DetailsMenu>
|
||||
<DetailItem
|
||||
label={intl.get('amount')}
|
||||
children={<h3 class="big-number">{bill.formatted_amount}</h3>}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('bill_number')}
|
||||
children={defaultTo(bill.bill_number, '-')}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('bill_date')}
|
||||
children={bill.formatted_bill_date}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('vendor_name')}
|
||||
children={bill.vendor?.display_name}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('due_date')}
|
||||
children={bill.formatted_due_date}
|
||||
/>
|
||||
</DetailsMenu>
|
||||
|
||||
<DetailsMenu direction={'horizantal'} minLabelSize={'140px'}>
|
||||
<DetailItem
|
||||
label={intl.get('due_amount')}
|
||||
children={bill.formatted_due_amount}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('reference')}
|
||||
children={defaultTo(bill.reference_no, '--')}
|
||||
/>
|
||||
<DetailItem label={'Created at'} children={'2020 Ang 21'} />
|
||||
</DetailsMenu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
29
client/src/containers/Drawers/BillDrawer/BillDetailTab.js
Normal file
29
client/src/containers/Drawers/BillDrawer/BillDetailTab.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { Card } from 'components';
|
||||
|
||||
import BillDetailActionsBar from './BillDetailActionsBar';
|
||||
import BillDetailHeader from './BillDetailHeader';
|
||||
import BillDetailTable from './BillDetailTable';
|
||||
import { BillDetailFooter } from './BillDetailFooter'
|
||||
|
||||
import BillDrawerCls from 'style/components/Drawers/BillDrawer.module.scss';
|
||||
|
||||
|
||||
/**
|
||||
* Bill detail panel tab.
|
||||
*/
|
||||
export default function BillDetailTab() {
|
||||
return (
|
||||
<div className={clsx(BillDrawerCls.detail_panel)}>
|
||||
<BillDetailActionsBar />
|
||||
|
||||
<Card>
|
||||
<BillDetailHeader />
|
||||
<BillDetailTable />
|
||||
<BillDetailFooter />
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
26
client/src/containers/Drawers/BillDrawer/BillDetailTable.js
Normal file
26
client/src/containers/Drawers/BillDrawer/BillDetailTable.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { DataTable } from 'components';
|
||||
|
||||
import { useBillDrawerContext } from './BillDrawerProvider';
|
||||
import { useBillReadonlyEntriesTableColumns } from './utils';
|
||||
|
||||
import BillDrawerCls from 'style/components/Drawers/BillDrawer.module.scss';
|
||||
|
||||
export default function BillDetailTable() {
|
||||
const { bill: { entries } } = useBillDrawerContext();
|
||||
|
||||
// Retrieve bill readonly entries table columns.
|
||||
const columns = useBillReadonlyEntriesTableColumns();
|
||||
|
||||
return (
|
||||
<div className={clsx(BillDrawerCls.detail_panel_table)}>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={entries}
|
||||
className={'table-constrant'}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,19 +4,19 @@ import 'style/components/Drawers/ViewDetail/ViewDetail.scss';
|
||||
|
||||
import { BillDrawerProvider } from './BillDrawerProvider';
|
||||
import BillDrawerDetails from './BillDrawerDetails';
|
||||
import BillDrawerAlerts from './BillDrawerAlerts';
|
||||
// import BillDrawerAlerts from './BillDrawerAlerts';
|
||||
|
||||
/**
|
||||
* Bill drawer content.
|
||||
*/
|
||||
export default function BillDrawerContent({
|
||||
// #ownProp
|
||||
bill,
|
||||
billId,
|
||||
}) {
|
||||
return (
|
||||
<BillDrawerProvider billId={bill}>
|
||||
<BillDrawerProvider billId={billId}>
|
||||
<BillDrawerDetails />
|
||||
<BillDrawerAlerts />
|
||||
{/* <BillDrawerAlerts /> */}
|
||||
</BillDrawerProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import React from 'react';
|
||||
import { Tabs, Tab } from '@blueprintjs/core';
|
||||
import { Tab } from '@blueprintjs/core';
|
||||
import intl from 'react-intl-universal';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { DrawerMainTabs } from 'components';
|
||||
|
||||
import BillDetailTab from './BillDetailTab';
|
||||
import LocatedLandedCostTable from './LocatedLandedCostTable';
|
||||
import JournalEntriesTable from '../../JournalEntriesTable/JournalEntriesTable';
|
||||
import { useBillDrawerContext } from './BillDrawerProvider';
|
||||
|
||||
import BillDrawerCls from 'style/components/Drawers/BillDrawer.module.scss';
|
||||
|
||||
/**
|
||||
* Bill view details.
|
||||
*/
|
||||
@@ -15,9 +21,13 @@ export default function BillDrawerDetails() {
|
||||
} = useBillDrawerContext();
|
||||
|
||||
return (
|
||||
<div className="view-detail-drawer">
|
||||
<Tabs animate={true} large={true} defaultSelectedTabId="journal_entries">
|
||||
<Tab title={intl.get('details')} id={'details'} disabled={true} />
|
||||
<div className={clsx(BillDrawerCls.root)}>
|
||||
<DrawerMainTabs defaultSelectedTabId="details">
|
||||
<Tab
|
||||
title={intl.get('details')}
|
||||
id={'details'}
|
||||
panel={<BillDetailTab />}
|
||||
/>
|
||||
<Tab
|
||||
title={intl.get('journal_entries')}
|
||||
id={'journal_entries'}
|
||||
@@ -28,9 +38,7 @@ export default function BillDrawerDetails() {
|
||||
id={'landed_cost'}
|
||||
panel={<LocatedLandedCostTable />}
|
||||
/>
|
||||
</Tabs>
|
||||
</DrawerMainTabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 42 / fon-w 600
|
||||
@@ -1,8 +1,11 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { DrawerHeaderContent, DashboardInsider } from 'components';
|
||||
import { useBillLocatedLandedCost } from 'hooks/query';
|
||||
import { useTransactionsByReference } from 'hooks/query';
|
||||
import {
|
||||
useBill,
|
||||
useTransactionsByReference,
|
||||
useBillLocatedLandedCost,
|
||||
} from 'hooks/query';
|
||||
|
||||
const BillDrawerContext = React.createContext();
|
||||
|
||||
@@ -10,7 +13,11 @@ const BillDrawerContext = React.createContext();
|
||||
* Bill drawer provider.
|
||||
*/
|
||||
function BillDrawerProvider({ billId, ...props }) {
|
||||
|
||||
// Handle fetch bill details.
|
||||
const { isLoading: isBillLoading, data: bill } = useBill(billId, {
|
||||
enabled: !!billId,
|
||||
});
|
||||
|
||||
// Handle fetch transaction by reference.
|
||||
const { data, isLoading: isTransactionLoading } = useTransactionsByReference(
|
||||
{
|
||||
@@ -31,10 +38,13 @@ function BillDrawerProvider({ billId, ...props }) {
|
||||
transactions,
|
||||
billId,
|
||||
data,
|
||||
bill,
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider loading={isLandedCostLoading || isTransactionLoading}>
|
||||
<DashboardInsider
|
||||
loading={isLandedCostLoading || isTransactionLoading || isBillLoading}
|
||||
>
|
||||
<DrawerHeaderContent
|
||||
name="bill-drawer"
|
||||
title={intl.get('bill_details')}
|
||||
|
||||
@@ -16,9 +16,14 @@ function BillDrawer({
|
||||
payload: { billId },
|
||||
}) {
|
||||
return (
|
||||
<Drawer isOpen={isOpen} name={name} size={'750px'}>
|
||||
<Drawer
|
||||
isOpen={isOpen}
|
||||
name={name}
|
||||
style={{ minWidth: '700px', maxWidth: '900px' }}
|
||||
size={'65%'}
|
||||
>
|
||||
<DrawerSuspense>
|
||||
<BillDrawerContent bill={billId} />
|
||||
<BillDrawerContent billId={billId} />
|
||||
</DrawerSuspense>
|
||||
</Drawer>
|
||||
);
|
||||
|
||||
43
client/src/containers/Drawers/BillDrawer/utils.js
Normal file
43
client/src/containers/Drawers/BillDrawer/utils.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
export const useBillReadonlyEntriesTableColumns = () =>
|
||||
React.useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: intl.get('product_and_service'),
|
||||
accessor: 'item.name',
|
||||
width: 150,
|
||||
className: 'item',
|
||||
disableSortBy: true
|
||||
},
|
||||
{
|
||||
Header: intl.get('description'),
|
||||
accessor: 'description',
|
||||
className: 'description',
|
||||
disableSortBy: true
|
||||
},
|
||||
{
|
||||
Header: intl.get('quantity'),
|
||||
accessor: 'quantity',
|
||||
width: 100,
|
||||
className: 'quantity',
|
||||
disableSortBy: true
|
||||
},
|
||||
{
|
||||
Header: intl.get('rate'),
|
||||
accessor: 'rate',
|
||||
width: 100,
|
||||
className: 'rate',
|
||||
disableSortBy: true
|
||||
},
|
||||
{
|
||||
Header: intl.get('amount'),
|
||||
accessor: 'amount',
|
||||
width: 100,
|
||||
className: 'amount',
|
||||
disableSortBy: true
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
@@ -1,21 +1,26 @@
|
||||
import React from 'react';
|
||||
import { Tabs, Tab } from '@blueprintjs/core';
|
||||
import { Tab } from '@blueprintjs/core';
|
||||
import intl from 'react-intl-universal';
|
||||
import EstimateDetailTab from './EstimateDetailTab';
|
||||
import { DrawerMainTabs } from 'components';
|
||||
|
||||
import EstimateDetailPanel from './EstimateDetailPanel';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import EstimateDetailsCls from 'style/components/Drawers/EstimateDetails.module.scss';
|
||||
|
||||
/**
|
||||
* Estimate view detail
|
||||
*/
|
||||
export default function EstimateDetail() {
|
||||
return (
|
||||
<div className="view-detail-drawer">
|
||||
<Tabs animate={true} large={true}>
|
||||
<div className={clsx(EstimateDetailsCls.root)}>
|
||||
<DrawerMainTabs>
|
||||
<Tab
|
||||
title={intl.get('details')}
|
||||
id={'details'}
|
||||
panel={<EstimateDetailTab />}
|
||||
panel={<EstimateDetailPanel />}
|
||||
/>
|
||||
</Tabs>
|
||||
</DrawerMainTabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,9 +17,12 @@ import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||
|
||||
import { Icon, FormattedMessage as T } from 'components';
|
||||
|
||||
import { safeCallback, compose } from 'utils';
|
||||
import { compose } from 'utils';
|
||||
|
||||
function EstimateDetailTab({
|
||||
/**
|
||||
* Estimate read-only details actions bar of the drawer.
|
||||
*/
|
||||
function EstimateDetailActionsBar({
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
|
||||
@@ -29,28 +32,24 @@ function EstimateDetailTab({
|
||||
// #withDrawerActions
|
||||
closeDrawer,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
const { estimateId } = useEstimateDetailDrawerContext();
|
||||
|
||||
const history = useHistory();
|
||||
|
||||
// Handle edit sale estimate.
|
||||
const onEditEstimate = () => {
|
||||
return estimateId
|
||||
? (history.push(`/estimates/${estimateId}/edit`),
|
||||
closeDrawer('estimate-detail-drawer'))
|
||||
: null;
|
||||
const handleEditEstimate = () => {
|
||||
history.push(`/estimates/${estimateId}/edit`);
|
||||
closeDrawer('estimate-detail-drawer');
|
||||
};
|
||||
|
||||
// Handle delete sale estimate.
|
||||
const onDeleteEstimate = () => {
|
||||
return estimateId
|
||||
? (openAlert('estimate-delete', { estimateId }),
|
||||
closeDrawer('estimate-detail-drawer'))
|
||||
: null;
|
||||
const handleDeleteEstimate = () => {
|
||||
openAlert('estimate-delete', { estimateId });
|
||||
closeDrawer('estimate-detail-drawer');
|
||||
};
|
||||
|
||||
// Handle print estimate.
|
||||
const onPrintEstimate = () => {
|
||||
const handlePrintEstimate = () => {
|
||||
openDialog('estimate-pdf-preview', { estimateId });
|
||||
};
|
||||
|
||||
@@ -61,21 +60,21 @@ function EstimateDetailTab({
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={<T id={'edit_estimate'} />}
|
||||
onClick={safeCallback(onEditEstimate)}
|
||||
onClick={handleEditEstimate}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="print-16" />}
|
||||
text={<T id={'print'} />}
|
||||
onClick={safeCallback(onPrintEstimate)}
|
||||
onClick={handleDeleteEstimate}
|
||||
/>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon={'trash-16'} iconSize={16} />}
|
||||
text={<T id={'delete'} />}
|
||||
intent={Intent.DANGER}
|
||||
onClick={safeCallback(onDeleteEstimate)}
|
||||
onClick={handlePrintEstimate}
|
||||
/>
|
||||
</NavbarGroup>
|
||||
</DashboardActionsBar>
|
||||
@@ -86,4 +85,4 @@ export default compose(
|
||||
withDialogActions,
|
||||
withAlertsActions,
|
||||
withDrawerActions,
|
||||
)(EstimateDetailTab);
|
||||
)(EstimateDetailActionsBar);
|
||||
@@ -1,7 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import 'style/components/Drawers/ViewDetail/ViewDetail.scss';
|
||||
|
||||
import EstimateDetail from './EstimateDetail';
|
||||
import { EstimateDetailDrawerProvider } from './EstimateDetailDrawerProvider';
|
||||
|
||||
@@ -10,10 +8,10 @@ import { EstimateDetailDrawerProvider } from './EstimateDetailDrawerProvider';
|
||||
*/
|
||||
export default function EstimateDetailDrawerContent({
|
||||
// #ownProp
|
||||
estimate,
|
||||
estimateId,
|
||||
}) {
|
||||
return (
|
||||
<EstimateDetailDrawerProvider estimateId={estimate}>
|
||||
<EstimateDetailDrawerProvider estimateId={estimateId}>
|
||||
<EstimateDetail />
|
||||
</EstimateDetailDrawerProvider>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { DrawerHeaderContent, DashboardInsider } from 'components';
|
||||
import { useEstimate } from 'hooks/query';
|
||||
import { DrawerHeaderContent, DrawerInsider } from 'components';
|
||||
|
||||
const EstimateDetailDrawerContext = React.createContext();
|
||||
|
||||
@@ -8,19 +9,25 @@ const EstimateDetailDrawerContext = React.createContext();
|
||||
* Estimate detail provider.
|
||||
*/
|
||||
function EstimateDetailDrawerProvider({ estimateId, ...props }) {
|
||||
// Fetches the estimate by the given id.
|
||||
const { data: estimate, isLoading: isEstimateLoading } = useEstimate(
|
||||
estimateId,
|
||||
{ enabled: !!estimateId },
|
||||
);
|
||||
|
||||
const provider = {
|
||||
estimateId,
|
||||
estimate,
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider>
|
||||
<DrawerInsider loading={isEstimateLoading}>
|
||||
<DrawerHeaderContent
|
||||
name="estimate-detail-drawer"
|
||||
title={intl.get('estimate_details')}
|
||||
/>
|
||||
|
||||
<EstimateDetailDrawerContext.Provider value={provider} {...props} />
|
||||
</DashboardInsider>
|
||||
</DrawerInsider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { TotalLines, TotalLine, If } from 'components';
|
||||
|
||||
import EstimateDetailsCls from 'style/components/Drawers/EstimateDetails.module.scss';
|
||||
|
||||
/**
|
||||
* Estimate details panel footer content.
|
||||
*/
|
||||
export default function EstimateDetailFooter() {
|
||||
return (
|
||||
<div className={clsx(EstimateDetailsCls.detail_panel_footer)}>
|
||||
<TotalLines className={clsx(EstimateDetailsCls.total_lines)}>
|
||||
<TotalLine
|
||||
title={'Subtotal'}
|
||||
value={'1000'}
|
||||
className={EstimateDetailsCls.total_line_subtotal}
|
||||
/>
|
||||
<TotalLine
|
||||
title={'TOTAL'}
|
||||
value={'1000'}
|
||||
className={EstimateDetailsCls.total_line_total}
|
||||
/>
|
||||
<TotalLine
|
||||
title={'Payment made'}
|
||||
value={'1000'}
|
||||
className={EstimateDetailsCls.total_line_payment}
|
||||
/>
|
||||
<TotalLine
|
||||
title={'Due amount'}
|
||||
value={'1000'}
|
||||
className={EstimateDetailsCls.total_line_dueAmount}
|
||||
/>
|
||||
</TotalLines>
|
||||
|
||||
<If condition={false}>
|
||||
<div className={clsx(EstimateDetailsCls.detail_panel_note)}>
|
||||
<p>
|
||||
<b>Note:</b> --
|
||||
</p>
|
||||
</div>
|
||||
</If>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { defaultTo } from 'lodash';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { DetailsMenu, DetailItem } from 'components';
|
||||
import { useEstimateDetailDrawerContext } from './EstimateDetailDrawerProvider';
|
||||
|
||||
import EstimateDetailsCls from 'style/components/Drawers/EstimateDetails.module.scss';
|
||||
|
||||
/**
|
||||
* Estimate read-only details drawer header.
|
||||
*/
|
||||
export default function EstimateDetailHeader() {
|
||||
const { estimate } = useEstimateDetailDrawerContext();
|
||||
|
||||
return (
|
||||
<div className={clsx(EstimateDetailsCls.detail_panel_header)}>
|
||||
<DetailsMenu>
|
||||
<DetailItem label={intl.get('amount')}>
|
||||
<span class="big-number">{estimate.formatted_amount}</span>
|
||||
</DetailItem>
|
||||
<DetailItem
|
||||
label={intl.get('estimate_number')}
|
||||
children={defaultTo(estimate.estimate_number, '-')}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('customer_name')}
|
||||
children={estimate.customer?.display_name}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('estimate_date')}
|
||||
children={estimate.formatted_estimate_date}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('expiration_date')}
|
||||
children={estimate.formatted_expiration_date}
|
||||
/>
|
||||
</DetailsMenu>
|
||||
|
||||
<DetailsMenu direction={'horizantal'} minLabelSize={'140px'}>
|
||||
<DetailItem
|
||||
label={intl.get('reference')}
|
||||
children={defaultTo(estimate.reference, '-')}
|
||||
/>
|
||||
<DetailItem label={'Created at'} children={'2020 Ang 21'} />
|
||||
</DetailsMenu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { Card } from 'components';
|
||||
|
||||
import EstimateDetailActionsBar from './EstimateDetailActionsBar';
|
||||
import EstimateDetailHeader from './EstimateDetailHeader';
|
||||
import EstimateDetailTable from './EstimateDetailTable';
|
||||
|
||||
import EstimateDetailsCls from 'style/components/Drawers/EstimateDetails.module.scss';
|
||||
import EstimateDetailFooter from './EstimateDetailFooter';
|
||||
|
||||
export default function EstimateDetailTab() {
|
||||
return (
|
||||
<div className={clsx(EstimateDetailsCls.detail_panel)}>
|
||||
<EstimateDetailActionsBar />
|
||||
|
||||
<Card>
|
||||
<EstimateDetailHeader />
|
||||
<EstimateDetailTable />
|
||||
<EstimateDetailFooter />
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { DataTable } from 'components';
|
||||
import { useEstimateDetailDrawerContext } from './EstimateDetailDrawerProvider';
|
||||
|
||||
import { useEstimateReadonlyEntriesColumns } from './utils';
|
||||
|
||||
import EstimateDetailsCls from 'style/components/Drawers/EstimateDetails.module.scss';
|
||||
|
||||
/**
|
||||
* Estimate detail table.
|
||||
*/
|
||||
export default function EstimateDetailTable() {
|
||||
const {
|
||||
estimate: { entries },
|
||||
} = useEstimateDetailDrawerContext();
|
||||
|
||||
// Estimate entries table columns.
|
||||
const columns = useEstimateReadonlyEntriesColumns();
|
||||
|
||||
return (
|
||||
<div className={clsx(EstimateDetailsCls.detail_panel_table)}>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={entries}
|
||||
className={'table-constrant'}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
const globalStateClassesMapping = {
|
||||
active: 'active',
|
||||
checked: 'checked',
|
||||
completed: 'completed',
|
||||
disabled: 'disabled',
|
||||
error: 'error',
|
||||
expanded: 'expanded',
|
||||
focused: 'focused',
|
||||
focusVisible: 'focusVisible',
|
||||
required: 'required',
|
||||
selected: 'selected',
|
||||
};
|
||||
|
||||
function generateUtilityClass(componentName, slot) {
|
||||
const globalStateClass = globalStateClassesMapping[slot];
|
||||
return globalStateClass || `${componentName}__${slot}`;
|
||||
}
|
||||
|
||||
function generateUtilityClasses(componentName, modifiers) {
|
||||
const result = {
|
||||
root: componentName,
|
||||
};
|
||||
modifiers.forEach((modifier) => {
|
||||
result[modifier] = generateUtilityClass(componentName, modifier);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export const EstimateDrawerCls = generateUtilityClasses('estimate-drawer', [
|
||||
'content',
|
||||
]);
|
||||
@@ -15,9 +15,14 @@ function EstimateDetailDrawer({
|
||||
payload: { estimateId },
|
||||
}) {
|
||||
return (
|
||||
<Drawer isOpen={isOpen} name={name} size={'750px'}>
|
||||
<Drawer
|
||||
isOpen={isOpen}
|
||||
name={name}
|
||||
style={{ minWidth: '700px', maxWidth: '900px' }}
|
||||
size={'65%'}
|
||||
>
|
||||
<DrawerSuspense>
|
||||
<EstimateDetailDrawerContent estimate={estimateId} />
|
||||
<EstimateDetailDrawerContent estimateId={estimateId} />
|
||||
</DrawerSuspense>
|
||||
</Drawer>
|
||||
);
|
||||
|
||||
43
client/src/containers/Drawers/EstimateDetailDrawer/utils.js
Normal file
43
client/src/containers/Drawers/EstimateDetailDrawer/utils.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
/**
|
||||
* Retrieve table columns of estimate readonly entries details.
|
||||
*/
|
||||
export const useEstimateReadonlyEntriesColumns = () =>
|
||||
React.useMemo(() => [
|
||||
{
|
||||
Header: intl.get('product_and_service'),
|
||||
accessor: 'item.name',
|
||||
width: 150,
|
||||
className: 'name',
|
||||
disableSortBy: true,
|
||||
},
|
||||
{
|
||||
Header: intl.get('description'),
|
||||
accessor: 'description',
|
||||
className: 'description',
|
||||
disableSortBy: true,
|
||||
},
|
||||
{
|
||||
Header: intl.get('quantity'),
|
||||
accessor: 'quantity',
|
||||
width: 100,
|
||||
className: 'quantity',
|
||||
disableSortBy: true,
|
||||
},
|
||||
{
|
||||
Header: intl.get('rate'),
|
||||
accessor: 'rate',
|
||||
width: 100,
|
||||
className: 'rate',
|
||||
disableSortBy: true,
|
||||
},
|
||||
{
|
||||
Header: intl.get('amount'),
|
||||
accessor: 'amount',
|
||||
width: 100,
|
||||
className: 'amount',
|
||||
disableSortBy: true,
|
||||
},
|
||||
], []);
|
||||
@@ -1,36 +1,36 @@
|
||||
import React from 'react';
|
||||
import { Tabs, Tab } from '@blueprintjs/core';
|
||||
import { Tab } from '@blueprintjs/core';
|
||||
import intl from 'react-intl-universal';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { DrawerMainTabs } from 'components';
|
||||
|
||||
import JournalEntriesTable from '../../JournalEntriesTable/JournalEntriesTable';
|
||||
import InvoiceDetailTab from './InvoiceDetailTab';
|
||||
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
|
||||
|
||||
import InvoiceDrawerCls from 'style/components/Drawers/InvoiceDrawer.module.scss';
|
||||
|
||||
/**
|
||||
* Invoice view detail.
|
||||
*/
|
||||
export default function InvoiceDetail() {
|
||||
const { transactions, invoiceId } = useInvoiceDetailDrawerContext();
|
||||
const { transactions } = useInvoiceDetailDrawerContext();
|
||||
|
||||
return (
|
||||
<div className="view-detail-drawer">
|
||||
<Tabs
|
||||
animate={true}
|
||||
large={true}
|
||||
defaultSelectedTabId="journal_entries"
|
||||
renderActiveTabPanelOnly={false}
|
||||
>
|
||||
<div className={clsx(InvoiceDrawerCls.invoice_details)}>
|
||||
<DrawerMainTabs defaultSelectedTabId="details">
|
||||
<Tab
|
||||
title={intl.get('details')}
|
||||
id={'details'}
|
||||
panel={<InvoiceDetailTab invoiceId={invoiceId} />}
|
||||
panel={<InvoiceDetailTab />}
|
||||
/>
|
||||
<Tab
|
||||
title={intl.get('journal_entries')}
|
||||
id={'journal_entries'}
|
||||
panel={<JournalEntriesTable transactions={transactions} />}
|
||||
/>
|
||||
</Tabs>
|
||||
</DrawerMainTabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
Button,
|
||||
NavbarGroup,
|
||||
Classes,
|
||||
NavbarDivider,
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
||||
|
||||
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||
|
||||
import { Icon, FormattedMessage as T } from 'components';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Invoice details action bar.
|
||||
*/
|
||||
function InvoiceDetailActionsBar({
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
|
||||
// #withAlertsActions
|
||||
openAlert,
|
||||
|
||||
// #withDrawerActions
|
||||
closeDrawer,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
// Invoice detail drawer context.
|
||||
const { invoiceId } = useInvoiceDetailDrawerContext();
|
||||
|
||||
// Handle edit sale invoice.
|
||||
const handleEditInvoice = () => {
|
||||
history.push(`/invoices/${invoiceId}/edit`);
|
||||
closeDrawer('invoice-detail-drawer');
|
||||
};
|
||||
|
||||
// Handle delete sale invoice.
|
||||
const handleDeleteInvoice = () => {
|
||||
openAlert('invoice-delete', { invoiceId });
|
||||
closeDrawer('invoice-detail-drawer');
|
||||
};
|
||||
|
||||
// Handle print invoices.
|
||||
const handlePrintInvoice = () => {
|
||||
openDialog('invoice-pdf-preview', { invoiceId });
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={<T id={'edit_invoice'} />}
|
||||
onClick={handleEditInvoice}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="print-16" />}
|
||||
text={<T id={'print'} />}
|
||||
onClick={handlePrintInvoice}
|
||||
/>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon={'trash-16'} iconSize={16} />}
|
||||
text={<T id={'delete'} />}
|
||||
intent={Intent.DANGER}
|
||||
onClick={handleDeleteInvoice}
|
||||
/>
|
||||
</NavbarGroup>
|
||||
</DashboardActionsBar>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withDialogActions,
|
||||
withDrawerActions,
|
||||
withAlertsActions,
|
||||
)(InvoiceDetailActionsBar);
|
||||
@@ -10,10 +10,10 @@ import { InvoiceDetailDrawerProvider } from './InvoiceDetailDrawerProvider';
|
||||
*/
|
||||
export default function InvoiceDetailDrawerContent({
|
||||
// #ownProp
|
||||
invoice,
|
||||
invoiceId,
|
||||
}) {
|
||||
return (
|
||||
<InvoiceDetailDrawerProvider invoiceId={invoice}>
|
||||
<InvoiceDetailDrawerProvider invoiceId={invoiceId}>
|
||||
<InvoiceDetail />
|
||||
</InvoiceDetailDrawerProvider>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { DrawerHeaderContent, DashboardInsider } from 'components';
|
||||
import { useTransactionsByReference } from 'hooks/query';
|
||||
import { useTransactionsByReference, useInvoice } from 'hooks/query';
|
||||
|
||||
const InvoiceDetailDrawerContext = React.createContext();
|
||||
/**
|
||||
@@ -20,13 +20,19 @@ function InvoiceDetailDrawerProvider({ invoiceId, ...props }) {
|
||||
{ enabled: !!invoiceId },
|
||||
);
|
||||
|
||||
// Fetch sale invoice details.
|
||||
const { data: invoice, isLoading: isInvoiceLoading } = useInvoice(invoiceId, {
|
||||
enabled: !!invoiceId,
|
||||
});
|
||||
|
||||
//provider.
|
||||
const provider = {
|
||||
transactions,
|
||||
invoiceId,
|
||||
invoice,
|
||||
};
|
||||
return (
|
||||
<DashboardInsider loading={isTransactionLoading}>
|
||||
<DashboardInsider loading={isTransactionLoading || isInvoiceLoading}>
|
||||
<DrawerHeaderContent
|
||||
name="invoice-detail-drawer"
|
||||
title={intl.get('invoice_details')}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { TotalLines, TotalLine } from 'components';
|
||||
import InvoiceDrawerCls from 'style/components/Drawers/InvoiceDrawer.module.scss';
|
||||
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export function InvoiceDetailFooter() {
|
||||
const { invoice } = useInvoiceDetailDrawerContext();
|
||||
|
||||
return (
|
||||
<div className={clsx(InvoiceDrawerCls.detail_panel_footer)}>
|
||||
<TotalLines>
|
||||
<TotalLine
|
||||
title={'Subtotal'}
|
||||
value={invoice.balance}
|
||||
className={InvoiceDrawerCls.total_line_subtotal}
|
||||
/>
|
||||
<TotalLine
|
||||
title={'TOTAL'}
|
||||
value={invoice.balance}
|
||||
className={InvoiceDrawerCls.total_line_total}
|
||||
/>
|
||||
<TotalLine
|
||||
title={'Payment made'}
|
||||
value={invoice.payment_amount}
|
||||
className={InvoiceDrawerCls.total_line_payment}
|
||||
/>
|
||||
<TotalLine
|
||||
title={'Due amount'}
|
||||
value={'1000'}
|
||||
className={InvoiceDrawerCls.total_line_dueAmount}
|
||||
/>
|
||||
</TotalLines>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { defaultTo } from 'lodash';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { DetailsMenu, DetailItem } from 'components';
|
||||
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
|
||||
|
||||
import InvoiceDrawerCls from 'style/components/Drawers/InvoiceDrawer.module.scss';
|
||||
|
||||
/**
|
||||
* Invoice detail header.
|
||||
*/
|
||||
export default function InvoiceDetailHeader() {
|
||||
const { invoice } = useInvoiceDetailDrawerContext();
|
||||
|
||||
return (
|
||||
<div className={clsx(InvoiceDrawerCls.detail_panel_header)}>
|
||||
<DetailsMenu>
|
||||
<DetailItem label={intl.get('amount')}>
|
||||
<h3 class="big-number">{invoice.formatted_amount}</h3>
|
||||
</DetailItem>
|
||||
<DetailItem
|
||||
label={intl.get('invoice_no')}
|
||||
children={invoice.invoice_no}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('customer_name')}
|
||||
children={invoice.customer?.display_name}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('invoice_date')}
|
||||
children={invoice.formatted_invoice_date}
|
||||
/>
|
||||
|
||||
<DetailItem
|
||||
label={intl.get('due_date')}
|
||||
children={invoice.formatted_due_date}
|
||||
/>
|
||||
</DetailsMenu>
|
||||
|
||||
<DetailsMenu direction={'horizantal'}>
|
||||
<DetailItem
|
||||
label={intl.get('due_amount')}
|
||||
children={invoice.formatted_due_amount}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('reference')}
|
||||
children={defaultTo(invoice.reference_no, '--')}
|
||||
/>
|
||||
<DetailItem label={'Created at'} children={'2020 Ang 21'} />
|
||||
</DetailsMenu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,89 +1,28 @@
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import {
|
||||
Button,
|
||||
NavbarGroup,
|
||||
Classes,
|
||||
NavbarDivider,
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
||||
import { Card } from 'components';
|
||||
|
||||
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
|
||||
import InvoiceDetailActionsBar from './InvoiceDetailActionsBar';
|
||||
import InvoiceDetailHeader from './InvoiceDetailHeader';
|
||||
import InvoiceDetailTable from './InvoiceDetailTable';
|
||||
import { InvoiceDetailFooter } from './InvoiceDetailFooter';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||
|
||||
import { Icon, FormattedMessage as T } from 'components';
|
||||
|
||||
import { safeCallback, compose } from 'utils';
|
||||
|
||||
function InvoiceDetailTab({
|
||||
invoiceId,
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
|
||||
// #withAlertsActions
|
||||
openAlert,
|
||||
|
||||
// #withDrawerActions
|
||||
closeDrawer,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
// Handle edit sale invoice.
|
||||
const onEditInvoice = () => {
|
||||
return invoiceId
|
||||
? (history.push(`/invoices/${invoiceId}/edit`),
|
||||
closeDrawer('invoice-detail-drawer'))
|
||||
: null;
|
||||
};
|
||||
|
||||
// Handle delete sale invoice.
|
||||
const onDeleteInvoice = () => {
|
||||
return invoiceId
|
||||
? (openAlert('invoice-delete', { invoiceId }),
|
||||
closeDrawer('invoice-detail-drawer'))
|
||||
: null;
|
||||
};
|
||||
|
||||
// Handle print invoices.
|
||||
const onPrintInvoice = () => {
|
||||
openDialog('invoice-pdf-preview', { invoiceId });
|
||||
};
|
||||
import InvoiceDrawerCls from 'style/components/Drawers/InvoiceDrawer.module.scss';
|
||||
|
||||
/**
|
||||
* Invoice readonly details tab panel.
|
||||
*/
|
||||
export default function InvoiceDetailTab() {
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={<T id={'edit_invoice'} />}
|
||||
onClick={safeCallback(onEditInvoice)}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="print-16" />}
|
||||
text={<T id={'print'} />}
|
||||
onClick={safeCallback(onPrintInvoice)}
|
||||
/>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon={'trash-16'} iconSize={16} />}
|
||||
text={<T id={'delete'} />}
|
||||
intent={Intent.DANGER}
|
||||
onClick={safeCallback(onDeleteInvoice)}
|
||||
/>
|
||||
</NavbarGroup>
|
||||
</DashboardActionsBar>
|
||||
);
|
||||
}
|
||||
<div className={clsx(InvoiceDrawerCls.detail_panel)}>
|
||||
<InvoiceDetailActionsBar />
|
||||
|
||||
export default compose(
|
||||
withDialogActions,
|
||||
withDrawerActions,
|
||||
withAlertsActions,
|
||||
)(InvoiceDetailTab);
|
||||
<Card>
|
||||
<InvoiceDetailHeader />
|
||||
<InvoiceDetailTable />
|
||||
<InvoiceDetailFooter />
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { DataTable } from 'components';
|
||||
|
||||
import { useInvoiceReadonlyEntriesColumns } from './utils';
|
||||
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
|
||||
|
||||
import InvoiceDrawerCls from 'style/components/Drawers/InvoiceDrawer.module.scss';
|
||||
|
||||
/**
|
||||
* Invoice readonly details entries table columns.
|
||||
*/
|
||||
export default function InvoiceDetailTable() {
|
||||
const columns = useInvoiceReadonlyEntriesColumns();
|
||||
|
||||
const {
|
||||
invoice: { entries },
|
||||
} = useInvoiceDetailDrawerContext();
|
||||
|
||||
return (
|
||||
<div className={clsx(InvoiceDrawerCls.detail_panel_table)}>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={entries}
|
||||
className={'table-constrant'}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -18,9 +18,14 @@ function InvoiceDetailDrawer({
|
||||
payload: { invoiceId },
|
||||
}) {
|
||||
return (
|
||||
<Drawer isOpen={isOpen} name={name} size={'750px'}>
|
||||
<Drawer
|
||||
isOpen={isOpen}
|
||||
name={name}
|
||||
style={{ minWidth: '700px', maxWidth: '900px' }}
|
||||
size={'65%'}
|
||||
>
|
||||
<DrawerSuspense>
|
||||
<InvoiceDetailDrawerContent invoice={invoiceId} />
|
||||
<InvoiceDetailDrawerContent invoiceId={invoiceId} />
|
||||
</DrawerSuspense>
|
||||
</Drawer>
|
||||
);
|
||||
|
||||
43
client/src/containers/Drawers/InvoiceDetailDrawer/utils.js
Normal file
43
client/src/containers/Drawers/InvoiceDetailDrawer/utils.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
export const useInvoiceReadonlyEntriesColumns = () =>
|
||||
React.useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: intl.get('product_and_service'),
|
||||
accessor: 'item.name',
|
||||
width: 150,
|
||||
className: 'name',
|
||||
disableSortBy: true,
|
||||
},
|
||||
{
|
||||
Header: intl.get('description'),
|
||||
accessor: 'description',
|
||||
className: 'description',
|
||||
disableSortBy: true,
|
||||
},
|
||||
{
|
||||
Header: intl.get('quantity'),
|
||||
accessor: 'quantity',
|
||||
width: 100,
|
||||
className: 'quantity',
|
||||
disableSortBy: true,
|
||||
},
|
||||
{
|
||||
Header: intl.get('rate'),
|
||||
accessor: 'rate',
|
||||
width: 100,
|
||||
className: 'rate',
|
||||
disableSortBy: true,
|
||||
},
|
||||
{
|
||||
Header: intl.get('amount'),
|
||||
accessor: 'amount',
|
||||
width: 100,
|
||||
className: 'amount',
|
||||
disableSortBy: true,
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
@@ -1,31 +1,35 @@
|
||||
import React from 'react';
|
||||
import { Tabs, Tab } from '@blueprintjs/core';
|
||||
import { Tab } from '@blueprintjs/core';
|
||||
import intl from 'react-intl-universal';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { DrawerMainTabs } from 'components';
|
||||
import JournalEntriesTable from '../../JournalEntriesTable/JournalEntriesTable';
|
||||
import ReceiptDetailTab from './ReceiptDetailTab';
|
||||
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
|
||||
|
||||
import ReceiptDrawerCls from 'style/components/Drawers/ReceiptDrawer.module.scss';
|
||||
|
||||
/**
|
||||
* Receipt view detail.
|
||||
*/
|
||||
export default function ReceiptDetail() {
|
||||
const { transactions, receiptId } = useReceiptDetailDrawerContext();
|
||||
const { transactions } = useReceiptDetailDrawerContext();
|
||||
|
||||
return (
|
||||
<div className="view-detail-drawer">
|
||||
<Tabs animate={true} large={true} defaultSelectedTabId="journal_entries">
|
||||
<div className={clsx(ReceiptDrawerCls.root)}>
|
||||
<DrawerMainTabs defaultSelectedTabId="details">
|
||||
<Tab
|
||||
title={intl.get('details')}
|
||||
id={'details'}
|
||||
panel={<ReceiptDetailTab receiptId={receiptId} />}
|
||||
panel={<ReceiptDetailTab />}
|
||||
/>
|
||||
<Tab
|
||||
title={intl.get('journal_entries')}
|
||||
id={'journal_entries'}
|
||||
panel={<JournalEntriesTable transactions={transactions} />}
|
||||
/>
|
||||
</Tabs>
|
||||
</DrawerMainTabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
Button,
|
||||
NavbarGroup,
|
||||
Classes,
|
||||
NavbarDivider,
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||
|
||||
import { Icon, FormattedMessage as T } from 'components';
|
||||
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
|
||||
|
||||
import { safeCallback, compose } from 'utils';
|
||||
|
||||
function ReceiptDetailActionBar({
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
|
||||
// #withAlertsActions
|
||||
openAlert,
|
||||
|
||||
// #withDrawerActions
|
||||
closeDrawer,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { receiptId } = useReceiptDetailDrawerContext();
|
||||
|
||||
// Handle edit sale receipt.
|
||||
const onEditReceipt = () => {
|
||||
return receiptId
|
||||
? (history.push(`/receipts/${receiptId}/edit`),
|
||||
closeDrawer('receipt-detail-drawer'))
|
||||
: null;
|
||||
};
|
||||
|
||||
// Handle delete sale receipt.
|
||||
const onDeleteReceipt = () => {
|
||||
return receiptId
|
||||
? (openAlert('receipt-delete', { receiptId }),
|
||||
closeDrawer('receipt-detail-drawer'))
|
||||
: null;
|
||||
};
|
||||
// Handle print receipt.
|
||||
const onPrintReceipt = () => {
|
||||
openDialog('receipt-pdf-preview', { receiptId });
|
||||
};
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={<T id={'edit_receipt'} />}
|
||||
onClick={safeCallback(onEditReceipt)}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="print-16" />}
|
||||
text={<T id={'print'} />}
|
||||
onClick={safeCallback(onPrintReceipt)}
|
||||
/>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon={'trash-16'} iconSize={16} />}
|
||||
text={<T id={'delete'} />}
|
||||
intent={Intent.DANGER}
|
||||
onClick={safeCallback(onDeleteReceipt)}
|
||||
/>
|
||||
</NavbarGroup>
|
||||
</DashboardActionsBar>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withDialogActions,
|
||||
withDrawerActions,
|
||||
withAlertsActions,
|
||||
)(ReceiptDetailActionBar);
|
||||
@@ -10,10 +10,10 @@ import { ReceiptDetailDrawerProvider } from './ReceiptDetailDrawerProvider';
|
||||
*/
|
||||
export default function ReceiptDetailDrawerContent({
|
||||
// #ownProp
|
||||
receipt,
|
||||
receiptId,
|
||||
}) {
|
||||
return (
|
||||
<ReceiptDetailDrawerProvider receiptId={receipt}>
|
||||
<ReceiptDetailDrawerProvider receiptId={receiptId}>
|
||||
<ReceiptDetail />
|
||||
</ReceiptDetailDrawerProvider>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { DrawerHeaderContent, DashboardInsider } from 'components';
|
||||
import { useTransactionsByReference } from 'hooks/query';
|
||||
import { useTransactionsByReference, useReceipt } from 'hooks/query';
|
||||
|
||||
// useTransactionsByReference
|
||||
const ReceiptDetailDrawerContext = React.createContext();
|
||||
@@ -10,6 +10,14 @@ const ReceiptDetailDrawerContext = React.createContext();
|
||||
* Receipt detail provider.
|
||||
*/
|
||||
function ReceiptDetailDrawerProvider({ receiptId, ...props }) {
|
||||
// Fetch sale receipt details.
|
||||
const { data: receipt, isFetching: isReceiptLoading } = useReceipt(
|
||||
receiptId,
|
||||
{
|
||||
enabled: !!receiptId,
|
||||
},
|
||||
);
|
||||
|
||||
// Handle fetch transaction by reference.
|
||||
const {
|
||||
data: { transactions },
|
||||
@@ -26,10 +34,11 @@ function ReceiptDetailDrawerProvider({ receiptId, ...props }) {
|
||||
const provider = {
|
||||
transactions,
|
||||
receiptId,
|
||||
receipt,
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardInsider loading={isTransactionLoading}>
|
||||
<DashboardInsider loading={isTransactionLoading || isReceiptLoading}>
|
||||
<DrawerHeaderContent
|
||||
name="receipt-detail-drawer"
|
||||
title={intl.get('receipt_details')}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { TotalLines, TotalLine } from 'components';
|
||||
|
||||
import ReceiptDrawerCls from 'style/components/Drawers/ReceiptDrawer.module.scss';
|
||||
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
|
||||
|
||||
export function ReceiptDetailFooter() {
|
||||
const { receipt } = useReceiptDetailDrawerContext();
|
||||
|
||||
return (
|
||||
<div className={clsx(ReceiptDrawerCls.detail_panel_footer)}>
|
||||
<TotalLines>
|
||||
<TotalLine
|
||||
title={'Subtotal'}
|
||||
value={receipt.amount}
|
||||
className={ReceiptDrawerCls.total_line_subtotal}
|
||||
/>
|
||||
<TotalLine
|
||||
title={'TOTAL'}
|
||||
value={receipt.amount}
|
||||
className={ReceiptDrawerCls.total_line_total}
|
||||
/>
|
||||
<TotalLine
|
||||
title={'Payment made'}
|
||||
value={receipt.amount}
|
||||
className={ReceiptDrawerCls.total_line_payment}
|
||||
/>
|
||||
<TotalLine
|
||||
title={'Due amount'}
|
||||
value={'0'}
|
||||
className={ReceiptDrawerCls.total_line_dueAmount}
|
||||
/>
|
||||
</TotalLines>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { defaultTo } from 'lodash';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { DetailsMenu, DetailItem } from 'components';
|
||||
|
||||
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
|
||||
|
||||
import ReceiptDrawerCls from 'style/components/Drawers/ReceiptDrawer.module.scss';
|
||||
|
||||
/**
|
||||
* receipt detail content.
|
||||
*/
|
||||
export default function ReceiptDetailHeader() {
|
||||
const { receipt } = useReceiptDetailDrawerContext();
|
||||
|
||||
return (
|
||||
<div className={clsx(ReceiptDrawerCls.detail_panel_header)}>
|
||||
<DetailsMenu>
|
||||
<DetailItem label={intl.get('amount')}>
|
||||
<h3 class="big-number">{receipt.formatted_amount}</h3>
|
||||
</DetailItem>
|
||||
<DetailItem
|
||||
label={intl.get('receipt_no')}
|
||||
children={defaultTo(receipt.receipt_no, '-')}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('customer_name')}
|
||||
children={receipt.customer?.display_name}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('receipt_date')}
|
||||
children={receipt.formatted_receipt_date}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('closed_date')}
|
||||
children={defaultTo(receipt.formatted_closed_at_date, '-')}
|
||||
/>
|
||||
</DetailsMenu>
|
||||
|
||||
<DetailsMenu direction={'horizantal'}>
|
||||
<DetailItem
|
||||
label={intl.get('deposit_account')}
|
||||
children={receipt.deposit_account?.name}
|
||||
/>
|
||||
<DetailItem
|
||||
label={intl.get('reference')}
|
||||
children={defaultTo(receipt.reference_no, '--')}
|
||||
/>
|
||||
<DetailItem label={'Created at'} children={'2020 Ang 21'} />
|
||||
</DetailsMenu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,85 +1,25 @@
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import {
|
||||
Button,
|
||||
NavbarGroup,
|
||||
Classes,
|
||||
NavbarDivider,
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
||||
import { Card } from 'components';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||
import ReceiptDetailActionBar from './ReceiptDetailActionBar';
|
||||
import ReceiptDetailHeader from './ReceiptDetailHeader';
|
||||
import ReceiptDetailTable from './ReceiptDetailTable';
|
||||
import { ReceiptDetailFooter } from './ReceiptDetailFooter';
|
||||
|
||||
import { Icon, FormattedMessage as T } from 'components';
|
||||
import ReceiptDrawerCls from 'style/components/Drawers/ReceiptDrawer.module.scss';
|
||||
|
||||
import { safeCallback, compose } from 'utils';
|
||||
|
||||
function ReceiptDetailTab({
|
||||
receiptId,
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
|
||||
// #withAlertsActions
|
||||
openAlert,
|
||||
|
||||
// #withDrawerActions
|
||||
closeDrawer,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
// Handle edit sale receipt.
|
||||
const onEditReceipt = () => {
|
||||
return receiptId
|
||||
? (history.push(`/receipts/${receiptId}/edit`),
|
||||
closeDrawer('receipt-detail-drawer'))
|
||||
: null;
|
||||
};
|
||||
|
||||
// Handle delete sale receipt.
|
||||
const onDeleteReceipt = () => {
|
||||
return receiptId
|
||||
? (openAlert('receipt-delete', { receiptId }),
|
||||
closeDrawer('receipt-detail-drawer'))
|
||||
: null;
|
||||
};
|
||||
// Handle print receipt.
|
||||
const onPrintReceipt = () => {
|
||||
openDialog('receipt-pdf-preview', { receiptId });
|
||||
};
|
||||
export default function ReceiptDetailTab() {
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={<T id={'edit_receipt'} />}
|
||||
onClick={safeCallback(onEditReceipt)}
|
||||
/>
|
||||
<NavbarDivider />
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="print-16" />}
|
||||
text={<T id={'print'} />}
|
||||
onClick={safeCallback(onPrintReceipt)}
|
||||
/>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon={'trash-16'} iconSize={16} />}
|
||||
text={<T id={'delete'} />}
|
||||
intent={Intent.DANGER}
|
||||
onClick={safeCallback(onDeleteReceipt)}
|
||||
/>
|
||||
</NavbarGroup>
|
||||
</DashboardActionsBar>
|
||||
<div className={clsx(ReceiptDrawerCls.detail_panel)}>
|
||||
<ReceiptDetailActionBar />
|
||||
|
||||
<Card>
|
||||
<ReceiptDetailHeader />
|
||||
<ReceiptDetailTable />
|
||||
<ReceiptDetailFooter />
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withDialogActions,
|
||||
withDrawerActions,
|
||||
withAlertsActions,
|
||||
)(ReceiptDetailTab);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
|
||||
import { DataTable } from 'components';
|
||||
|
||||
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
|
||||
import { useReceiptReadonlyEntriesTableColumns } from './utils';
|
||||
|
||||
import ReceiptDrawerCls from 'style/components/Drawers/ReceiptDrawer.module.scss';
|
||||
|
||||
/**
|
||||
* Receipt readonly details table columns.
|
||||
*/
|
||||
export default function ReceiptDetailTable() {
|
||||
const {
|
||||
receipt: { entries },
|
||||
} = useReceiptDetailDrawerContext();
|
||||
|
||||
// Receipt readonly entries table columns.
|
||||
const columns = useReceiptReadonlyEntriesTableColumns();
|
||||
|
||||
return (
|
||||
<div className={clsx(ReceiptDrawerCls.detail_panel_table)}>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={entries}
|
||||
className={'table-constrant'}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -18,9 +18,14 @@ function ReceiptDetailDrawer({
|
||||
payload: { receiptId },
|
||||
}) {
|
||||
return (
|
||||
<Drawer isOpen={isOpen} name={name} size={'750px'}>
|
||||
<Drawer
|
||||
isOpen={isOpen}
|
||||
name={name}
|
||||
style={{ minWidth: '700px', maxWidth: '900px' }}
|
||||
size={'65%'}
|
||||
>
|
||||
<DrawerSuspense>
|
||||
<ReceiptDetailDrawerContent receipt={receiptId} />
|
||||
<ReceiptDetailDrawerContent receiptId={receiptId} />
|
||||
</DrawerSuspense>
|
||||
</Drawer>
|
||||
);
|
||||
|
||||
40
client/src/containers/Drawers/ReceiptDetailDrawer/utils.js
Normal file
40
client/src/containers/Drawers/ReceiptDetailDrawer/utils.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
export const useReceiptReadonlyEntriesTableColumns = () => React.useMemo(() => [
|
||||
{
|
||||
Header: intl.get('product_and_service'),
|
||||
accessor: 'item.name',
|
||||
width: 150,
|
||||
className: 'name',
|
||||
disableSortBy: true
|
||||
},
|
||||
{
|
||||
Header: intl.get('description'),
|
||||
accessor: 'description',
|
||||
className: 'description',
|
||||
disableSortBy: true
|
||||
},
|
||||
{
|
||||
Header: intl.get('quantity'),
|
||||
accessor: 'quantity',
|
||||
width: 100,
|
||||
className: 'quantity',
|
||||
disableSortBy: true
|
||||
},
|
||||
{
|
||||
Header: intl.get('rate'),
|
||||
accessor: 'rate',
|
||||
width: 100,
|
||||
className: 'rate',
|
||||
disableSortBy: true
|
||||
},
|
||||
{
|
||||
Header: intl.get('amount'),
|
||||
accessor: 'amount',
|
||||
width: 100,
|
||||
className: 'amount',
|
||||
disableSortBy: true
|
||||
},
|
||||
], []);
|
||||
|
||||
@@ -15,12 +15,14 @@ function BillUniversalSearchSelectComponent({
|
||||
// #ownProps
|
||||
resourceType,
|
||||
resourceId,
|
||||
onAction,
|
||||
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
}) {
|
||||
if (resourceType === RESOURCES_TYPES.INVOICE) {
|
||||
if (resourceType === RESOURCES_TYPES.BILL) {
|
||||
openDrawer('bill-drawer', { billId: resourceId });
|
||||
onAction && onAction();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -103,6 +105,7 @@ export function BillUniversalSearchItem(
|
||||
}
|
||||
|
||||
const billsToSearch = (bill) => ({
|
||||
id: bill.id,
|
||||
text: bill.vendor.display_name,
|
||||
reference: bill,
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import intl from 'react-intl-universal';
|
||||
|
||||
import { Choose, T, Icon } from 'components';
|
||||
|
||||
import { RESOURCES_TYPES } from "../../../../common/resourcesTypes";
|
||||
import { RESOURCES_TYPES } from "common/resourcesTypes";
|
||||
import withDrawerActions from "../../../Drawer/withDrawerActions";
|
||||
|
||||
/**
|
||||
@@ -19,7 +19,7 @@ function EstimateUniversalSearchSelectComponent({
|
||||
openDrawer,
|
||||
}) {
|
||||
if (resourceType === RESOURCES_TYPES.ESTIMATE) {
|
||||
openDrawer('estimate-drawer', { estimateId: resourceId });
|
||||
openDrawer('estimate-detail-drawer', { estimateId: resourceId });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -69,6 +69,7 @@ export function EstimateUniversalSearchItem(
|
||||
) {
|
||||
return (
|
||||
<MenuItem
|
||||
active={modifiers.active}
|
||||
text={
|
||||
<div>
|
||||
<div>{item.text}</div>
|
||||
@@ -91,13 +92,19 @@ export function EstimateUniversalSearchItem(
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transformes the estimates to search items.
|
||||
*/
|
||||
const transformEstimatesToSearch = (estimate) => ({
|
||||
id: estimate.id,
|
||||
text: estimate.customer.display_name,
|
||||
label: estimate.formatted_balance,
|
||||
reference: estimate,
|
||||
});
|
||||
|
||||
/**
|
||||
* Estimate resource universal search bind configure.
|
||||
*/
|
||||
export const universalSearchEstimateBind = () => ({
|
||||
resourceType: RESOURCES_TYPES.ESTIMATE,
|
||||
optionItemLabel: intl.get('estimates'),
|
||||
|
||||
@@ -22,7 +22,8 @@ function ReceiptUniversalSearchSelectComponent({
|
||||
openDrawer,
|
||||
}) {
|
||||
if (resourceType === RESOURCES_TYPES.RECEIPT) {
|
||||
openDrawer('receipt-drawer', { estimateId: resourceId });
|
||||
openDrawer('receipt-detail-drawer', { receiptId: resourceId });
|
||||
onAction && onAction();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -84,6 +85,7 @@ export function ReceiptUniversalSearchItem(
|
||||
* Transformes receipt resource item to search item.
|
||||
*/
|
||||
const transformReceiptsToSearch = (receipt) => ({
|
||||
id: receipt.id,
|
||||
text: receipt.customer.display_name,
|
||||
label: receipt.formatted_amount,
|
||||
reference: receipt,
|
||||
|
||||
Reference in New Issue
Block a user