mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
re-structure to monorepo.
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { debounce } from 'lodash';
|
||||
import { isUndefined } from 'lodash';
|
||||
|
||||
import { useUniversalSearch } from '@/hooks/query';
|
||||
import { UniversalSearch } from '@/components';
|
||||
|
||||
import { RESOURCES_TYPES } from '@/constants/resourcesTypes';
|
||||
import { compose } from '@/utils';
|
||||
import withUniversalSearchActions from './withUniversalSearchActions';
|
||||
import withUniversalSearch from './withUniversalSearch';
|
||||
|
||||
import DashboardUniversalSearchItemActions from './DashboardUniversalSearchItemActions';
|
||||
import { DashboardUniversalSearchItem } from './components';
|
||||
|
||||
import DashboardUniversalSearchHotkeys from './DashboardUniversalSearchHotkeys';
|
||||
import { useGetUniversalSearchTypeOptions } from './utils';
|
||||
|
||||
/**
|
||||
* Dashboard universal search.
|
||||
*/
|
||||
function DashboardUniversalSearch({
|
||||
// #withUniversalSearchActions
|
||||
setSelectedItemUniversalSearch,
|
||||
|
||||
// #withUniversalSearch
|
||||
globalSearchShow,
|
||||
closeGlobalSearch,
|
||||
defaultUniversalResourceType,
|
||||
}) {
|
||||
const searchTypeOptions = useGetUniversalSearchTypeOptions();
|
||||
|
||||
// Search keyword.
|
||||
const [searchKeyword, setSearchKeyword] = React.useState('');
|
||||
|
||||
// Default search type.
|
||||
const [defaultSearchType, setDefaultSearchType] = React.useState(
|
||||
defaultUniversalResourceType || RESOURCES_TYPES.CUSTOMR,
|
||||
);
|
||||
// Search type.
|
||||
const [searchType, setSearchType] = React.useState(defaultSearchType);
|
||||
|
||||
// Sync default search type with default universal resource type.
|
||||
React.useEffect(() => {
|
||||
if (
|
||||
!isUndefined(defaultUniversalResourceType) &&
|
||||
defaultSearchType !== defaultUniversalResourceType
|
||||
) {
|
||||
setSearchType(defaultUniversalResourceType);
|
||||
setDefaultSearchType(defaultUniversalResourceType);
|
||||
}
|
||||
}, [defaultSearchType, defaultUniversalResourceType]);
|
||||
|
||||
// Fetch accounts list according to the given custom view id.
|
||||
const {
|
||||
data,
|
||||
remove,
|
||||
isFetching: isSearchFetching,
|
||||
isLoading: isSearchLoading,
|
||||
refetch,
|
||||
} = useUniversalSearch(searchType, searchKeyword, {
|
||||
keepPreviousData: true,
|
||||
enabled: false,
|
||||
});
|
||||
|
||||
// Handle query change.
|
||||
const handleQueryChange = (query) => {
|
||||
setSearchKeyword(query);
|
||||
};
|
||||
// Handle search type change.
|
||||
const handleSearchTypeChange = (type) => {
|
||||
remove();
|
||||
setSearchType(type.key);
|
||||
};
|
||||
// Handle overlay of universal search close.
|
||||
const handleClose = () => {
|
||||
closeGlobalSearch();
|
||||
};
|
||||
// Handle universal search item select.
|
||||
const handleItemSelect = (item) => {
|
||||
setSelectedItemUniversalSearch(searchType, item.id);
|
||||
closeGlobalSearch();
|
||||
setSearchKeyword('');
|
||||
};
|
||||
const debounceFetch = React.useRef(
|
||||
debounce(() => {
|
||||
refetch();
|
||||
}, 200),
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (searchKeyword && searchType) {
|
||||
debounceFetch.current();
|
||||
}
|
||||
}, [searchKeyword, searchType]);
|
||||
|
||||
// Handles the overlay once be closed.
|
||||
const handleOverlayClosed = () => {
|
||||
setSearchKeyword('');
|
||||
};
|
||||
|
||||
if (searchTypeOptions.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="dashboard__universal-search">
|
||||
<UniversalSearch
|
||||
isOpen={globalSearchShow}
|
||||
isLoading={isSearchFetching}
|
||||
items={data}
|
||||
overlayProps={{
|
||||
onClose: handleClose,
|
||||
onClosed: handleOverlayClosed,
|
||||
}}
|
||||
searchResource={searchType}
|
||||
onQueryChange={handleQueryChange}
|
||||
onSearchTypeChange={handleSearchTypeChange}
|
||||
onItemSelect={handleItemSelect}
|
||||
itemRenderer={DashboardUniversalSearchItem}
|
||||
query={searchKeyword}
|
||||
searchTypeOptions={searchTypeOptions}
|
||||
/>
|
||||
<DashboardUniversalSearchItemActions />
|
||||
<DashboardUniversalSearchHotkeys />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withUniversalSearchActions,
|
||||
withUniversalSearch(({ globalSearchShow, defaultUniversalResourceType }) => ({
|
||||
globalSearchShow,
|
||||
defaultUniversalResourceType,
|
||||
})),
|
||||
)(DashboardUniversalSearch);
|
||||
@@ -0,0 +1,31 @@
|
||||
// @ts-nocheck
|
||||
import { universalSearchInvoiceBind } from '../Sales/Invoices/InvoiceUniversalSearch';
|
||||
import { universalSearchReceiptBind } from '../Sales/Receipts/ReceiptUniversalSearch';
|
||||
import { universalSearchBillBind } from '../Purchases/Bills/BillUniversalSearch';
|
||||
import { universalSearchEstimateBind } from '../Sales/Estimates/EstimatesLanding/EstimateUniversalSearch';
|
||||
import { universalSearchPaymentReceiveBind } from '../Sales/PaymentReceives/PaymentReceiveUniversalSearch';
|
||||
import { universalSearchPaymentMadeBind } from '../Purchases/PaymentMades/PaymentMadeUniversalSearch';
|
||||
import { universalSearchItemBind } from '../Items/ItemsUniversalSearch';
|
||||
import { universalSearchCustomerBind } from '../Customers/CustomersUniversalSearch';
|
||||
import { universalSearchJournalBind } from '../Accounting/ManualJournalUniversalSearch';
|
||||
import { universalSearchAccountBind } from '../Accounts/AccountUniversalSearch';
|
||||
import { universalSearchVendorBind } from '../Vendors/VendorsUniversalSearch';
|
||||
import { universalSearchCreditNoteBind } from '../Sales/CreditNotes/CreditNoteUniversalSearch';
|
||||
import { universalSearchVendorCreditBind } from '../Purchases/CreditNotes/VendorCreditIUniversalSearchBind';
|
||||
|
||||
// Universal search binds.
|
||||
export const universalSearchBinds = [
|
||||
universalSearchItemBind,
|
||||
universalSearchAccountBind,
|
||||
universalSearchInvoiceBind,
|
||||
universalSearchReceiptBind,
|
||||
universalSearchEstimateBind,
|
||||
universalSearchBillBind,
|
||||
universalSearchPaymentReceiveBind,
|
||||
universalSearchPaymentMadeBind,
|
||||
universalSearchCustomerBind,
|
||||
universalSearchVendorBind,
|
||||
universalSearchJournalBind,
|
||||
universalSearchCreditNoteBind,
|
||||
universalSearchVendorCreditBind,
|
||||
];
|
||||
@@ -0,0 +1,22 @@
|
||||
// @ts-nocheck
|
||||
import * as R from 'ramda';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
|
||||
import withUniversalSearchActions from './withUniversalSearchActions';
|
||||
|
||||
/**
|
||||
* Universal search hotkey.
|
||||
*/
|
||||
function DashboardUniversalSearchHotkey({
|
||||
openGlobalSearch,
|
||||
}) {
|
||||
useHotkeys('shift+p', (event, handle) => {
|
||||
openGlobalSearch();
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default R.compose(
|
||||
withUniversalSearchActions
|
||||
)(DashboardUniversalSearchHotkey);
|
||||
@@ -0,0 +1,44 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import * as R from 'ramda';
|
||||
|
||||
import withUniversalSearch from './withUniversalSearch';
|
||||
|
||||
import { getUniversalSearchItemsActions } from './utils';
|
||||
import withUniversalSearchActions from './withUniversalSearchActions';
|
||||
|
||||
/**
|
||||
* Universal search selected item action based on each resource type.
|
||||
*/
|
||||
function DashboardUniversalSearchItemActions({
|
||||
searchSelectedResourceType,
|
||||
searchSelectedResourceId,
|
||||
|
||||
// #with
|
||||
resetSelectedItemUniversalSearch,
|
||||
}) {
|
||||
const components = getUniversalSearchItemsActions();
|
||||
|
||||
// Handle action execuation.
|
||||
const handleActionExec = React.useCallback(() => {
|
||||
resetSelectedItemUniversalSearch();
|
||||
}, [resetSelectedItemUniversalSearch]);
|
||||
|
||||
return components.map((COMPONENT) => (
|
||||
<COMPONENT
|
||||
resourceId={searchSelectedResourceId}
|
||||
resourceType={searchSelectedResourceType}
|
||||
onAction={handleActionExec}
|
||||
/>
|
||||
));
|
||||
}
|
||||
|
||||
export default R.compose(
|
||||
withUniversalSearch(
|
||||
({ searchSelectedResourceType, searchSelectedResourceId }) => ({
|
||||
searchSelectedResourceType,
|
||||
searchSelectedResourceId,
|
||||
}),
|
||||
),
|
||||
withUniversalSearchActions,
|
||||
)(DashboardUniversalSearchItemActions);
|
||||
@@ -0,0 +1,45 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { MenuItem } from '@blueprintjs/core';
|
||||
|
||||
import { highlightText } from '@/utils';
|
||||
import { getUniversalSearchBind } from './utils';
|
||||
|
||||
/**
|
||||
* Default univesal search item component.
|
||||
*/
|
||||
function UniversalSearchItemDetail(item, { handleClick, modifiers, query }) {
|
||||
return (
|
||||
<MenuItem
|
||||
active={modifiers.active}
|
||||
disabled={modifiers.disabled}
|
||||
text={
|
||||
<div>
|
||||
<div>{highlightText(item.text, query)}</div>
|
||||
|
||||
{item.subText && (
|
||||
<span class="bp3-text-muted">
|
||||
{highlightText(item.subText, query)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
label={item.label ? highlightText(item.label, query) : ''}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} props
|
||||
* @param {*} actions
|
||||
* @returns
|
||||
*/
|
||||
export const DashboardUniversalSearchItem = (props, actions) => {
|
||||
const itemRenderer = getUniversalSearchBind(props._type, 'itemRenderer');
|
||||
|
||||
return typeof itemRenderer !== 'undefined'
|
||||
? itemRenderer(props, actions)
|
||||
: UniversalSearchItemDetail(props, actions);
|
||||
};
|
||||
55
packages/webapp/src/containers/UniversalSearch/utils.tsx
Normal file
55
packages/webapp/src/containers/UniversalSearch/utils.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
// @ts-nocheck
|
||||
import { get } from 'lodash';
|
||||
import * as R from 'ramda';
|
||||
import React from 'react';
|
||||
|
||||
import { universalSearchBinds } from './DashboardUniversalSearchBinds';
|
||||
import { useAbilitiesFilter } from '@/hooks/utils';
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
export const getUniversalSearchBinds = () => {
|
||||
return universalSearchBinds.map((binder) => binder());
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} resourceType
|
||||
* @param {*} key
|
||||
* @returns
|
||||
*/
|
||||
export const getUniversalSearchBind = (resourceType, key) => {
|
||||
const resourceConfig = getUniversalSearchBinds().find(
|
||||
(meta) => meta.resourceType === resourceType,
|
||||
);
|
||||
return key ? get(resourceConfig, key) : resourceConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve universal search type options.
|
||||
*/
|
||||
export const useGetUniversalSearchTypeOptions = () => {
|
||||
const abilityFilter = useAbilitiesFilter();
|
||||
|
||||
const momerizedBinds = React.useMemo(() => {
|
||||
const filteredBinds = R.compose(abilityFilter, getUniversalSearchBinds)();
|
||||
|
||||
return filteredBinds.map((bind) => ({
|
||||
key: bind.resourceType,
|
||||
label: bind.optionItemLabel,
|
||||
}));
|
||||
}, [abilityFilter]);
|
||||
|
||||
return momerizedBinds;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve universal search types actions.
|
||||
*/
|
||||
export const getUniversalSearchItemsActions = () => {
|
||||
return getUniversalSearchBinds()
|
||||
.filter((bind) => bind.selectItemAction)
|
||||
.map((bind) => bind.selectItemAction);
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
// @ts-nocheck
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
export default (mapState) => {
|
||||
const mapStateToProps = (state, props) => {
|
||||
const { globalSearch } = state;
|
||||
|
||||
const mapped = {
|
||||
globalSearchShow: globalSearch.isOpen,
|
||||
defaultUniversalResourceType: globalSearch.defaultResourceType,
|
||||
|
||||
searchSelectedResourceType: globalSearch.selectedItem.resourceType,
|
||||
searchSelectedResourceId: globalSearch.selectedItem.resourceId,
|
||||
};
|
||||
return mapState ? mapState(mapped, state, props) : mapped;
|
||||
};
|
||||
|
||||
return connect(mapStateToProps);
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
// @ts-nocheck
|
||||
import { connect } from 'react-redux';
|
||||
import t from '@/store/types';
|
||||
import {
|
||||
universalSearchResetResourceType,
|
||||
universalSearchSetResourceType,
|
||||
universalSearchSetSelectedItem,
|
||||
universalSearchResetSelectedItem,
|
||||
} from '@/store/search/search.actions';
|
||||
|
||||
export const mapDispatchToProps = (dispatch) => ({
|
||||
openGlobalSearch: () => dispatch({ type: t.OPEN_SEARCH }),
|
||||
closeGlobalSearch: () => dispatch({ type: t.CLOSE_SEARCH }),
|
||||
|
||||
setResourceTypeUniversalSearch: (resourceType) =>
|
||||
dispatch(universalSearchSetResourceType(resourceType)),
|
||||
|
||||
resetResourceTypeUniversalSearch: () =>
|
||||
dispatch(universalSearchResetResourceType()),
|
||||
|
||||
setSelectedItemUniversalSearch: (resourceType, resourceId) =>
|
||||
dispatch(universalSearchSetSelectedItem(resourceType, resourceId)),
|
||||
|
||||
resetSelectedItemUniversalSearch: () =>
|
||||
dispatch(universalSearchResetSelectedItem()),
|
||||
});
|
||||
|
||||
export default connect(null, mapDispatchToProps);
|
||||
Reference in New Issue
Block a user