mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 07:10:33 +00:00
Merge remote-tracking branch 'origin/feature/Detail'
This commit is contained in:
@@ -8,10 +8,17 @@ const DIRECTION = {
|
|||||||
HORIZANTAL: 'horizantal',
|
HORIZANTAL: 'horizantal',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DetailsMenuContext = React.createContext();
|
||||||
|
const useDetailsMenuContext = () => React.useContext(DetailsMenuContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Details menu.
|
* Details menu.
|
||||||
*/
|
*/
|
||||||
export function DetailsMenu({ children, direction = DIRECTION.VERTICAL }) {
|
export function DetailsMenu({
|
||||||
|
children,
|
||||||
|
direction = DIRECTION.VERTICAL,
|
||||||
|
minLabelSize,
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames('details-menu', {
|
className={classNames('details-menu', {
|
||||||
@@ -19,7 +26,9 @@ export function DetailsMenu({ children, direction = DIRECTION.VERTICAL }) {
|
|||||||
'details-menu--horizantal': direction === DIRECTION.HORIZANTAL,
|
'details-menu--horizantal': direction === DIRECTION.HORIZANTAL,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
<DetailsMenuContext.Provider value={{ minLabelSize }}>
|
||||||
{children}
|
{children}
|
||||||
|
</DetailsMenuContext.Provider>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -28,11 +37,22 @@ export function DetailsMenu({ children, direction = DIRECTION.VERTICAL }) {
|
|||||||
* Detail item.
|
* Detail item.
|
||||||
*/
|
*/
|
||||||
export function DetailItem({ label, children, name }) {
|
export function DetailItem({ label, children, name }) {
|
||||||
|
const { minLabelSize } = useDetailsMenuContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames('detail-item', {
|
<div
|
||||||
|
className={classNames('detail-item', {
|
||||||
[`detail-item--${name}`]: name,
|
[`detail-item--${name}`]: name,
|
||||||
})}>
|
})}
|
||||||
<div class="detail-item__label">{label}</div>
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
'min-width': minLabelSize,
|
||||||
|
}}
|
||||||
|
class="detail-item__label"
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</div>
|
||||||
<div class="detail-item__content">{children}</div>
|
<div class="detail-item__content">{children}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
26
client/src/components/Drawer/DrawerInsider.js
Normal file
26
client/src/components/Drawer/DrawerInsider.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import LoadingIndicator from 'components/LoadingIndicator';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drawer inside.
|
||||||
|
*/
|
||||||
|
export function DrawerInsider({
|
||||||
|
loading,
|
||||||
|
children,
|
||||||
|
name,
|
||||||
|
mount = false,
|
||||||
|
className,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className={classnames({
|
||||||
|
'drawer__insider': true,
|
||||||
|
'drawer__insider--loading': loading,
|
||||||
|
[`drawer__insider--${name}`]: !!name,
|
||||||
|
}, className)}>
|
||||||
|
<LoadingIndicator loading={loading} mount={mount}>
|
||||||
|
{ children }
|
||||||
|
</LoadingIndicator>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
15
client/src/components/Drawer/DrawerMainTabs.js
Normal file
15
client/src/components/Drawer/DrawerMainTabs.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Tabs } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drawer main tabs.
|
||||||
|
*/
|
||||||
|
export function DrawerMainTabs({ children, ...restProps }) {
|
||||||
|
return (
|
||||||
|
<div class="drawer__main-tabs">
|
||||||
|
<Tabs animate={true} large={true} {...restProps}>
|
||||||
|
{children}
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import EstimateDrawer from 'containers/Sales/Estimates/EstimateDetails/EstimateDrawer';
|
// import EstimateDrawer from 'containers/Sales/Estimates/EstimateDetails/EstimateDrawer';
|
||||||
import InvoiceDrawer from 'containers/Sales/Invoices/InvoiceDetails/InvoiceDrawer';
|
// import InvoiceDrawer from 'containers/Sales/Invoices/InvoiceDetails/InvoiceDrawer';
|
||||||
import ReceiptDrawer from 'containers/Sales/Receipts/ReceiptDetails/ReceiptDrawer';
|
// import ReceiptDrawer from 'containers/Sales/Receipts/ReceiptDetails/ReceiptDrawer';
|
||||||
import PaymentReceiveDrawer from 'containers/Sales/PaymentReceives/PaymentDetails/PaymentReceiveDrawer';
|
import PaymentReceiveDrawer from 'containers/Sales/PaymentReceives/PaymentDetails/PaymentReceiveDrawer';
|
||||||
import AccountDrawer from 'containers/Drawers/AccountDrawer';
|
import AccountDrawer from 'containers/Drawers/AccountDrawer';
|
||||||
import ManualJournalDrawer from 'containers/Drawers/ManualJournalDrawer';
|
import ManualJournalDrawer from 'containers/Drawers/ManualJournalDrawer';
|
||||||
@@ -23,9 +23,9 @@ import { DRAWERS } from 'common/drawers';
|
|||||||
export default function DrawersContainer() {
|
export default function DrawersContainer() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<EstimateDrawer name={DRAWERS.EstimateDrawer} />
|
{/* <EstimateDrawer name={DRAWERS.EstimateDrawer} /> */}
|
||||||
<InvoiceDrawer name={'invoice-drawer'} />
|
{/* <InvoiceDrawer name={'invoice-drawer'} /> */}
|
||||||
<ReceiptDrawer name={'receipt-drawer'} />
|
{/* <ReceiptDrawer name={'receipt-drawer'} /> */}
|
||||||
<PaymentReceiveDrawer name={'payment-receive-drawer'} />
|
<PaymentReceiveDrawer name={'payment-receive-drawer'} />
|
||||||
<AccountDrawer name={DRAWERS.ACCOUNT_DRAWER} />
|
<AccountDrawer name={DRAWERS.ACCOUNT_DRAWER} />
|
||||||
<ManualJournalDrawer name={DRAWERS.JOURNAL_DRAWER} />
|
<ManualJournalDrawer name={DRAWERS.JOURNAL_DRAWER} />
|
||||||
|
|||||||
12
client/src/components/TotalLines/TotalLines.module.scss
Normal file
12
client/src/components/TotalLines/TotalLines.module.scss
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.total_lines {}
|
||||||
|
|
||||||
|
|
||||||
|
.total_line {
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid #d2dde2;
|
||||||
|
|
||||||
|
:global .amount,
|
||||||
|
:global .title{
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
client/src/components/TotalLines/index.js
Normal file
23
client/src/components/TotalLines/index.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import clsx from 'classnames';
|
||||||
|
|
||||||
|
import TotalLinesCls from './TotalLines.module.scss';
|
||||||
|
|
||||||
|
export function TotalLines({ children, className }) {
|
||||||
|
return (
|
||||||
|
<div className={clsx('total_lines', TotalLinesCls.total_lines, className)}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TotalLine({ title, value, className }) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx('total_lines_line', TotalLinesCls.total_line, className)}
|
||||||
|
>
|
||||||
|
<div class="title">{title}</div>
|
||||||
|
<div class="amount">{value}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -2,11 +2,11 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import If from './If';
|
import If from './If';
|
||||||
|
|
||||||
const Choose = props => {
|
const Choose = (props) => {
|
||||||
let when = null;
|
let when = null;
|
||||||
let otherwise = null;
|
let otherwise = null;
|
||||||
|
|
||||||
React.Children.forEach(props.children, children => {
|
React.Children.forEach(props.children, (children) => {
|
||||||
if (children.props.condition === undefined) {
|
if (children.props.condition === undefined) {
|
||||||
otherwise = children;
|
otherwise = children;
|
||||||
} else if (!when && children.props.condition === true) {
|
} else if (!when && children.props.condition === true) {
|
||||||
@@ -18,16 +18,16 @@ const Choose = props => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Choose.propTypes = {
|
Choose.propTypes = {
|
||||||
children: PropTypes.node
|
children: PropTypes.node,
|
||||||
};
|
};
|
||||||
|
|
||||||
Choose.When = If;
|
Choose.When = If;
|
||||||
|
|
||||||
Choose.Otherwise = ({render, children}) => render ? render() : children;
|
Choose.Otherwise = ({ render, children }) => (render ? render() : children);
|
||||||
|
|
||||||
Choose.Otherwise.propTypes = {
|
Choose.Otherwise.propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
render: PropTypes.func
|
render: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Choose;
|
export default Choose;
|
||||||
@@ -69,6 +69,9 @@ export * from './Dashboard/DashboardRowsHeightButton';
|
|||||||
export * from './UniversalSearch/UniversalSearch';
|
export * from './UniversalSearch/UniversalSearch';
|
||||||
export * from './PdfPreview';
|
export * from './PdfPreview';
|
||||||
export * from './Details';
|
export * from './Details';
|
||||||
|
export * from './Drawer/DrawerInsider';
|
||||||
|
export * from './Drawer/DrawerMainTabs';
|
||||||
|
export * from './TotalLines/index'
|
||||||
|
|
||||||
const Hint = FieldHint;
|
const Hint = FieldHint;
|
||||||
|
|
||||||
|
|||||||
@@ -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 { BillDrawerProvider } from './BillDrawerProvider';
|
||||||
import BillDrawerDetails from './BillDrawerDetails';
|
import BillDrawerDetails from './BillDrawerDetails';
|
||||||
import BillDrawerAlerts from './BillDrawerAlerts';
|
// import BillDrawerAlerts from './BillDrawerAlerts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bill drawer content.
|
* Bill drawer content.
|
||||||
*/
|
*/
|
||||||
export default function BillDrawerContent({
|
export default function BillDrawerContent({
|
||||||
// #ownProp
|
// #ownProp
|
||||||
bill,
|
billId,
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<BillDrawerProvider billId={bill}>
|
<BillDrawerProvider billId={billId}>
|
||||||
<BillDrawerDetails />
|
<BillDrawerDetails />
|
||||||
<BillDrawerAlerts />
|
{/* <BillDrawerAlerts /> */}
|
||||||
</BillDrawerProvider>
|
</BillDrawerProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Tabs, Tab } from '@blueprintjs/core';
|
import { Tab } from '@blueprintjs/core';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
import clsx from 'classnames';
|
||||||
|
|
||||||
|
import { DrawerMainTabs } from 'components';
|
||||||
|
|
||||||
|
import BillDetailTab from './BillDetailTab';
|
||||||
import LocatedLandedCostTable from './LocatedLandedCostTable';
|
import LocatedLandedCostTable from './LocatedLandedCostTable';
|
||||||
import JournalEntriesTable from '../../JournalEntriesTable/JournalEntriesTable';
|
import JournalEntriesTable from '../../JournalEntriesTable/JournalEntriesTable';
|
||||||
import { useBillDrawerContext } from './BillDrawerProvider';
|
import { useBillDrawerContext } from './BillDrawerProvider';
|
||||||
|
|
||||||
|
import BillDrawerCls from 'style/components/Drawers/BillDrawer.module.scss';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bill view details.
|
* Bill view details.
|
||||||
*/
|
*/
|
||||||
@@ -15,9 +21,13 @@ export default function BillDrawerDetails() {
|
|||||||
} = useBillDrawerContext();
|
} = useBillDrawerContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="view-detail-drawer">
|
<div className={clsx(BillDrawerCls.root)}>
|
||||||
<Tabs animate={true} large={true} defaultSelectedTabId="journal_entries">
|
<DrawerMainTabs defaultSelectedTabId="details">
|
||||||
<Tab title={intl.get('details')} id={'details'} disabled={true} />
|
<Tab
|
||||||
|
title={intl.get('details')}
|
||||||
|
id={'details'}
|
||||||
|
panel={<BillDetailTab />}
|
||||||
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
title={intl.get('journal_entries')}
|
title={intl.get('journal_entries')}
|
||||||
id={'journal_entries'}
|
id={'journal_entries'}
|
||||||
@@ -28,9 +38,7 @@ export default function BillDrawerDetails() {
|
|||||||
id={'landed_cost'}
|
id={'landed_cost'}
|
||||||
panel={<LocatedLandedCostTable />}
|
panel={<LocatedLandedCostTable />}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</DrawerMainTabs>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 42 / fon-w 600
|
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { DrawerHeaderContent, DashboardInsider } from 'components';
|
import { DrawerHeaderContent, DashboardInsider } from 'components';
|
||||||
import { useBillLocatedLandedCost } from 'hooks/query';
|
import {
|
||||||
import { useTransactionsByReference } from 'hooks/query';
|
useBill,
|
||||||
|
useTransactionsByReference,
|
||||||
|
useBillLocatedLandedCost,
|
||||||
|
} from 'hooks/query';
|
||||||
|
|
||||||
const BillDrawerContext = React.createContext();
|
const BillDrawerContext = React.createContext();
|
||||||
|
|
||||||
@@ -10,6 +13,10 @@ const BillDrawerContext = React.createContext();
|
|||||||
* Bill drawer provider.
|
* Bill drawer provider.
|
||||||
*/
|
*/
|
||||||
function BillDrawerProvider({ billId, ...props }) {
|
function BillDrawerProvider({ billId, ...props }) {
|
||||||
|
// Handle fetch bill details.
|
||||||
|
const { isLoading: isBillLoading, data: bill } = useBill(billId, {
|
||||||
|
enabled: !!billId,
|
||||||
|
});
|
||||||
|
|
||||||
// Handle fetch transaction by reference.
|
// Handle fetch transaction by reference.
|
||||||
const { data, isLoading: isTransactionLoading } = useTransactionsByReference(
|
const { data, isLoading: isTransactionLoading } = useTransactionsByReference(
|
||||||
@@ -31,10 +38,13 @@ function BillDrawerProvider({ billId, ...props }) {
|
|||||||
transactions,
|
transactions,
|
||||||
billId,
|
billId,
|
||||||
data,
|
data,
|
||||||
|
bill,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardInsider loading={isLandedCostLoading || isTransactionLoading}>
|
<DashboardInsider
|
||||||
|
loading={isLandedCostLoading || isTransactionLoading || isBillLoading}
|
||||||
|
>
|
||||||
<DrawerHeaderContent
|
<DrawerHeaderContent
|
||||||
name="bill-drawer"
|
name="bill-drawer"
|
||||||
title={intl.get('bill_details')}
|
title={intl.get('bill_details')}
|
||||||
|
|||||||
@@ -16,9 +16,14 @@ function BillDrawer({
|
|||||||
payload: { billId },
|
payload: { billId },
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Drawer isOpen={isOpen} name={name} size={'750px'}>
|
<Drawer
|
||||||
|
isOpen={isOpen}
|
||||||
|
name={name}
|
||||||
|
style={{ minWidth: '700px', maxWidth: '900px' }}
|
||||||
|
size={'65%'}
|
||||||
|
>
|
||||||
<DrawerSuspense>
|
<DrawerSuspense>
|
||||||
<BillDrawerContent bill={billId} />
|
<BillDrawerContent billId={billId} />
|
||||||
</DrawerSuspense>
|
</DrawerSuspense>
|
||||||
</Drawer>
|
</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 React from 'react';
|
||||||
import { Tabs, Tab } from '@blueprintjs/core';
|
import { Tab } from '@blueprintjs/core';
|
||||||
import intl from 'react-intl-universal';
|
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
|
* Estimate view detail
|
||||||
*/
|
*/
|
||||||
export default function EstimateDetail() {
|
export default function EstimateDetail() {
|
||||||
return (
|
return (
|
||||||
<div className="view-detail-drawer">
|
<div className={clsx(EstimateDetailsCls.root)}>
|
||||||
<Tabs animate={true} large={true}>
|
<DrawerMainTabs>
|
||||||
<Tab
|
<Tab
|
||||||
title={intl.get('details')}
|
title={intl.get('details')}
|
||||||
id={'details'}
|
id={'details'}
|
||||||
panel={<EstimateDetailTab />}
|
panel={<EstimateDetailPanel />}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</DrawerMainTabs>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,12 @@ import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
|||||||
|
|
||||||
import { Icon, FormattedMessage as T } from 'components';
|
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
|
// #withDialogActions
|
||||||
openDialog,
|
openDialog,
|
||||||
|
|
||||||
@@ -29,28 +32,24 @@ function EstimateDetailTab({
|
|||||||
// #withDrawerActions
|
// #withDrawerActions
|
||||||
closeDrawer,
|
closeDrawer,
|
||||||
}) {
|
}) {
|
||||||
const history = useHistory();
|
|
||||||
|
|
||||||
const { estimateId } = useEstimateDetailDrawerContext();
|
const { estimateId } = useEstimateDetailDrawerContext();
|
||||||
|
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
// Handle edit sale estimate.
|
// Handle edit sale estimate.
|
||||||
const onEditEstimate = () => {
|
const handleEditEstimate = () => {
|
||||||
return estimateId
|
history.push(`/estimates/${estimateId}/edit`);
|
||||||
? (history.push(`/estimates/${estimateId}/edit`),
|
closeDrawer('estimate-detail-drawer');
|
||||||
closeDrawer('estimate-detail-drawer'))
|
|
||||||
: null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle delete sale estimate.
|
// Handle delete sale estimate.
|
||||||
const onDeleteEstimate = () => {
|
const handleDeleteEstimate = () => {
|
||||||
return estimateId
|
openAlert('estimate-delete', { estimateId });
|
||||||
? (openAlert('estimate-delete', { estimateId }),
|
closeDrawer('estimate-detail-drawer');
|
||||||
closeDrawer('estimate-detail-drawer'))
|
|
||||||
: null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle print estimate.
|
// Handle print estimate.
|
||||||
const onPrintEstimate = () => {
|
const handlePrintEstimate = () => {
|
||||||
openDialog('estimate-pdf-preview', { estimateId });
|
openDialog('estimate-pdf-preview', { estimateId });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -61,21 +60,21 @@ function EstimateDetailTab({
|
|||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
icon={<Icon icon="pen-18" />}
|
icon={<Icon icon="pen-18" />}
|
||||||
text={<T id={'edit_estimate'} />}
|
text={<T id={'edit_estimate'} />}
|
||||||
onClick={safeCallback(onEditEstimate)}
|
onClick={handleEditEstimate}
|
||||||
/>
|
/>
|
||||||
<NavbarDivider />
|
<NavbarDivider />
|
||||||
<Button
|
<Button
|
||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
icon={<Icon icon="print-16" />}
|
icon={<Icon icon="print-16" />}
|
||||||
text={<T id={'print'} />}
|
text={<T id={'print'} />}
|
||||||
onClick={safeCallback(onPrintEstimate)}
|
onClick={handleDeleteEstimate}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
icon={<Icon icon={'trash-16'} iconSize={16} />}
|
icon={<Icon icon={'trash-16'} iconSize={16} />}
|
||||||
text={<T id={'delete'} />}
|
text={<T id={'delete'} />}
|
||||||
intent={Intent.DANGER}
|
intent={Intent.DANGER}
|
||||||
onClick={safeCallback(onDeleteEstimate)}
|
onClick={handlePrintEstimate}
|
||||||
/>
|
/>
|
||||||
</NavbarGroup>
|
</NavbarGroup>
|
||||||
</DashboardActionsBar>
|
</DashboardActionsBar>
|
||||||
@@ -86,4 +85,4 @@ export default compose(
|
|||||||
withDialogActions,
|
withDialogActions,
|
||||||
withAlertsActions,
|
withAlertsActions,
|
||||||
withDrawerActions,
|
withDrawerActions,
|
||||||
)(EstimateDetailTab);
|
)(EstimateDetailActionsBar);
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import 'style/components/Drawers/ViewDetail/ViewDetail.scss';
|
|
||||||
|
|
||||||
import EstimateDetail from './EstimateDetail';
|
import EstimateDetail from './EstimateDetail';
|
||||||
import { EstimateDetailDrawerProvider } from './EstimateDetailDrawerProvider';
|
import { EstimateDetailDrawerProvider } from './EstimateDetailDrawerProvider';
|
||||||
|
|
||||||
@@ -10,10 +8,10 @@ import { EstimateDetailDrawerProvider } from './EstimateDetailDrawerProvider';
|
|||||||
*/
|
*/
|
||||||
export default function EstimateDetailDrawerContent({
|
export default function EstimateDetailDrawerContent({
|
||||||
// #ownProp
|
// #ownProp
|
||||||
estimate,
|
estimateId,
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<EstimateDetailDrawerProvider estimateId={estimate}>
|
<EstimateDetailDrawerProvider estimateId={estimateId}>
|
||||||
<EstimateDetail />
|
<EstimateDetail />
|
||||||
</EstimateDetailDrawerProvider>
|
</EstimateDetailDrawerProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import intl from 'react-intl-universal';
|
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();
|
const EstimateDetailDrawerContext = React.createContext();
|
||||||
|
|
||||||
@@ -8,19 +9,25 @@ const EstimateDetailDrawerContext = React.createContext();
|
|||||||
* Estimate detail provider.
|
* Estimate detail provider.
|
||||||
*/
|
*/
|
||||||
function EstimateDetailDrawerProvider({ estimateId, ...props }) {
|
function EstimateDetailDrawerProvider({ estimateId, ...props }) {
|
||||||
|
// Fetches the estimate by the given id.
|
||||||
|
const { data: estimate, isLoading: isEstimateLoading } = useEstimate(
|
||||||
|
estimateId,
|
||||||
|
{ enabled: !!estimateId },
|
||||||
|
);
|
||||||
|
|
||||||
const provider = {
|
const provider = {
|
||||||
estimateId,
|
estimateId,
|
||||||
|
estimate,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardInsider>
|
<DrawerInsider loading={isEstimateLoading}>
|
||||||
<DrawerHeaderContent
|
<DrawerHeaderContent
|
||||||
name="estimate-detail-drawer"
|
name="estimate-detail-drawer"
|
||||||
title={intl.get('estimate_details')}
|
title={intl.get('estimate_details')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<EstimateDetailDrawerContext.Provider value={provider} {...props} />
|
<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 },
|
payload: { estimateId },
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Drawer isOpen={isOpen} name={name} size={'750px'}>
|
<Drawer
|
||||||
|
isOpen={isOpen}
|
||||||
|
name={name}
|
||||||
|
style={{ minWidth: '700px', maxWidth: '900px' }}
|
||||||
|
size={'65%'}
|
||||||
|
>
|
||||||
<DrawerSuspense>
|
<DrawerSuspense>
|
||||||
<EstimateDetailDrawerContent estimate={estimateId} />
|
<EstimateDetailDrawerContent estimateId={estimateId} />
|
||||||
</DrawerSuspense>
|
</DrawerSuspense>
|
||||||
</Drawer>
|
</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 React from 'react';
|
||||||
import { Tabs, Tab } from '@blueprintjs/core';
|
import { Tab } from '@blueprintjs/core';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
import clsx from 'classnames';
|
||||||
|
|
||||||
|
import { DrawerMainTabs } from 'components';
|
||||||
|
|
||||||
import JournalEntriesTable from '../../JournalEntriesTable/JournalEntriesTable';
|
import JournalEntriesTable from '../../JournalEntriesTable/JournalEntriesTable';
|
||||||
import InvoiceDetailTab from './InvoiceDetailTab';
|
import InvoiceDetailTab from './InvoiceDetailTab';
|
||||||
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
|
import { useInvoiceDetailDrawerContext } from './InvoiceDetailDrawerProvider';
|
||||||
|
|
||||||
|
import InvoiceDrawerCls from 'style/components/Drawers/InvoiceDrawer.module.scss';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice view detail.
|
* Invoice view detail.
|
||||||
*/
|
*/
|
||||||
export default function InvoiceDetail() {
|
export default function InvoiceDetail() {
|
||||||
const { transactions, invoiceId } = useInvoiceDetailDrawerContext();
|
const { transactions } = useInvoiceDetailDrawerContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="view-detail-drawer">
|
<div className={clsx(InvoiceDrawerCls.invoice_details)}>
|
||||||
<Tabs
|
<DrawerMainTabs defaultSelectedTabId="details">
|
||||||
animate={true}
|
|
||||||
large={true}
|
|
||||||
defaultSelectedTabId="journal_entries"
|
|
||||||
renderActiveTabPanelOnly={false}
|
|
||||||
>
|
|
||||||
<Tab
|
<Tab
|
||||||
title={intl.get('details')}
|
title={intl.get('details')}
|
||||||
id={'details'}
|
id={'details'}
|
||||||
panel={<InvoiceDetailTab invoiceId={invoiceId} />}
|
panel={<InvoiceDetailTab />}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
title={intl.get('journal_entries')}
|
title={intl.get('journal_entries')}
|
||||||
id={'journal_entries'}
|
id={'journal_entries'}
|
||||||
panel={<JournalEntriesTable transactions={transactions} />}
|
panel={<JournalEntriesTable transactions={transactions} />}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</DrawerMainTabs>
|
||||||
</div>
|
</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({
|
export default function InvoiceDetailDrawerContent({
|
||||||
// #ownProp
|
// #ownProp
|
||||||
invoice,
|
invoiceId,
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<InvoiceDetailDrawerProvider invoiceId={invoice}>
|
<InvoiceDetailDrawerProvider invoiceId={invoiceId}>
|
||||||
<InvoiceDetail />
|
<InvoiceDetail />
|
||||||
</InvoiceDetailDrawerProvider>
|
</InvoiceDetailDrawerProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { DrawerHeaderContent, DashboardInsider } from 'components';
|
import { DrawerHeaderContent, DashboardInsider } from 'components';
|
||||||
import { useTransactionsByReference } from 'hooks/query';
|
import { useTransactionsByReference, useInvoice } from 'hooks/query';
|
||||||
|
|
||||||
const InvoiceDetailDrawerContext = React.createContext();
|
const InvoiceDetailDrawerContext = React.createContext();
|
||||||
/**
|
/**
|
||||||
@@ -20,13 +20,19 @@ function InvoiceDetailDrawerProvider({ invoiceId, ...props }) {
|
|||||||
{ enabled: !!invoiceId },
|
{ enabled: !!invoiceId },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Fetch sale invoice details.
|
||||||
|
const { data: invoice, isLoading: isInvoiceLoading } = useInvoice(invoiceId, {
|
||||||
|
enabled: !!invoiceId,
|
||||||
|
});
|
||||||
|
|
||||||
//provider.
|
//provider.
|
||||||
const provider = {
|
const provider = {
|
||||||
transactions,
|
transactions,
|
||||||
invoiceId,
|
invoiceId,
|
||||||
|
invoice,
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<DashboardInsider loading={isTransactionLoading}>
|
<DashboardInsider loading={isTransactionLoading || isInvoiceLoading}>
|
||||||
<DrawerHeaderContent
|
<DrawerHeaderContent
|
||||||
name="invoice-detail-drawer"
|
name="invoice-detail-drawer"
|
||||||
title={intl.get('invoice_details')}
|
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 React from 'react';
|
||||||
import { useHistory } from 'react-router-dom';
|
import clsx from 'classnames';
|
||||||
|
|
||||||
import {
|
import { Card } from 'components';
|
||||||
Button,
|
|
||||||
NavbarGroup,
|
|
||||||
Classes,
|
|
||||||
NavbarDivider,
|
|
||||||
Intent,
|
|
||||||
} from '@blueprintjs/core';
|
|
||||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
|
||||||
|
|
||||||
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 InvoiceDrawerCls from 'style/components/Drawers/InvoiceDrawer.module.scss';
|
||||||
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 });
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice readonly details tab panel.
|
||||||
|
*/
|
||||||
|
export default function InvoiceDetailTab() {
|
||||||
return (
|
return (
|
||||||
<DashboardActionsBar>
|
<div className={clsx(InvoiceDrawerCls.detail_panel)}>
|
||||||
<NavbarGroup>
|
<InvoiceDetailActionsBar />
|
||||||
<Button
|
|
||||||
className={Classes.MINIMAL}
|
<Card>
|
||||||
icon={<Icon icon="pen-18" />}
|
<InvoiceDetailHeader />
|
||||||
text={<T id={'edit_invoice'} />}
|
<InvoiceDetailTable />
|
||||||
onClick={safeCallback(onEditInvoice)}
|
<InvoiceDetailFooter />
|
||||||
/>
|
</Card>
|
||||||
<NavbarDivider />
|
</div>
|
||||||
<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>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
|
||||||
withDialogActions,
|
|
||||||
withDrawerActions,
|
|
||||||
withAlertsActions,
|
|
||||||
)(InvoiceDetailTab);
|
|
||||||
|
|||||||
@@ -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 },
|
payload: { invoiceId },
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Drawer isOpen={isOpen} name={name} size={'750px'}>
|
<Drawer
|
||||||
|
isOpen={isOpen}
|
||||||
|
name={name}
|
||||||
|
style={{ minWidth: '700px', maxWidth: '900px' }}
|
||||||
|
size={'65%'}
|
||||||
|
>
|
||||||
<DrawerSuspense>
|
<DrawerSuspense>
|
||||||
<InvoiceDetailDrawerContent invoice={invoiceId} />
|
<InvoiceDetailDrawerContent invoiceId={invoiceId} />
|
||||||
</DrawerSuspense>
|
</DrawerSuspense>
|
||||||
</Drawer>
|
</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 React from 'react';
|
||||||
import { Tabs, Tab } from '@blueprintjs/core';
|
import { Tab } from '@blueprintjs/core';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
import clsx from 'classnames';
|
||||||
|
|
||||||
|
import { DrawerMainTabs } from 'components';
|
||||||
import JournalEntriesTable from '../../JournalEntriesTable/JournalEntriesTable';
|
import JournalEntriesTable from '../../JournalEntriesTable/JournalEntriesTable';
|
||||||
import ReceiptDetailTab from './ReceiptDetailTab';
|
import ReceiptDetailTab from './ReceiptDetailTab';
|
||||||
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
|
import { useReceiptDetailDrawerContext } from './ReceiptDetailDrawerProvider';
|
||||||
|
|
||||||
|
import ReceiptDrawerCls from 'style/components/Drawers/ReceiptDrawer.module.scss';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receipt view detail.
|
* Receipt view detail.
|
||||||
*/
|
*/
|
||||||
export default function ReceiptDetail() {
|
export default function ReceiptDetail() {
|
||||||
const { transactions, receiptId } = useReceiptDetailDrawerContext();
|
const { transactions } = useReceiptDetailDrawerContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="view-detail-drawer">
|
<div className={clsx(ReceiptDrawerCls.root)}>
|
||||||
<Tabs animate={true} large={true} defaultSelectedTabId="journal_entries">
|
<DrawerMainTabs defaultSelectedTabId="details">
|
||||||
<Tab
|
<Tab
|
||||||
title={intl.get('details')}
|
title={intl.get('details')}
|
||||||
id={'details'}
|
id={'details'}
|
||||||
panel={<ReceiptDetailTab receiptId={receiptId} />}
|
panel={<ReceiptDetailTab />}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
title={intl.get('journal_entries')}
|
title={intl.get('journal_entries')}
|
||||||
id={'journal_entries'}
|
id={'journal_entries'}
|
||||||
panel={<JournalEntriesTable transactions={transactions} />}
|
panel={<JournalEntriesTable transactions={transactions} />}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</DrawerMainTabs>
|
||||||
</div>
|
</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({
|
export default function ReceiptDetailDrawerContent({
|
||||||
// #ownProp
|
// #ownProp
|
||||||
receipt,
|
receiptId,
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<ReceiptDetailDrawerProvider receiptId={receipt}>
|
<ReceiptDetailDrawerProvider receiptId={receiptId}>
|
||||||
<ReceiptDetail />
|
<ReceiptDetail />
|
||||||
</ReceiptDetailDrawerProvider>
|
</ReceiptDetailDrawerProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { DrawerHeaderContent, DashboardInsider } from 'components';
|
import { DrawerHeaderContent, DashboardInsider } from 'components';
|
||||||
import { useTransactionsByReference } from 'hooks/query';
|
import { useTransactionsByReference, useReceipt } from 'hooks/query';
|
||||||
|
|
||||||
// useTransactionsByReference
|
// useTransactionsByReference
|
||||||
const ReceiptDetailDrawerContext = React.createContext();
|
const ReceiptDetailDrawerContext = React.createContext();
|
||||||
@@ -10,6 +10,14 @@ const ReceiptDetailDrawerContext = React.createContext();
|
|||||||
* Receipt detail provider.
|
* Receipt detail provider.
|
||||||
*/
|
*/
|
||||||
function ReceiptDetailDrawerProvider({ receiptId, ...props }) {
|
function ReceiptDetailDrawerProvider({ receiptId, ...props }) {
|
||||||
|
// Fetch sale receipt details.
|
||||||
|
const { data: receipt, isFetching: isReceiptLoading } = useReceipt(
|
||||||
|
receiptId,
|
||||||
|
{
|
||||||
|
enabled: !!receiptId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Handle fetch transaction by reference.
|
// Handle fetch transaction by reference.
|
||||||
const {
|
const {
|
||||||
data: { transactions },
|
data: { transactions },
|
||||||
@@ -26,10 +34,11 @@ function ReceiptDetailDrawerProvider({ receiptId, ...props }) {
|
|||||||
const provider = {
|
const provider = {
|
||||||
transactions,
|
transactions,
|
||||||
receiptId,
|
receiptId,
|
||||||
|
receipt,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardInsider loading={isTransactionLoading}>
|
<DashboardInsider loading={isTransactionLoading || isReceiptLoading}>
|
||||||
<DrawerHeaderContent
|
<DrawerHeaderContent
|
||||||
name="receipt-detail-drawer"
|
name="receipt-detail-drawer"
|
||||||
title={intl.get('receipt_details')}
|
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 React from 'react';
|
||||||
import { useHistory } from 'react-router-dom';
|
import clsx from 'classnames';
|
||||||
|
|
||||||
import {
|
import { Card } from 'components';
|
||||||
Button,
|
|
||||||
NavbarGroup,
|
|
||||||
Classes,
|
|
||||||
NavbarDivider,
|
|
||||||
Intent,
|
|
||||||
} from '@blueprintjs/core';
|
|
||||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
|
||||||
|
|
||||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
import ReceiptDetailActionBar from './ReceiptDetailActionBar';
|
||||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
import ReceiptDetailHeader from './ReceiptDetailHeader';
|
||||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
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';
|
export default function ReceiptDetailTab() {
|
||||||
|
|
||||||
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 });
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<DashboardActionsBar>
|
<div className={clsx(ReceiptDrawerCls.detail_panel)}>
|
||||||
<NavbarGroup>
|
<ReceiptDetailActionBar />
|
||||||
<Button
|
|
||||||
className={Classes.MINIMAL}
|
<Card>
|
||||||
icon={<Icon icon="pen-18" />}
|
<ReceiptDetailHeader />
|
||||||
text={<T id={'edit_receipt'} />}
|
<ReceiptDetailTable />
|
||||||
onClick={safeCallback(onEditReceipt)}
|
<ReceiptDetailFooter />
|
||||||
/>
|
</Card>
|
||||||
<NavbarDivider />
|
</div>
|
||||||
<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,
|
|
||||||
)(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 },
|
payload: { receiptId },
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Drawer isOpen={isOpen} name={name} size={'750px'}>
|
<Drawer
|
||||||
|
isOpen={isOpen}
|
||||||
|
name={name}
|
||||||
|
style={{ minWidth: '700px', maxWidth: '900px' }}
|
||||||
|
size={'65%'}
|
||||||
|
>
|
||||||
<DrawerSuspense>
|
<DrawerSuspense>
|
||||||
<ReceiptDetailDrawerContent receipt={receiptId} />
|
<ReceiptDetailDrawerContent receiptId={receiptId} />
|
||||||
</DrawerSuspense>
|
</DrawerSuspense>
|
||||||
</Drawer>
|
</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
|
// #ownProps
|
||||||
resourceType,
|
resourceType,
|
||||||
resourceId,
|
resourceId,
|
||||||
|
onAction,
|
||||||
|
|
||||||
// #withDrawerActions
|
// #withDrawerActions
|
||||||
openDrawer,
|
openDrawer,
|
||||||
}) {
|
}) {
|
||||||
if (resourceType === RESOURCES_TYPES.INVOICE) {
|
if (resourceType === RESOURCES_TYPES.BILL) {
|
||||||
openDrawer('bill-drawer', { billId: resourceId });
|
openDrawer('bill-drawer', { billId: resourceId });
|
||||||
|
onAction && onAction();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -103,6 +105,7 @@ export function BillUniversalSearchItem(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const billsToSearch = (bill) => ({
|
const billsToSearch = (bill) => ({
|
||||||
|
id: bill.id,
|
||||||
text: bill.vendor.display_name,
|
text: bill.vendor.display_name,
|
||||||
reference: bill,
|
reference: bill,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import intl from 'react-intl-universal';
|
|||||||
|
|
||||||
import { Choose, T, Icon } from 'components';
|
import { Choose, T, Icon } from 'components';
|
||||||
|
|
||||||
import { RESOURCES_TYPES } from "../../../../common/resourcesTypes";
|
import { RESOURCES_TYPES } from "common/resourcesTypes";
|
||||||
import withDrawerActions from "../../../Drawer/withDrawerActions";
|
import withDrawerActions from "../../../Drawer/withDrawerActions";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,7 +19,7 @@ function EstimateUniversalSearchSelectComponent({
|
|||||||
openDrawer,
|
openDrawer,
|
||||||
}) {
|
}) {
|
||||||
if (resourceType === RESOURCES_TYPES.ESTIMATE) {
|
if (resourceType === RESOURCES_TYPES.ESTIMATE) {
|
||||||
openDrawer('estimate-drawer', { estimateId: resourceId });
|
openDrawer('estimate-detail-drawer', { estimateId: resourceId });
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -69,6 +69,7 @@ export function EstimateUniversalSearchItem(
|
|||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
active={modifiers.active}
|
||||||
text={
|
text={
|
||||||
<div>
|
<div>
|
||||||
<div>{item.text}</div>
|
<div>{item.text}</div>
|
||||||
@@ -91,13 +92,19 @@ export function EstimateUniversalSearchItem(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transformes the estimates to search items.
|
||||||
|
*/
|
||||||
const transformEstimatesToSearch = (estimate) => ({
|
const transformEstimatesToSearch = (estimate) => ({
|
||||||
|
id: estimate.id,
|
||||||
text: estimate.customer.display_name,
|
text: estimate.customer.display_name,
|
||||||
label: estimate.formatted_balance,
|
label: estimate.formatted_balance,
|
||||||
reference: estimate,
|
reference: estimate,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estimate resource universal search bind configure.
|
||||||
|
*/
|
||||||
export const universalSearchEstimateBind = () => ({
|
export const universalSearchEstimateBind = () => ({
|
||||||
resourceType: RESOURCES_TYPES.ESTIMATE,
|
resourceType: RESOURCES_TYPES.ESTIMATE,
|
||||||
optionItemLabel: intl.get('estimates'),
|
optionItemLabel: intl.get('estimates'),
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ function ReceiptUniversalSearchSelectComponent({
|
|||||||
openDrawer,
|
openDrawer,
|
||||||
}) {
|
}) {
|
||||||
if (resourceType === RESOURCES_TYPES.RECEIPT) {
|
if (resourceType === RESOURCES_TYPES.RECEIPT) {
|
||||||
openDrawer('receipt-drawer', { estimateId: resourceId });
|
openDrawer('receipt-detail-drawer', { receiptId: resourceId });
|
||||||
|
onAction && onAction();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -84,6 +85,7 @@ export function ReceiptUniversalSearchItem(
|
|||||||
* Transformes receipt resource item to search item.
|
* Transformes receipt resource item to search item.
|
||||||
*/
|
*/
|
||||||
const transformReceiptsToSearch = (receipt) => ({
|
const transformReceiptsToSearch = (receipt) => ({
|
||||||
|
id: receipt.id,
|
||||||
text: receipt.customer.display_name,
|
text: receipt.customer.display_name,
|
||||||
label: receipt.formatted_amount,
|
label: receipt.formatted_amount,
|
||||||
reference: receipt,
|
reference: receipt,
|
||||||
|
|||||||
@@ -1211,5 +1211,6 @@
|
|||||||
"receipt_preview.dialog.title":"Receipt PDF Preview",
|
"receipt_preview.dialog.title":"Receipt PDF Preview",
|
||||||
"edit_contact":"Edit {name}",
|
"edit_contact":"Edit {name}",
|
||||||
"item.sell_description": "Sell description",
|
"item.sell_description": "Sell description",
|
||||||
"item.purchase_description": "Purchase description"
|
"item.purchase_description": "Purchase description",
|
||||||
|
"closed_date":"Closed date"
|
||||||
}
|
}
|
||||||
@@ -265,3 +265,12 @@ html[lang^="ar"] {
|
|||||||
background: rgba(0, 10, 30, 0.05);
|
background: rgba(0, 10, 30, 0.05);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.big-number {
|
||||||
|
font-size: 28px;
|
||||||
|
color: #c06361;
|
||||||
|
margin: 6px 0;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -337,3 +337,27 @@
|
|||||||
will-change: auto !important;
|
will-change: auto !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.table-constrant {
|
||||||
|
.table {
|
||||||
|
.thead .th {
|
||||||
|
background: transparent;
|
||||||
|
color: #222222;
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
border-top: 1px solid #000000;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tbody .tr .td {
|
||||||
|
background: transparent;
|
||||||
|
padding: 0.5rem 0.5rem;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tbody .tr:last-child .td {
|
||||||
|
border-bottom: 1px solid #d2dce2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
||||||
&:not(:first-of-type){
|
&:not(:first-of-type){
|
||||||
margin-top: 10px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__label{
|
&__label{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
@import '../Base.scss';
|
||||||
|
|
||||||
.bp3-drawer {
|
.bp3-drawer {
|
||||||
|
|
||||||
|
|
||||||
.bp3-drawer-header {
|
.bp3-drawer-header {
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
background-color: #FFF;
|
background-color: #FFF;
|
||||||
@@ -15,3 +15,53 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.drawer{
|
||||||
|
&__insider{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1 0 0;
|
||||||
|
background-color: #fbfbfb;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__main-tabs{
|
||||||
|
.bp3-tabs {
|
||||||
|
.bp3-tab-list {
|
||||||
|
position: relative;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: #e1e2e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
> *:not(:last-child) {
|
||||||
|
margin-right: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bp3-large > .bp3-tab {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #555;
|
||||||
|
margin: 0 0.8rem;
|
||||||
|
|
||||||
|
&[aria-selected='true'],
|
||||||
|
&:not([aria-disabled='true']):hover {
|
||||||
|
color: $pt-link-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bp3-tab-panel {
|
||||||
|
margin-top: 0;
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
client/src/style/components/Drawers/BillDrawer.module.scss
Normal file
57
client/src/style/components/Drawers/BillDrawer.module.scss
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
.root {}
|
||||||
|
|
||||||
|
.detail_panel {
|
||||||
|
:global .card {
|
||||||
|
padding: 22px 15px;
|
||||||
|
}
|
||||||
|
&_header {}
|
||||||
|
|
||||||
|
&_table {
|
||||||
|
margin-top: 30px;
|
||||||
|
|
||||||
|
:global .bigcapital-datatable {
|
||||||
|
.thead,
|
||||||
|
.tbody {
|
||||||
|
.quantity,
|
||||||
|
.rate,
|
||||||
|
.amount {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_footer {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
:global .total_lines {
|
||||||
|
margin-left: auto;
|
||||||
|
|
||||||
|
&_line {
|
||||||
|
.amount,
|
||||||
|
.title {
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
.amount {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.title{
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.total_line {
|
||||||
|
&_subtotal {
|
||||||
|
border-bottom: 1px solid #000;
|
||||||
|
}
|
||||||
|
&_total {
|
||||||
|
border-bottom: 3px double #000;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
&_dueAmount {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
|
||||||
|
.root{}
|
||||||
|
|
||||||
|
.detail_panel {
|
||||||
|
|
||||||
|
:global .card {
|
||||||
|
padding: 22px 15px;
|
||||||
|
margin: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_table{
|
||||||
|
:global .bigcapital-datatable {
|
||||||
|
margin-top: 30px;
|
||||||
|
|
||||||
|
.thead,
|
||||||
|
.tbody {
|
||||||
|
.quantity,
|
||||||
|
.rate,
|
||||||
|
.amount {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_footer{
|
||||||
|
:global .total_lines {
|
||||||
|
margin-left: auto;
|
||||||
|
|
||||||
|
&_line {
|
||||||
|
.title{
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
.amount,
|
||||||
|
.title {
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
.amount{
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_footer {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total_line{
|
||||||
|
&_subtotal {
|
||||||
|
border-bottom: 1px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_total {
|
||||||
|
border-bottom: 3px double #000;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
&_dueAmount {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_note{
|
||||||
|
|
||||||
|
b{
|
||||||
|
color: #727983;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
.invoice_details {}
|
||||||
|
|
||||||
|
.detail_panel {
|
||||||
|
:global .card {
|
||||||
|
padding: 22px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_header {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_table {
|
||||||
|
:global .bigcapital-datatable {
|
||||||
|
|
||||||
|
.thead,
|
||||||
|
.tbody {
|
||||||
|
|
||||||
|
.quantity,
|
||||||
|
.rate,
|
||||||
|
.amount {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_footer {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
:global .total_lines {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global .total_lines_line {
|
||||||
|
|
||||||
|
.amount,
|
||||||
|
.title {
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.total_line {
|
||||||
|
&_subtotal {
|
||||||
|
border-bottom: 1px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_total {
|
||||||
|
border-bottom: 3px double #000;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_dueAmount {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
.root {}
|
||||||
|
|
||||||
|
.detail_panel {
|
||||||
|
:global .card {
|
||||||
|
padding: 22px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_header {}
|
||||||
|
|
||||||
|
&_table {
|
||||||
|
margin-top: 30px;
|
||||||
|
|
||||||
|
:global .bigcapital-datatable {
|
||||||
|
|
||||||
|
.thead,
|
||||||
|
.tbody {
|
||||||
|
|
||||||
|
.quantity,
|
||||||
|
.rate,
|
||||||
|
.amount {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_footer {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
:global .total_lines {
|
||||||
|
margin-left: auto;
|
||||||
|
|
||||||
|
&_line {
|
||||||
|
|
||||||
|
.amount,
|
||||||
|
.title {
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.total_line {
|
||||||
|
&_subtotal {
|
||||||
|
border-bottom: 1px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_total {
|
||||||
|
border-bottom: 3px double #000;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_dueAmount {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user