mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 21:00:31 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
49
client/src/components/CategoriesSelectList.js
Normal file
49
client/src/components/CategoriesSelectList.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { ListSelect } from 'components';
|
||||
import { MenuItem } from '@blueprintjs/core';
|
||||
|
||||
export default function CategoriesSelectList({
|
||||
categoriesList,
|
||||
selecetedCategoryId,
|
||||
defaultSelectText = <T id={'select_category'} />,
|
||||
onCategorySelected,
|
||||
...restProps
|
||||
}) {
|
||||
|
||||
// Filter Items Category
|
||||
const filterItemCategory = (query, item, _index, exactMatch) => {
|
||||
const normalizedTitle = item.name.toLowerCase();
|
||||
const normalizedQuery = query.toLowerCase();
|
||||
if (exactMatch) {
|
||||
return normalizedTitle === normalizedQuery;
|
||||
} else {
|
||||
return `${item.code} ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
|
||||
}
|
||||
};
|
||||
|
||||
const handleItemCategorySelected = useCallback(
|
||||
(ItemCategory) => onCategorySelected && onCategorySelected(ItemCategory),
|
||||
[],
|
||||
);
|
||||
const categoryItem = useCallback(
|
||||
(item, { handleClick }) => (
|
||||
<MenuItem key={item.id} text={item.name} onClick={handleClick} />
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<ListSelect
|
||||
items={categoriesList}
|
||||
selectedItemProp={'id'}
|
||||
selectedItem={selecetedCategoryId}
|
||||
labelProp={'name'}
|
||||
defaultText={defaultSelectText}
|
||||
onItemSelect={handleItemCategorySelected}
|
||||
itemPredicate={filterItemCategory}
|
||||
itemRenderer={categoryItem}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -25,6 +25,8 @@ import Dialog from './Dialog/Dialog';
|
||||
import DialogContent from './Dialog/DialogContent';
|
||||
import DialogSuspense from './Dialog/DialogSuspense';
|
||||
import InputPrependButton from './Forms/InputPrependButton';
|
||||
import CategoriesSelectList from './CategoriesSelectList';
|
||||
|
||||
const Hint = FieldHint;
|
||||
|
||||
export {
|
||||
@@ -55,5 +57,6 @@ export {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogSuspense,
|
||||
InputPrependButton
|
||||
};
|
||||
InputPrependButton,
|
||||
CategoriesSelectList
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@ function Customer({
|
||||
formik,
|
||||
//#withCustomersActions
|
||||
requestFetchCustomers,
|
||||
requestFetchCustomer,
|
||||
}) {
|
||||
const { id } = useParams();
|
||||
const history = useHistory();
|
||||
@@ -26,11 +27,12 @@ function Customer({
|
||||
requestFetchCustomers({}),
|
||||
);
|
||||
// Handle fetch customer details.
|
||||
const fetchCustomer= useQuery(['customer', id], () =>
|
||||
requestFetchCustomers(),
|
||||
{ enabled: !!id },
|
||||
const fetchCustomer = useQuery(
|
||||
['customer', id],
|
||||
(key, customerId) => requestFetchCustomer(customerId),
|
||||
{ enabled: id && id },
|
||||
);
|
||||
|
||||
|
||||
const handleFormSubmit = useCallback(
|
||||
(payload) => {
|
||||
payload.redirect && history.push('/customers');
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
fetchCustomers,
|
||||
fetchCustomer,
|
||||
submitCustomer,
|
||||
editCustomer,
|
||||
deleteCustomer,
|
||||
deleteBulkCustomers
|
||||
deleteBulkCustomers,
|
||||
} from 'store/customers/customers.actions';
|
||||
import t from 'store/types';
|
||||
|
||||
export const mapDispatchToProps = (dispatch) => ({
|
||||
requestFetchCustomers: (query) => dispatch(fetchCustomers({ query })),
|
||||
requestDeleteCustomer: (id) => dispatch(deleteCustomer({ id })),
|
||||
requestDeleteBulkCustomers:(ids)=>dispatch(deleteBulkCustomers({ids})),
|
||||
requestDeleteBulkCustomers: (ids) => dispatch(deleteBulkCustomers({ ids })),
|
||||
requestSubmitCustomer: (form) => dispatch(submitCustomer({ form })),
|
||||
requestEditCustomer: (id, form) => dispatch(editCustomer({ id, form })),
|
||||
|
||||
requestFetchCustomer: (id) => dispatch(fetchCustomer({ id })),
|
||||
addCustomersTableQueries: (queries) =>
|
||||
dispatch({
|
||||
type: t.CUSTOMERS_TABLE_QUERIES_ADD,
|
||||
|
||||
@@ -50,6 +50,7 @@ const ItemsCategoryList = ({
|
||||
(category) => (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={formatMessage({ id: 'edit_category' })}
|
||||
onClick={handelEditCategory(category)}
|
||||
/>
|
||||
|
||||
@@ -23,7 +23,11 @@ import ErrorMessage from 'components/ErrorMessage';
|
||||
import Icon from 'components/Icon';
|
||||
import MoneyInputGroup from 'components/MoneyInputGroup';
|
||||
import Dragzone from 'components/Dragzone';
|
||||
import { ListSelect, AccountsSelectList, If } from 'components';
|
||||
import {
|
||||
ListSelect,
|
||||
AccountsSelectList,
|
||||
CategoriesSelectList,
|
||||
} from 'components';
|
||||
|
||||
import withItemsActions from 'containers/Items/withItemsActions';
|
||||
import withItemCategories from 'containers/Items/withItemCategories';
|
||||
@@ -170,7 +174,7 @@ const ItemForm = ({
|
||||
},
|
||||
onSubmit: (values, { setSubmitting, resetForm, setErrors }) => {
|
||||
const saveItem = (mediaIds) => {
|
||||
const formValues = { ...values, media_ids: mediaIds };
|
||||
const formValues = { ...values };
|
||||
if (itemDetail && itemDetail.id) {
|
||||
requestEditItem(itemDetail.id, formValues)
|
||||
.then((response) => {
|
||||
@@ -222,29 +226,6 @@ const ItemForm = ({
|
||||
},
|
||||
});
|
||||
|
||||
const accountItem = useCallback(
|
||||
(item, { handleClick }) => (
|
||||
<MenuItem
|
||||
key={item.id}
|
||||
text={item.name}
|
||||
label={item.code}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
// Filter Account Items
|
||||
const filterAccounts = (query, item, _index, exactMatch) => {
|
||||
const normalizedTitle = item.name.toLowerCase();
|
||||
const normalizedQuery = query.toLowerCase();
|
||||
if (exactMatch) {
|
||||
return normalizedTitle === normalizedQuery;
|
||||
} else {
|
||||
return `${item.code} ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
|
||||
}
|
||||
};
|
||||
|
||||
const onItemAccountSelect = useCallback(
|
||||
(filedName) => {
|
||||
return (account) => {
|
||||
@@ -254,13 +235,6 @@ const ItemForm = ({
|
||||
[setFieldValue],
|
||||
);
|
||||
|
||||
const categoryItem = useCallback(
|
||||
(item, { handleClick }) => (
|
||||
<MenuItem key={item.id} text={item.name} onClick={handleClick} />
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
const requiredSpan = useMemo(() => <span class="required">*</span>, []);
|
||||
const infoIcon = useMemo(() => <Icon icon="info-circle" iconSize={12} />, []);
|
||||
|
||||
@@ -374,17 +348,11 @@ const ItemForm = ({
|
||||
Classes.FILL,
|
||||
)}
|
||||
>
|
||||
<ListSelect
|
||||
items={categoriesList}
|
||||
noResults={<MenuItem disabled={true} text="No results." />}
|
||||
itemRenderer={categoryItem}
|
||||
itemPredicate={filterAccounts}
|
||||
<CategoriesSelectList
|
||||
categoriesList={categoriesList}
|
||||
selecetedCategoryId={values.category_id}
|
||||
onCategorySelected={onItemAccountSelect('category_id')}
|
||||
popoverProps={{ minimal: true }}
|
||||
onItemSelect={onItemAccountSelect('category_id')}
|
||||
selectedItem={values.customer_id}
|
||||
selectedItemProp={'id'}
|
||||
defaultText={<T id={'select_category'} />}
|
||||
labelProp={'name'}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
|
||||
@@ -40,11 +40,8 @@ const ItemFormContainer = ({
|
||||
const fetchItemDetail = useQuery(
|
||||
['item', id],
|
||||
(key, _id) => requestFetchItem(_id),
|
||||
{
|
||||
enabled: !!id,
|
||||
},
|
||||
{ enabled: id && id },
|
||||
);
|
||||
|
||||
const handleFormSubmit = useCallback(
|
||||
(payload) => {
|
||||
payload.redirect && history.push('/items');
|
||||
|
||||
@@ -9,9 +9,7 @@ import {
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import DataTable from 'components/DataTable';
|
||||
import Icon from 'components/Icon';
|
||||
import Money from 'components/Money';
|
||||
import { Icon, DataTable, Money, If, Choose } from 'components';
|
||||
|
||||
import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import withItems from 'containers/Items/withItems';
|
||||
@@ -56,14 +54,19 @@ const ItemsDataTable = ({
|
||||
const actionMenuList = useCallback(
|
||||
(item) => (
|
||||
<Menu>
|
||||
<MenuItem text={formatMessage({ id: 'view_details' })} />
|
||||
<MenuItem
|
||||
icon={<Icon icon="reader-18" />}
|
||||
text={formatMessage({ id: 'view_details' })}
|
||||
/>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={formatMessage({ id: 'edit_item' })}
|
||||
onClick={handleEditItem(item)}
|
||||
/>
|
||||
<MenuItem
|
||||
text={formatMessage({ id: 'delete_item' })}
|
||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||
onClick={handleDeleteItem(item)}
|
||||
intent={Intent.DANGER}
|
||||
/>
|
||||
@@ -72,9 +75,12 @@ const ItemsDataTable = ({
|
||||
[handleEditItem, handleDeleteItem, formatMessage],
|
||||
);
|
||||
|
||||
const handleRowContextMenu = useCallback((cell) => {
|
||||
return actionMenuList(cell.row.original);
|
||||
}, [actionMenuList]);
|
||||
const handleRowContextMenu = useCallback(
|
||||
(cell) => {
|
||||
return actionMenuList(cell.row.original);
|
||||
},
|
||||
[actionMenuList],
|
||||
);
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
@@ -155,7 +161,6 @@ const ItemsDataTable = ({
|
||||
},
|
||||
[onSelectedRowsChange],
|
||||
);
|
||||
|
||||
return (
|
||||
<LoadingIndicator loading={loading} mount={false}>
|
||||
<DataTable
|
||||
|
||||
@@ -211,6 +211,8 @@ export default {
|
||||
once_delete_this_item_you_will_able_to_restore_it: `Once you delete this item, you won\'t be able to restore the item later. Are you sure you want to delete ?<br /><br />If you're not sure, you can inactivate it instead.`,
|
||||
the_item_has_been_successfully_deleted:
|
||||
'The item has been successfully deleted.',
|
||||
the_item_has_been_successfully_edited:
|
||||
'The item #{number} has been successfully edited.',
|
||||
the_item_category_has_been_successfully_created:
|
||||
'The item category has been successfully created.',
|
||||
the_item_category_has_been_successfully_edited:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { resolve } from 'p-progress';
|
||||
import ApiService from 'services/ApiService';
|
||||
import t from 'store/types';
|
||||
|
||||
@@ -52,14 +53,13 @@ export const fetchCustomers = ({ query }) => {
|
||||
ApiService.get(`customers`, { params: { ...pageQuery, ...query } })
|
||||
.then((response) => {
|
||||
dispatch({
|
||||
type: t.CUSTOMER_SET,
|
||||
type: t.CUSTOMERS_ITEMS_SET,
|
||||
customers: response.data.customers,
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: t.CUSTOMERS_PAGE_SET,
|
||||
customers: response.data.customers,
|
||||
customViewId: response.data.customers.customViewId,
|
||||
customViewId: response.data.customers?.viewMeta?.customViewId || -1,
|
||||
paginationMeta: response.data.pagination,
|
||||
});
|
||||
dispatch({
|
||||
@@ -74,6 +74,26 @@ export const fetchCustomers = ({ query }) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchCustomer = ({ id }) => {
|
||||
return (dispatch) =>
|
||||
new Promise((resolve, reject) => {
|
||||
ApiService.get(`customers/${id}`)
|
||||
.then((response) => {
|
||||
dispatch({
|
||||
type: t.CUSTOMER_SET,
|
||||
payload: {
|
||||
id,
|
||||
customer: response.data.contact,
|
||||
},
|
||||
});
|
||||
resolve(response);
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteCustomer = ({ id }) => {
|
||||
return (dispatch) =>
|
||||
new Promise((resolve, reject) => {
|
||||
|
||||
@@ -11,7 +11,7 @@ const initialState = {
|
||||
};
|
||||
|
||||
const customersReducer = createReducer(initialState, {
|
||||
[t.CUSTOMER_SET]: (state, action) => {
|
||||
[t.CUSTOMERS_ITEMS_SET]: (state, action) => {
|
||||
const _customers = {};
|
||||
|
||||
action.customers.forEach((customer) => {
|
||||
@@ -51,6 +51,10 @@ const customersReducer = createReducer(initialState, {
|
||||
});
|
||||
state.items = items;
|
||||
},
|
||||
[t.CUSTOMER_SET]: (state, action) => {
|
||||
const { id, customer } = action.payload;
|
||||
state.items[id] = { ...customer };
|
||||
},
|
||||
});
|
||||
|
||||
export default createTableQueryReducers('customers', customersReducer);
|
||||
|
||||
@@ -27,7 +27,7 @@ export const fetchItems = ({ query }) => {
|
||||
dispatch({
|
||||
type: t.ITEMS_PAGE_SET,
|
||||
items: response.data.items,
|
||||
customViewId: response.data.customViewId,
|
||||
customViewId: response.data?.filter_meta?.view?.custom_view_id,
|
||||
paginationMeta: response.data.pagination,
|
||||
});
|
||||
dispatch({
|
||||
@@ -55,8 +55,12 @@ export const fetchItem = ({ id }) => {
|
||||
.then((response) => {
|
||||
dispatch({
|
||||
type: t.ITEM_SET,
|
||||
item: response.data.item,
|
||||
payload: {
|
||||
id,
|
||||
item: response.data.item,
|
||||
},
|
||||
});
|
||||
resolve(response);
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error);
|
||||
|
||||
@@ -27,6 +27,11 @@ const itemsReducer = createReducer(initialState, {
|
||||
};
|
||||
},
|
||||
|
||||
[t.ITEM_SET]: (state, action) => {
|
||||
const { id, item } = action.payload;
|
||||
state.items[id] = { ...item };
|
||||
},
|
||||
|
||||
[t.ITEMS_PAGE_SET]: (state, action) => {
|
||||
const { items, customViewId, paginationMeta } = action;
|
||||
|
||||
@@ -42,10 +47,10 @@ const itemsReducer = createReducer(initialState, {
|
||||
state.itemsRelation[item.id] = [];
|
||||
}
|
||||
const filteredRelation = state.itemsRelation[item.id].filter(
|
||||
(relation) => (
|
||||
(relation) =>
|
||||
relation.viewId === viewId &&
|
||||
relation.pageNumber === paginationMeta.page
|
||||
));
|
||||
relation.pageNumber === paginationMeta.page,
|
||||
);
|
||||
|
||||
filteredRelation.push({
|
||||
viewId,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
|
||||
|
||||
export default {
|
||||
ITEMS_SET: 'ITEMS_SET',
|
||||
ITEM_SET: 'ITEM_SET',
|
||||
ITEMS_PAGE_SET: 'ITEMS_PAGE_SET',
|
||||
ITEM_DELETE: 'ITEM_DELETE',
|
||||
ITEM_BULK_ACTION_ADD: 'ITEM_BULK_ACTION_ADD',
|
||||
@@ -12,6 +11,5 @@ export default {
|
||||
|
||||
ITEMS_TABLE_LOADING: 'ITEMS_TABLE_LOADING',
|
||||
ITEMS_SET_CURRENT_VIEW: 'ITEMS_SET_CURRENT_VIEW',
|
||||
ITEMS_BULK_DELETE:'ITEMS_BULK_DELETE'
|
||||
|
||||
ITEMS_BULK_DELETE: 'ITEMS_BULK_DELETE',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user