fix bugs in items form.

This commit is contained in:
Ahmed Bouhuolia
2020-04-15 01:29:46 +02:00
parent 26faaddfed
commit cac6620ffe
20 changed files with 378 additions and 129 deletions

View File

@@ -52,7 +52,7 @@ function AccountsDataTable({
openDialog('account-form', { action: 'edit', id: account.id });
}, [openDialog]);
const actionMenuList = account => (
const actionMenuList = useCallback(account => (
<Menu>
<MenuItem text='View Details' />
<MenuDivider />
@@ -66,7 +66,8 @@ function AccountsDataTable({
text='Delete Account'
onClick={() => onDeleteAccount(account)} />
</Menu>
);
), [handleEditAccount, onDeleteAccount, onInactiveAccount]);
const columns = useMemo(() => [
{
id: 'name',
@@ -139,7 +140,7 @@ function AccountsDataTable({
className: 'actions',
width: 50,
}
], []);
], [actionMenuList]);
const selectionColumn = useMemo(() => ({
minWidth: 42,

View File

@@ -9,6 +9,7 @@ import {
HTMLSelect,
Button,
Classes,
Checkbox,
} from '@blueprintjs/core';
import { Row, Col } from 'react-grid-system';
import { Select } from '@blueprintjs/select';
@@ -19,11 +20,15 @@ import {compose} from 'utils';
import ErrorMessage from 'components/ErrorMessage';
import classNames from 'classnames';
import Icon from 'components/Icon';
import ItemCategoryConnect from 'connectors/ItemsCategory.connect';
import MoneyInputGroup from 'components/MoneyInputGroup';
const ItemForm = ({
requestSubmitItem,
accounts,
categories,
categoriesList,
}) => {
const [selectedAccounts, setSelectedAccounts] = useState({});
@@ -35,24 +40,30 @@ const ItemForm = ({
]), []);
const validationSchema = Yup.object().shape({
active: Yup.boolean(),
name: Yup.string().required(),
type: Yup.string().trim().required(),
sku: Yup.string().required(),
cost_price: Yup.number().required(),
sell_price: Yup.number().required(),
cost_price: Yup.number(),
sell_price: Yup.number(),
cost_account_id: Yup.number().required(),
sell_account_id: Yup.number().required(),
inventory_account_id: Yup.number().required(),
category_id: Yup.number().required(),
inventory_account_id: Yup.number().when('type', {
is: (value) => value === 'inventory',
then: Yup.number().required(),
otherwise: Yup.number().nullable(),
}),
category_id: Yup.number().nullable(),
stock: Yup.string() || Yup.boolean()
});
const initialValues = useMemo(() => ({
active: true,
name: '',
type: '',
sku: '',
cost_price: null,
sell_price: null,
cost_price: 0,
sell_price: 0,
cost_account_id: null,
sell_account_id: null,
inventory_account_id: null,
@@ -80,9 +91,10 @@ const ItemForm = ({
});
const {errors, values, touched} = useMemo(() => formik, [formik]);
const accountItem = (item, { handleClick }) => (
const accountItem = useCallback((item, { handleClick }) => (
<MenuItem key={item.id} text={item.name} label={item.code} onClick={handleClick} />
);
), []);
// Filter Account Items
const filterAccounts = (query, account, _index, exactMatch) => {
const normalizedTitle = account.name.toLowerCase();
@@ -104,6 +116,10 @@ const ItemForm = ({
};
}, [formik, selectedAccounts]);
const categoryItem = useCallback((item, { handleClick }) => (
<MenuItem text={item.name} onClick={handleClick} />
), []);
const getSelectedAccountLabel = useCallback((fieldName, defaultLabel) => {
return typeof selectedAccounts[fieldName] !== 'undefined'
? selectedAccounts[fieldName].name : defaultLabel;
@@ -112,6 +128,10 @@ const ItemForm = ({
const requiredSpan = useMemo(() => (<span class="required">*</span>), []);
const infoIcon = useMemo(() => (<Icon icon="info-circle" iconSize={12} />), []);
const handleMoneyInputChange = (fieldKey) => (e, value) => {
formik.setFieldValue(fieldKey, value);
};
return (
<div class='item-form'>
<form onSubmit={formik.handleSubmit}>
@@ -175,8 +195,8 @@ const ItemForm = ({
)}
>
<Select
items={accounts}
itemRenderer={accountItem}
items={categoriesList}
itemRenderer={categoryItem}
itemPredicate={filterAccounts}
popoverProps={{ minimal: true }}
onItemSelect={onItemAccountSelect('category_id')}
@@ -184,15 +204,28 @@ const ItemForm = ({
<Button
fill={true}
rightIcon='caret-down'
text={getSelectedAccountLabel('category_id', 'Select account')}
text={getSelectedAccountLabel('category_id', 'Select category')}
/>
</Select>
</FormGroup>
<FormGroup
label={' '}
inline={true}
className={'form-group--active'}
>
<Checkbox
inline={true}
label={'Active'}
defaultChecked={values.active}
{...formik.getFieldProps('active')}
/>
</FormGroup>
</div>
<Row gutterWidth={16} className={'item-form__accounts-section'}>
<Col width={404}>
<h4 >Purchase Information</h4>
<h4>Purchase Information</h4>
<FormGroup
label={'Selling Price'}
@@ -201,11 +234,14 @@ const ItemForm = ({
helperText={<ErrorMessage {...formik} name="selling_price" />}
inline={true}
>
<InputGroup
medium={true}
intent={(errors.selling_price && touched.selling_price) && Intent.DANGER}
{...formik.getFieldProps('sell_price')}
/>
<MoneyInputGroup
value={values.selling_price}
prefix={'$'}
onChange={handleMoneyInputChange('selling_price')}
inputGroupProps={{
medium: true,
intent: (errors.selling_price && touched.selling_price) && Intent.DANGER,
}} />
</FormGroup>
<FormGroup
@@ -236,7 +272,9 @@ const ItemForm = ({
</Col>
<Col width={404}>
<h4>Sales Information</h4>
<h4>
Sales Information
</h4>
<FormGroup
label={'Cost Price'}
@@ -245,11 +283,14 @@ const ItemForm = ({
helperText={<ErrorMessage {...formik} name="cost_price" />}
inline={true}
>
<InputGroup
medium={true}
intent={(errors.cost_price && touched.cost_price) && Intent.DANGER}
{...formik.getFieldProps('cost_price')}
/>
<MoneyInputGroup
value={values.cost_price}
prefix={'$'}
onChange={handleMoneyInputChange('cost_price')}
inputGroupProps={{
medium: true,
intent: (errors.cost_price && touched.cost_price) && Intent.DANGER,
}} />
</FormGroup>
<FormGroup
@@ -262,7 +303,7 @@ const ItemForm = ({
'form-group--cost-account',
'form-group--select-list',
Classes.FILL)}
>
>
<Select
items={accounts}
itemRenderer={accountItem}
@@ -282,12 +323,14 @@ const ItemForm = ({
<Row className={'item-form__accounts-section mt2'}>
<Col width={404}>
<h4>Inventory Information</h4>
<h4>
Inventory Information
</h4>
<FormGroup
label={'Inventory Account'}
inline={true}
intent={(errors.inventory_account_id && errors.inventory_account_id) && Intent.DANGER}
intent={(errors.inventory_account_id && touched.inventory_account_id) && Intent.DANGER}
helperText={<ErrorMessage {...formik} name="inventory_account_id" />}
className={classNames(
'form-group--item-inventory_account',
@@ -312,8 +355,8 @@ const ItemForm = ({
<FormGroup
label={'Opening Stock'}
className={'form-group--item-stock'}
intent={formik.errors.cost_price && Intent.DANGER}
helperText={formik.errors.stock && formik.errors.stock}
// intent={errors.cost_price && Intent.DANGER}
// helperText={formik.errors.stock && formik.errors.stock}
inline={true}
>
<InputGroup
@@ -341,4 +384,5 @@ const ItemForm = ({
export default compose(
AccountsConnect,
ItemsConnect,
ItemCategoryConnect,
)(ItemForm);

View File

@@ -147,6 +147,12 @@ function ManualJournalsDataTable({
onFetchData && onFetchData();
}, [onFetchData]);
const selectionColumn = useMemo(() => ({
minWidth: 42,
width: 42,
maxWidth: 42,
}), []);
return (
<LoadingIndicator loading={manualJournalsLoading} spinnerSize={30}>
<DataTable
@@ -154,7 +160,7 @@ function ManualJournalsDataTable({
data={manualJournals}
onFetchData={handleDataTableFetchData}
manualSortBy={true}
selectionColumn={true}
selectionColumn={selectionColumn}
/>
</LoadingIndicator>
);

View File

@@ -19,7 +19,7 @@ export default [
children: [
{
text: 'Items List',
href: '/dashboard/items/list'
href: '/dashboard/items'
},
{
text: 'New Item',
@@ -27,7 +27,7 @@ export default [
},
{
text: 'Category List',
href: '/dashboard/items/ItemCategoriesList'
href: '/dashboard/items/categories'
},
]
},

View File

@@ -24,6 +24,7 @@ export const mapStateToProps = (state, props) => {
state.items.items, viewPages, state.items.currentPage),
bulkSelected: state.items.bulkActions,
itemsTableLoading: state.items.loading,
};
};
@@ -37,6 +38,14 @@ export const mapDispatchToProps = (dispatch) => ({
removeBulkActionItem: (id) => dispatch({
type: t.ITEM_BULK_ACTION_REMOVE, itemId: id,
}),
setItemsTableQuery: (key, value) => dispatch({
type: t.ITEMS_TABLE_QUERY_SET, key, value,
}),
addItemsTableQueries: (queries) =>
dispatch({
type: t.ITEMS_TABLE_QUERIES_ADD, queries,
}),
});
export default connect(mapStateToProps, mapDispatchToProps);

View File

@@ -12,6 +12,7 @@ export const mapStateToProps = (state, props) => {
const dialogPayload = getDialogPayload(state, 'item-form');
return {
categories: state.itemCategories.categories,
categoriesList: Object.values(state.itemCategories.categories),
name: 'item-form',
payload: { action: 'new', id: null },
editItemCategory:
@@ -21,6 +22,7 @@ export const mapStateToProps = (state, props) => {
getCategoryId: id => getCategoryId(state, id)
};
};
export const mapDispatchToProps = dispatch => ({
requestSubmitItemCategory: form => dispatch(submitItemCategory({ form })),
requestFetchItemCategories: () => dispatch(fetchItemCategories()),

View File

@@ -117,8 +117,7 @@ function AccountsChart({
console.log(accounts);
};
const handleFilterChanged = useCallback(() => {
const handleFilterChanged = useCallback(() => {
fetchAccountsHook.execute();
}, [fetchAccountsHook]);

View File

@@ -6,11 +6,13 @@ import ItemForm from 'components/Items/ItemForm';
import DashboardInsider from 'components/Dashboard/DashboardInsider';
import ItemsConnect from 'connectors/Items.connect';
import AccountsConnect from 'connectors/Accounts.connector';
import ItemCategoryConnect from 'connectors/ItemsCategory.connect';
import { compose } from 'utils';
const ItemFormContainer = ({
changePageTitle,
fetchAccounts,
requestFetchAccounts,
requestFetchItemCategories,
}) => {
const { id } = useParams();
useEffect(() => {
@@ -21,11 +23,12 @@ const ItemFormContainer = ({
const fetchHook = useAsync(async () => {
await Promise.all([
fetchAccounts(),
requestFetchAccounts(),
requestFetchItemCategories(),
]);
});
return (
<DashboardInsider isLoading={fetchHook.loading} name={'item-form'}>
<DashboardInsider loading={fetchHook.loading} name={'item-form'}>
<ItemForm />
</DashboardInsider>
);
@@ -35,4 +38,5 @@ export default compose(
DashboardConnect,
ItemsConnect,
AccountsConnect,
ItemCategoryConnect,
)(ItemFormContainer);

View File

@@ -1,4 +1,4 @@
import React, { useMemo } from 'react';
import React, { useMemo, useCallback } from 'react';
import { useRouteMatch, useHistory } from 'react-router-dom';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
@@ -13,7 +13,7 @@ import {
Position,
Button,
Classes,
Intent
Intent,
} from '@blueprintjs/core';
import classNames from 'classnames';
import Icon from 'components/Icon';
@@ -28,8 +28,9 @@ const ItemsActionsBar = ({
getResourceFields,
getResourceViews,
views,
onFilterChange,
bulkSelected
onFilterChanged,
bulkSelected,
addItemsTableQueries,
}) => {
const { path } = useRouteMatch();
const history = useHistory();
@@ -46,7 +47,12 @@ const ItemsActionsBar = ({
const filterDropdown = FilterDropdown({
fields: itemsFields,
onFilterChange
onFilterChange: (filterConditions) => {
addItemsTableQueries({
filter_roles: filterConditions || '',
});
onFilterChanged && onFilterChanged(filterConditions);
}
});
const hasBulkActionsSelected = useMemo(
@@ -54,9 +60,9 @@ const ItemsActionsBar = ({
[bulkSelected]
);
const onClickNewCategory = () => {
const onClickNewCategory = useCallback(() => {
openDialog('item-form', {});
};
}, [openDialog]);
return (
<DashboardActionsBar>

View File

@@ -1,4 +1,4 @@
import React, {useEffect, useMemo} from 'react';
import React, {useEffect, useCallback, useMemo} from 'react';
import {
Button,
Popover,
@@ -6,87 +6,76 @@ import {
MenuItem,
MenuDivider,
Position,
Checkbox,
} from '@blueprintjs/core'
import LoadingIndicator from 'components/LoadingIndicator';
import CustomViewConnect from 'connectors/View.connector';
import ItemsConnect from 'connectors/Items.connect';
import {useParams} from 'react-router-dom'
import {compose} from 'utils';
import useAsync from 'hooks/async';
import DataTable from 'components/DataTable';
import Icon from 'components/Icon';
import {handleBooleanChange} from 'utils';
import Money from 'components/Money';
const ItemsDataTable = ({
requestFetchItems,
filterConditions,
itemsTableLoading,
currentPageItems,
onEditItem,
onDeleteItem,
addBulkActionItem,
removeBulkActionItem,
onFetchData,
}) => {
const { custom_view_id: customViewId } = useParams();
const fetchHook = useAsync(async () => {
await Promise.all([
requestFetchItems({
custom_view_id: customViewId,
stringified_filter_roles: JSON.stringify(filterConditions),
}),
]);
});
const handleEditItem = (item) => () => { onEditItem(item); };
const handleDeleteItem = (item) => () => { onDeleteItem(item); };
const handleClickCheckboxBulk = (item) => handleBooleanChange((value) => {
if (value) {
addBulkActionItem(item.id);
} else {
removeBulkActionItem(item.id);
}
});
const actionMenuList = (item) =>
const actionMenuList = useCallback((item) =>
(<Menu>
<MenuItem text="View Details" />
<MenuDivider />
<MenuItem text="Edit Item" onClick={handleEditItem(item)} />
<MenuItem text="Delete Item" onClick={handleDeleteItem(item)} />
</Menu>);
</Menu>), [handleEditItem, handleDeleteItem]);
const columns = useMemo(() => [
{
id: 'bulk_select',
Cell: ({ cell }) =>
(<Checkbox onChange={handleClickCheckboxBulk(cell.row.original)} />),
},
{
Header: 'Item Name',
accessor: 'name',
className: "actions",
},
{
Header: 'Cost Account',
accessor: 'cost_account.name',
className: "cost-account",
},
{
Header: 'Sell Account',
accessor: 'sell_account.name',
className: "sell-account",
},
{
Header: 'Inventory Account',
accessor: 'inventory_account.name',
className: "inventory-account",
Header: 'SKU',
accessor: 'sku',
className: "sku",
},
{
Header: 'Category',
accessor: 'category.name',
className: 'category',
},
{
Header: 'Sell Price',
accessor: row => (<Money amount={row.sell_price} currency={'USD'} />),
className: 'sell-price',
},
{
Header: 'Cost Price',
accessor: row => (<Money amount={row.cost_price} currency={'USD'} />),
className: 'cost-price',
},
// {
// Header: 'Cost Account',
// accessor: 'cost_account.name',
// className: "cost-account",
// },
// {
// Header: 'Sell Account',
// accessor: 'sell_account.name',
// className: "sell-account",
// },
// {
// Header: 'Inventory Account',
// accessor: 'inventory_account.name',
// className: "inventory-account",
// },
{
id: 'actions',
Cell: ({ cell }) => (
@@ -96,14 +85,28 @@ const ItemsDataTable = ({
<Button icon={<Icon icon="ellipsis-h" />} />
</Popover>
),
className: 'actions',
width: 50,
},
]);
], [actionMenuList]);
const selectionColumn = useMemo(() => ({
minWidth: 42,
width: 42,
maxWidth: 42,
}), []);
const handleFetchData = useCallback((...args) => {
onFetchData && onFetchData(...args)
}, [onFetchData])
return (
<LoadingIndicator loading={fetchHook.pending} spinnerSize={30}>
<LoadingIndicator loading={itemsTableLoading} spinnerSize={30}>
<DataTable
columns={columns}
data={currentPageItems} />
data={currentPageItems}
selectionColumn={selectionColumn}
onFetchData={handleFetchData} />
</LoadingIndicator>
);
};

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useCallback, useState } from 'react';
import {
Route,
Switch,
@@ -17,22 +17,24 @@ import ResourceConnect from 'connectors/Resource.connector';
import DashboardConnect from 'connectors/Dashboard.connector';
import ItemsConnect from 'connectors/Items.connect';
import CustomViewsConnect from 'connectors/CustomView.connector'
import DashboardViewsTabs from 'components/Accounts/AccountsViewsTabs';
import ItemsViewsTabs from 'containers/Dashboard/Items/ItemsViewsTabs';
import AppToaster from 'components/AppToaster';
function ItemsList({
changePageTitle,
fetchResourceViews,
fetchResourceFields,
views,
requestDeleteItem,
requestFetchItems,
addItemsTableQueries,
}) {
const [filterConditions, setFilterConditions] = useState([]);
const [deleteItem, setDeleteItem] = useState(false);
useEffect(() => {
changePageTitle('Items List');
}, []);
}, [changePageTitle]);
const fetchHook = useAsync(async () => {
await Promise.all([
@@ -40,31 +42,68 @@ function ItemsList({
fetchResourceFields('items'),
])
});
const handleDeleteItem = (item) => { setDeleteItem(item); };
const fetchItems = useAsync(async () => {
await Promise.all([
requestFetchItems({ }),
])
});
const handleDeleteItem = useCallback((item) => {
setDeleteItem(item);
}, [setDeleteItem]);
const handleEditItem = () => {};
const handleCancelDeleteItem = () => { setDeleteItem(false) };
const handleConfirmDeleteItem = () => {
const handleCancelDeleteItem = useCallback(() => {
setDeleteItem(false);
}, [setDeleteItem]);
const handleConfirmDeleteItem = useCallback(() => {
requestDeleteItem(deleteItem.id).then(() => {
AppToaster.show({ message: 'the_item_has_been_deleted' });
setDeleteItem(false);
});
};
}, [requestDeleteItem, deleteItem]);
const handleFilterChange = (filter) => { setFilterConditions(filter); };
const handleFetchData = useCallback(({ pageIndex, pageSize, sortBy }) => {
addItemsTableQueries({
...(sortBy.length > 0) ? {
column_sort_by: sortBy[0].id,
sort_by: sortBy[0].desc ? 'desc' : 'asc',
} : {},
});
fetchItems.execute();
}, [fetchItems, addItemsTableQueries]);
const handleFilterChanged = useCallback(() => {
fetchItems.execute();
}, [fetchItems]);
const handleCustomViewChanged = useCallback(() => {
fetchItems.execute();
}, [fetchItems]);
return (
<DashboardInsider isLoading={fetchHook.pending} name={'items-list'}>
<ItemsActionsBar views={views} onFilterChange={handleFilterChange} />
<ItemsActionsBar
onFilterChanged={handleFilterChanged}
views={views} />
<DashboardPageContent>
<Switch>
<Route>
<DashboardViewsTabs resourceName={'items'} />
<Route
exact={true}
path={[
'/dashboard/items/:custom_view_id/custom_view',
'/dashboard/items'
]}>
<ItemsViewsTabs onViewChanged={handleCustomViewChanged} />
<ItemsDataTable
filterConditions={filterConditions}
onDeleteItem={handleDeleteItem}
onEditItem={handleEditItem} />
onEditItem={handleEditItem}
onFetchData={handleFetchData} />
<Alert
cancelButtonText="Cancel"

View File

@@ -0,0 +1,94 @@
import React, {useEffect} from 'react';
import { useHistory } from 'react-router';
import { connect } from 'react-redux';
import {
Alignment,
Navbar,
NavbarGroup,
Tabs,
Tab,
Button
} from '@blueprintjs/core';
import { useParams } from 'react-router-dom';
import Icon from 'components/Icon';
import { Link } from 'react-router-dom';
import { compose } from 'utils';
import ItemsConnect from 'connectors/Items.connect';
import DashboardConnect from 'connectors/Dashboard.connector';
import {useUpdateEffect} from 'hooks';
function ItemsViewsTabs({
views,
setTopbarEditView,
customViewChanged,
addItemsTableQueries,
onViewChanged,
}) {
const history = useHistory();
const { custom_view_id: customViewId } = useParams();
const handleClickNewView = () => {
setTopbarEditView(null);
history.push('/dashboard/custom_views/items/new');
};
const handleViewLinkClick = () => {
setTopbarEditView(customViewId);
}
useUpdateEffect(() => {
customViewChanged && customViewChanged(customViewId);
addItemsTableQueries({
custom_view_id: customViewId || null,
});
onViewChanged && onViewChanged(customViewId);
}, [customViewId]);
useEffect(() => {
addItemsTableQueries({
custom_view_id: customViewId,
})
}, [customViewId, addItemsTableQueries]);
const tabs = views.map(view => {
const baseUrl = '/dashboard/items';
const link = (
<Link
to={`${baseUrl}/${view.id}/custom_view`}
onClick={handleViewLinkClick}
>{view.name}</Link>
);
return <Tab
id={`custom_view_${view.id}`}
title={link} />;
});
return (
<Navbar className='navbar--dashboard-views'>
<NavbarGroup align={Alignment.LEFT}>
<Tabs
id='navbar'
large={true}
selectedTabId={`custom_view_${customViewId}`}
className='tabs--dashboard-views'
>
<Tab
id='all'
title={<Link to={`/dashboard/items`}>All</Link>} />
{tabs}
<Button
className='button--new-view'
icon={<Icon icon='plus' />}
onClick={handleClickNewView}
minimal={true}
/>
</Tabs>
</NavbarGroup>
</Navbar>
);
}
export default compose(
ItemsConnect,
DashboardConnect,
)(ItemsViewsTabs);

View File

@@ -83,14 +83,14 @@ export default [
}),
text: 'Manual Journals'
},
// Items
{
path: `${BASE_URL}/items/list`,
path: `${BASE_URL}/items/categories`,
component: LazyLoader({
loader: () => import('containers/Dashboard/Items/ItemsList')
loader: () => import('containers/Dashboard/Items/ItemsCategoryList')
})
},
{
path: `${BASE_URL}/items/new`,
component: LazyLoader({
@@ -98,13 +98,16 @@ export default [
})
},
// Items
{
path: `${BASE_URL}/items/ItemCategoriesList`,
path: `${BASE_URL}/items`,
component: LazyLoader({
loader: () => import('containers/Dashboard/Items/ItemsCategoryList')
loader: () => import('containers/Dashboard/Items/ItemsList')
})
},
// Financial Reports.
{
path: `${BASE_URL}/accounting/general-ledger`,

View File

@@ -10,8 +10,14 @@ export const editItem = ({ id, form }) => {
};
export const fetchItems = ({ query }) => {
return (dispatch) => new Promise((resolve, reject) => {
ApiService.get(`items`).then(response => {
return (dispatch, getState) => new Promise((resolve, reject) => {
const pageQuery = getState().accounts.tableQuery;
dispatch({
type: t.ITEMS_TABLE_LOADING,
payload: { loading: true },
});
ApiService.get(`items`, { params: { ...pageQuery, ...query } }).then(response => {
dispatch({
type: t.ITEMS_SET,
items: response.data.items.results,
@@ -22,6 +28,10 @@ export const fetchItems = ({ query }) => {
customViewId: response.data.customViewId,
paginationMeta: response.data.items.pagination,
});
dispatch({
type: t.ITEMS_TABLE_LOADING,
payload: { loading: false },
});
resolve(response);
}).catch(error => { reject(error); });
});

View File

@@ -3,6 +3,7 @@ import { createReducer } from '@reduxjs/toolkit';
import {
getItemsViewPages,
} from 'store/items/items.selectors';
import { createTableQueryReducers } from 'store/queryReducers';
const initialState = {
items: {},
@@ -10,10 +11,12 @@ const initialState = {
itemsRelation: {},
currentPage: 1,
currentViewId: -1,
tableQuery: {},
bulkActions: {},
loading: false,
};
export default createReducer(initialState, {
const itemsReducer = createReducer(initialState, {
[t.ITEMS_SET]: (state, action) => {
const _items = {};
@@ -83,10 +86,16 @@ export default createReducer(initialState, {
delete state.items[itemId];
}
},
[t.ITEMS_TABLE_LOADING]: (state, action) => {
const { loading } = action.payload;
state.loading = !!loading;
},
});
export default createTableQueryReducers('items', itemsReducer);
export const getItemById = (state, id) => {
return state.items.items[id];
};

View File

@@ -6,4 +6,9 @@ export default {
ITEM_DELETE: 'ITEM_DELETE',
ITEM_BULK_ACTION_ADD: 'ITEM_BULK_ACTION_ADD',
ITEM_BULK_ACTION_REMOVE: 'ITEM_BULK_ACTION_REMOVE',
ITEMS_TABLE_QUERY_SET: 'ITEMS_TABLE_QUERY_SET',
ITEMS_TABLE_QUERIES_ADD: 'ITEMS_TABLE_QUERIES_ADD',
ITEMS_TABLE_LOADING: 'ITEMS_TABLE_LOADING',
}

View File

@@ -242,6 +242,7 @@ $form-check-input-indeterminate-bg-image: url("data:image/svg+xml,<svg xmlns='ht
.#{$ns}-control-indicator {
border: 1px solid #c6c6c6;
border-radius: $pt-border-radius;
background-color: #fff;
}
input:checked ~ .#{$ns}-control-indicator {
background-image: escape-svg($form-check-input-checked-bg-image);

View File

@@ -11,14 +11,6 @@
}
.table{
.thead,
.tbody{
.th.selection,
.td.selection{
padding-left: 18px;
}
}
.tbody{
.tr:not(.no-results) .td{
padding-top: 0.4rem;

View File

@@ -6,7 +6,7 @@
&__topbar{
width: 100%;
height: 80px;
min-height: 65px;
display: flex;
justify-content: space-between;
border-bottom: 1px solid #F2EFEF;
@@ -215,6 +215,20 @@
&__page-content{
// padding: 22px;
.bigcapital-datatable{
.table{
.thead,
.tbody{
.th.selection,
.td.selection{
padding-left: 18px;
}
}
}
}
}
&__preferences-topbar{

View File

@@ -45,4 +45,12 @@
width: 350px;
}
}
.form-group--active{
margin-bottom: 5px;
.bp3-control.bp3-checkbox{
margin: 0;
}
}
}