mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
feat: universal search.
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
import React from 'react';
|
||||
import { MenuItem } from '@blueprintjs/core';
|
||||
|
||||
import { Choose, T, Icon } from 'components';
|
||||
|
||||
import { RESOURCES_TYPES } from "../../../../common/resourcesTypes";
|
||||
import withDrawerActions from "../../../Drawer/withDrawerActions";
|
||||
|
||||
/**
|
||||
* Estimate universal search item select action.
|
||||
*/
|
||||
function EstimateUniversalSearchSelectComponent({
|
||||
// #ownProps
|
||||
resourceType,
|
||||
resourceId,
|
||||
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
}) {
|
||||
if (resourceType === RESOURCES_TYPES.ESTIMATE) {
|
||||
openDrawer('estimate-drawer', { estimateId: resourceId });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export const EstimateUniversalSearchSelect = withDrawerActions(
|
||||
EstimateUniversalSearchSelectComponent,
|
||||
);
|
||||
|
||||
/**
|
||||
* Status accessor.
|
||||
*/
|
||||
export const EstimateStatus = ({ estimate }) => (
|
||||
<Choose>
|
||||
<Choose.When condition={estimate.is_delivered && estimate.is_approved}>
|
||||
<span class="approved">
|
||||
<T id={'approved'} />
|
||||
</span>
|
||||
</Choose.When>
|
||||
<Choose.When condition={estimate.is_delivered && estimate.is_rejected}>
|
||||
<span class="reject">
|
||||
<T id={'rejected'} />
|
||||
</span>
|
||||
</Choose.When>
|
||||
<Choose.When
|
||||
condition={
|
||||
estimate.is_delivered && !estimate.is_rejected && !estimate.is_approved
|
||||
}
|
||||
>
|
||||
<span class="delivered">
|
||||
<T id={'delivered'} />
|
||||
</span>
|
||||
</Choose.When>
|
||||
<Choose.Otherwise>
|
||||
<span class="draft">
|
||||
<T id={'draft'} />
|
||||
</span>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
);
|
||||
|
||||
/**
|
||||
* Estimate universal search item.
|
||||
*/
|
||||
export function EstimateUniversalSearchItem(
|
||||
item,
|
||||
{ handleClick, modifiers, query },
|
||||
) {
|
||||
return (
|
||||
<MenuItem
|
||||
text={
|
||||
<div>
|
||||
<div>{item.text}</div>
|
||||
<span class="bp3-text-muted">
|
||||
{item.reference.estimate_number}{' '}
|
||||
<Icon icon={'caret-right-16'} iconSize={16} />
|
||||
{item.reference.formatted_estimate_date}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
label={
|
||||
<>
|
||||
<div class="amount">{item.reference.formatted_amount}</div>
|
||||
<EstimateStatus estimate={item.reference} />
|
||||
</>
|
||||
}
|
||||
onClick={handleClick}
|
||||
className={'universal-search__item--estimate'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const transformEstimatesToSearch = (estimate) => ({
|
||||
text: estimate.customer.display_name,
|
||||
label: estimate.formatted_balance,
|
||||
reference: estimate,
|
||||
});
|
||||
|
||||
export const universalSearchEstimateBind = () => ({
|
||||
resourceType: RESOURCES_TYPES.ESTIMATE,
|
||||
optionItemLabel: 'Estimates',
|
||||
selectItemAction: EstimateUniversalSearchSelect,
|
||||
itemRenderer: EstimateUniversalSearchItem,
|
||||
itemSelect: transformEstimatesToSearch
|
||||
});
|
||||
@@ -35,7 +35,7 @@ function EstimateActionsBar({
|
||||
setEstimatesTableState,
|
||||
|
||||
// #withEstimates
|
||||
estimatesFilterRoles
|
||||
estimatesFilterRoles,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
@@ -51,20 +51,24 @@ function EstimateActionsBar({
|
||||
const { refresh } = useRefreshEstimates();
|
||||
|
||||
// Handle tab change.
|
||||
const handleTabChange = (customView) => {
|
||||
const handleTabChange = (view) => {
|
||||
setEstimatesTableState({
|
||||
customViewId: customView.id || null,
|
||||
viewSlug: view ? view.slug : null,
|
||||
});
|
||||
};
|
||||
|
||||
// Handle click a refresh sale estimates
|
||||
const handleRefreshBtnClick = () => { refresh(); };
|
||||
const handleRefreshBtnClick = () => {
|
||||
refresh();
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<DashboardActionViewsList
|
||||
resourceName={'estimates'}
|
||||
allMenuItem={true}
|
||||
allMenuItemText={<T id={'all'} />}
|
||||
views={estimatesViews}
|
||||
onChange={handleTabChange}
|
||||
/>
|
||||
|
||||
121
client/src/containers/Sales/Invoices/InvoiceUniversalSearch.js
Normal file
121
client/src/containers/Sales/Invoices/InvoiceUniversalSearch.js
Normal file
@@ -0,0 +1,121 @@
|
||||
import React from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
import { MenuItem } from '@blueprintjs/core';
|
||||
|
||||
import { T, Choose, Icon } from 'components';
|
||||
|
||||
import { highlightText } from 'utils';
|
||||
|
||||
import { RESOURCES_TYPES } from 'common/resourcesTypes';
|
||||
import withDrawerActions from '../../Drawer/withDrawerActions';
|
||||
|
||||
/**
|
||||
* Universal search invoice item select action.
|
||||
*/
|
||||
function InvoiceUniversalSearchSelectComponent({
|
||||
// #ownProps
|
||||
resourceType,
|
||||
resourceId,
|
||||
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
}) {
|
||||
if (resourceType === RESOURCES_TYPES.INVOICE) {
|
||||
openDrawer('invoice-drawer', { invoiceId: resourceId });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export const InvoiceUniversalSearchSelect = withDrawerActions(
|
||||
InvoiceUniversalSearchSelectComponent,
|
||||
);
|
||||
|
||||
/**
|
||||
* Invoice status.
|
||||
*/
|
||||
function InvoiceStatus(customer) {
|
||||
return (
|
||||
<Choose>
|
||||
<Choose.When condition={customer.is_fully_paid && customer.is_delivered}>
|
||||
<span class="status status-success">
|
||||
<T id={'paid'} />
|
||||
</span>
|
||||
</Choose.When>
|
||||
|
||||
<Choose.When condition={customer.is_delivered}>
|
||||
<Choose>
|
||||
<Choose.When condition={customer.is_overdue}>
|
||||
<span className={'status status-warning'}>
|
||||
{intl.get('overdue_by', { overdue: customer.overdue_days })}
|
||||
</span>
|
||||
</Choose.When>
|
||||
<Choose.Otherwise>
|
||||
<span className={'status status-warning'}>
|
||||
{intl.get('due_in', { due: customer.remaining_days })}
|
||||
</span>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</Choose.When>
|
||||
<Choose.Otherwise>
|
||||
<span class="status status--gray">
|
||||
<T id={'draft'} />
|
||||
</span>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Universal search invoice item.
|
||||
*/
|
||||
export function InvoiceUniversalSearchItem(
|
||||
item,
|
||||
{ handleClick, modifiers, query },
|
||||
) {
|
||||
return (
|
||||
<MenuItem
|
||||
active={modifiers.active}
|
||||
text={
|
||||
<div>
|
||||
<div>{highlightText(item.text, query)}</div>
|
||||
<span class="bp3-text-muted">
|
||||
{highlightText(item.reference.invoice_no, query)}{' '}
|
||||
<Icon icon={'caret-right-16'} iconSize={16} />
|
||||
{highlightText(item.reference.formatted_invoice_date, query)}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
label={
|
||||
<>
|
||||
<div class="amount">${item.reference.balance}</div>
|
||||
<InvoiceStatus customer={item.reference} />
|
||||
</>
|
||||
}
|
||||
onClick={handleClick}
|
||||
className={'universal-search__item--invoice'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transformes invoices to search.
|
||||
* @param {*} invoice
|
||||
* @returns
|
||||
*/
|
||||
const transformInvoicesToSearch = (invoice) => ({
|
||||
id: invoice.id,
|
||||
text: invoice.customer.display_name,
|
||||
label: invoice.formatted_balance,
|
||||
reference: invoice,
|
||||
});
|
||||
|
||||
/**
|
||||
* Binds universal search invoice configure.
|
||||
*/
|
||||
export const universalSearchInvoiceBind = () => ({
|
||||
resourceType: RESOURCES_TYPES.INVOICE,
|
||||
optionItemLabel: 'Invoices',
|
||||
selectItemAction: InvoiceUniversalSearchSelect,
|
||||
itemRenderer: InvoiceUniversalSearchItem,
|
||||
itemSelect: transformInvoicesToSearch,
|
||||
});
|
||||
@@ -51,8 +51,8 @@ function InvoiceActionsBar({
|
||||
const { refresh } = useRefreshInvoices();
|
||||
|
||||
// Handle views tab change.
|
||||
const handleTabChange = (customView) => {
|
||||
setInvoicesTableState({ customViewId: customView.id || null });
|
||||
const handleTabChange = (view) => {
|
||||
setInvoicesTableState({ viewSlug: view ? view.slug : null });
|
||||
};
|
||||
|
||||
// Handle click a refresh sale invoices
|
||||
@@ -64,6 +64,7 @@ function InvoiceActionsBar({
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<DashboardActionViewsList
|
||||
allMenuItem={true}
|
||||
resourceName={'invoices'}
|
||||
views={invoicesViews}
|
||||
onChange={handleTabChange}
|
||||
|
||||
@@ -210,4 +210,4 @@ export function useInvoicesTableColumns() {
|
||||
],
|
||||
[],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import React from 'react';
|
||||
import { MenuItem } from '@blueprintjs/core';
|
||||
import { RESOURCES_TYPES } from "../../../common/resourcesTypes";
|
||||
import withDrawerActions from "../../Drawer/withDrawerActions";
|
||||
import { highlightText } from 'utils';
|
||||
import { Icon } from 'components';
|
||||
|
||||
/**
|
||||
* Payment receive universal search item select action.
|
||||
*/
|
||||
function PaymentReceiveUniversalSearchSelectComponent({
|
||||
// #ownProps
|
||||
resourceType,
|
||||
resourceId,
|
||||
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
}) {
|
||||
if (resourceType === RESOURCES_TYPES.PAYMENT_RECEIVE) {
|
||||
openDrawer('payment-receive-drawer', { paymentReceiveId: resourceId });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export const PaymentReceiveUniversalSearchSelect = withDrawerActions(
|
||||
PaymentReceiveUniversalSearchSelectComponent,
|
||||
);
|
||||
|
||||
/**
|
||||
* Payment receive universal search item.
|
||||
*/
|
||||
export function PaymentReceiveUniversalSearchItem(
|
||||
item,
|
||||
{ handleClick, modifiers, query },
|
||||
) {
|
||||
return (
|
||||
<MenuItem
|
||||
active={modifiers.active}
|
||||
text={
|
||||
<div>
|
||||
<div>{highlightText(item.text, query)}</div>
|
||||
|
||||
<span class="bp3-text-muted">
|
||||
{highlightText(item.reference.payment_receive_no, query)}{' '}
|
||||
<Icon icon={'caret-right-16'} iconSize={16} />
|
||||
{highlightText(item.reference.formatted_payment_date, query)}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
label={<div class="amount">{item.reference.formatted_amount}</div>}
|
||||
onClick={handleClick}
|
||||
className={'universal-search__item--invoice'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transformes payment receives to search.
|
||||
* @param {*} payment
|
||||
* @returns
|
||||
*/
|
||||
const paymentReceivesToSearch = (payment) => ({
|
||||
text: payment.customer.display_name,
|
||||
subText: payment.formatted_payment_date,
|
||||
label: payment.formatted_amount,
|
||||
reference: payment,
|
||||
});
|
||||
|
||||
/**
|
||||
* Binds universal search payment receive configure.
|
||||
*/
|
||||
export const universalSearchPaymentReceiveBind = () => ({
|
||||
resourceType: RESOURCES_TYPES.PAYMENT_RECEIVE,
|
||||
optionItemLabel: 'Payment receive',
|
||||
selectItemAction: PaymentReceiveUniversalSearchSelect,
|
||||
itemRenderer: PaymentReceiveUniversalSearchItem,
|
||||
itemSelect: paymentReceivesToSearch,
|
||||
});
|
||||
100
client/src/containers/Sales/Receipts/ReceiptUniversalSearch.js
Normal file
100
client/src/containers/Sales/Receipts/ReceiptUniversalSearch.js
Normal file
@@ -0,0 +1,100 @@
|
||||
|
||||
import React from 'react';
|
||||
import { MenuItem } from '@blueprintjs/core';
|
||||
|
||||
import { Icon, Choose, T } from 'components';
|
||||
|
||||
import { RESOURCES_TYPES } from "../../../common/resourcesTypes";
|
||||
import withDrawerActions from "../../Drawer/withDrawerActions";
|
||||
|
||||
|
||||
/**
|
||||
* Receipt universal search item select action.
|
||||
*/
|
||||
function ReceiptUniversalSearchSelectComponent({
|
||||
// #ownProps
|
||||
resourceType,
|
||||
resourceId,
|
||||
onAction,
|
||||
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
}) {
|
||||
if (resourceType === RESOURCES_TYPES.RECEIPT) {
|
||||
openDrawer('receipt-drawer', { estimateId: resourceId });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export const ReceiptUniversalSearchSelect = withDrawerActions(
|
||||
ReceiptUniversalSearchSelectComponent,
|
||||
);
|
||||
|
||||
/**
|
||||
* Status accessor.
|
||||
*/
|
||||
function ReceiptStatus({ receipt }) {
|
||||
return (
|
||||
<Choose>
|
||||
<Choose.When condition={receipt.is_closed}>
|
||||
<span class="closed"><T id={'closed'} /></span>
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<span class="draft"><T id={'draft'} /></span>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receipt universal search item.
|
||||
*/
|
||||
export function ReceiptUniversalSearchItem(
|
||||
item,
|
||||
{ handleClick, modifiers, query },
|
||||
) {
|
||||
return (
|
||||
<MenuItem
|
||||
active={modifiers.active}
|
||||
text={
|
||||
<div>
|
||||
<div>{item.text}</div>
|
||||
<span class="bp3-text-muted">
|
||||
{item.reference.receipt_number}{' '}
|
||||
<Icon icon={'caret-right-16'} iconSize={16} />
|
||||
{item.reference.formatted_receipt_date}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
label={
|
||||
<>
|
||||
<div class="amount">${item.reference.amount}</div>
|
||||
<ReceiptStatus receipt={item.reference} />
|
||||
</>
|
||||
}
|
||||
onClick={handleClick}
|
||||
className={'universal-search__item--receipt'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transformes receipt resource item to search item.
|
||||
*/
|
||||
const transformReceiptsToSearch = (receipt) => ({
|
||||
text: receipt.customer.display_name,
|
||||
label: receipt.formatted_amount,
|
||||
reference: receipt,
|
||||
});
|
||||
|
||||
/**
|
||||
* Receipt universal search bind configuration.
|
||||
*/
|
||||
export const universalSearchReceiptBind = () => ({
|
||||
resourceType: RESOURCES_TYPES.RECEIPT,
|
||||
optionItemLabel: 'Receipts',
|
||||
selectItemAction: ReceiptUniversalSearchSelect,
|
||||
itemRenderer: ReceiptUniversalSearchItem,
|
||||
itemSelect: transformReceiptsToSearch,
|
||||
});
|
||||
@@ -49,22 +49,24 @@ function ReceiptActionsBar({
|
||||
// Sale receipt refresh action.
|
||||
const { refresh } = useRefreshReceipts();
|
||||
|
||||
const handleTabChange = (customView) => {
|
||||
const handleTabChange = (view) => {
|
||||
setReceiptsTableState({
|
||||
customViewId: customView.id || null,
|
||||
viewSlug: view ? view.slug : null,
|
||||
});
|
||||
};
|
||||
|
||||
// Handle click a refresh sale estimates
|
||||
const handleRefreshBtnClick = () => { refresh(); };
|
||||
|
||||
console.log(receiptsFilterConditions, fields, 'XXX');
|
||||
const handleRefreshBtnClick = () => {
|
||||
refresh();
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
<DashboardActionViewsList
|
||||
resourceName={'receipts'}
|
||||
allMenuItem={true}
|
||||
allMenuItemText={<T id={'all'} />}
|
||||
views={receiptsViews}
|
||||
onChange={handleTabChange}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user