mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 21:30:31 +00:00
fix bugs.
This commit is contained in:
@@ -12,19 +12,24 @@ import Progress from 'components/NProgress/Progress';
|
||||
import messages from 'lang/en';
|
||||
import 'style/App.scss';
|
||||
|
||||
function App(props) {
|
||||
function App({
|
||||
isAuthorized,
|
||||
locale,
|
||||
}) {
|
||||
const history = createBrowserHistory();
|
||||
|
||||
history.listen((location, action) => {
|
||||
console.log(`new location via ${action}`, location);
|
||||
});
|
||||
|
||||
return (
|
||||
<IntlProvider locale={props.locale} messages={messages}>
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
<div className="App">
|
||||
<Router history={history}>
|
||||
<Authentication isAuthenticated={props.isAuthorized} />
|
||||
<PrivateRoute isAuthenticated={props.isAuthorized} component={Dashboard} />
|
||||
<Authentication isAuthenticated={isAuthorized} />
|
||||
<PrivateRoute isAuthenticated={isAuthorized} component={Dashboard} />
|
||||
</Router>
|
||||
</div>
|
||||
|
||||
<Progress isAnimating={props.isLoading} />
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
@@ -33,13 +38,10 @@ App.defaultProps = {
|
||||
locale: 'en',
|
||||
};
|
||||
|
||||
App.propTypes = {
|
||||
locale: PropTypes.string,
|
||||
isAuthorized: PropTypes.bool,
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
isAuthorized: isAuthenticated(state),
|
||||
};
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
isAuthorized: isAuthenticated(state),
|
||||
isLoading: !!state.dashboard.requestsLoading,
|
||||
});
|
||||
export default connect(mapStateToProps)(App);
|
||||
@@ -9,7 +9,8 @@ export default function DashboardContentRoute() {
|
||||
<Switch>
|
||||
{ routes.map((route, index) => (
|
||||
<Route
|
||||
key={index}
|
||||
exact
|
||||
// key={index}
|
||||
path={`${route.path}`}
|
||||
component={route.component} />
|
||||
))}
|
||||
|
||||
@@ -15,11 +15,8 @@ function DashboardTopbarUser({ logout }) {
|
||||
|
||||
const onClickLogout = useCallback(() => {
|
||||
logout();
|
||||
|
||||
setTimeout(() => {
|
||||
history.push('/auth/login');
|
||||
}, 100);
|
||||
}, [history, logout]);
|
||||
history.go('/auth/login');
|
||||
}, [logout, history]);
|
||||
|
||||
const userAvatarDropMenu = useMemo(() => (
|
||||
<Menu>
|
||||
|
||||
@@ -93,9 +93,9 @@ export default function DataTable({
|
||||
...(selectionColumn) ? [{
|
||||
id: 'selection',
|
||||
disableResizing: true,
|
||||
minWidth: 35,
|
||||
width: 35,
|
||||
maxWidth: 35,
|
||||
minWidth: 42,
|
||||
width: 42,
|
||||
maxWidth: 42,
|
||||
// The header can use the table's getToggleAllRowsSelectedProps method
|
||||
// to render a checkbox
|
||||
Header: ({ getToggleAllRowsSelectedProps }) => (
|
||||
|
||||
@@ -22,15 +22,15 @@ import classNames from 'classnames';
|
||||
import Icon from 'components/Icon';
|
||||
import ItemCategoryConnect from 'connectors/ItemsCategory.connect';
|
||||
import MoneyInputGroup from 'components/MoneyInputGroup';
|
||||
|
||||
import {useHistory} from 'react-router-dom';
|
||||
|
||||
const ItemForm = ({
|
||||
requestSubmitItem,
|
||||
accounts,
|
||||
categories,
|
||||
categoriesList,
|
||||
}) => {
|
||||
const [selectedAccounts, setSelectedAccounts] = useState({});
|
||||
const history = useHistory();
|
||||
|
||||
const ItemTypeDisplay = useMemo(() => ([
|
||||
{ value: null, label: 'Select Item Type' },
|
||||
@@ -43,7 +43,7 @@ const ItemForm = ({
|
||||
active: Yup.boolean(),
|
||||
name: Yup.string().required(),
|
||||
type: Yup.string().trim().required(),
|
||||
sku: Yup.string().required(),
|
||||
sku: Yup.string().trim(),
|
||||
cost_price: Yup.number(),
|
||||
sell_price: Yup.number(),
|
||||
cost_account_id: Yup.number().required(),
|
||||
@@ -71,7 +71,14 @@ const ItemForm = ({
|
||||
note: '',
|
||||
}), []);
|
||||
|
||||
const formik = useFormik({
|
||||
const {
|
||||
getFieldProps,
|
||||
setFieldValue,
|
||||
values,
|
||||
touched,
|
||||
errors,
|
||||
handleSubmit,
|
||||
} = useFormik({
|
||||
enableReinitialize: true,
|
||||
validationSchema: validationSchema,
|
||||
initialValues: {
|
||||
@@ -83,13 +90,13 @@ const ItemForm = ({
|
||||
message: 'The_Items_has_been_Submit'
|
||||
});
|
||||
setSubmitting(false);
|
||||
history.push('/dashboard/items');
|
||||
})
|
||||
.catch((error) => {
|
||||
setSubmitting(false);
|
||||
});
|
||||
}
|
||||
});
|
||||
const {errors, values, touched} = useMemo(() => formik, [formik]);
|
||||
|
||||
const accountItem = useCallback((item, { handleClick }) => (
|
||||
<MenuItem key={item.id} text={item.name} label={item.code} onClick={handleClick} />
|
||||
@@ -112,9 +119,9 @@ const ItemForm = ({
|
||||
...selectedAccounts,
|
||||
[filedName]: account
|
||||
});
|
||||
formik.setFieldValue(filedName, account.id);
|
||||
setFieldValue(filedName, account.id);
|
||||
};
|
||||
}, [formik, selectedAccounts]);
|
||||
}, [setFieldValue, selectedAccounts]);
|
||||
|
||||
const categoryItem = useCallback((item, { handleClick }) => (
|
||||
<MenuItem text={item.name} onClick={handleClick} />
|
||||
@@ -129,12 +136,12 @@ const ItemForm = ({
|
||||
const infoIcon = useMemo(() => (<Icon icon="info-circle" iconSize={12} />), []);
|
||||
|
||||
const handleMoneyInputChange = (fieldKey) => (e, value) => {
|
||||
formik.setFieldValue(fieldKey, value);
|
||||
setFieldValue(fieldKey, value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div class='item-form'>
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div class="item-form__primary-section">
|
||||
<FormGroup
|
||||
medium={true}
|
||||
@@ -142,13 +149,13 @@ const ItemForm = ({
|
||||
labelInfo={requiredSpan}
|
||||
className={'form-group--item-type'}
|
||||
intent={(errors.type && touched.type) && Intent.DANGER}
|
||||
helperText={<ErrorMessage {...formik} name="type" />}
|
||||
helperText={<ErrorMessage {...{errors, touched}} name="type" />}
|
||||
inline={true}
|
||||
>
|
||||
<HTMLSelect
|
||||
fill={true}
|
||||
options={ItemTypeDisplay}
|
||||
{...formik.getFieldProps('type')}
|
||||
{...getFieldProps('type')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
@@ -157,13 +164,13 @@ const ItemForm = ({
|
||||
labelInfo={requiredSpan}
|
||||
className={'form-group--item-name'}
|
||||
intent={(errors.name && touched.name) && Intent.DANGER}
|
||||
helperText={<ErrorMessage {...formik} name="name" />}
|
||||
helperText={<ErrorMessage {...{errors, touched}} name="name" />}
|
||||
inline={true}
|
||||
>
|
||||
<InputGroup
|
||||
medium={true}
|
||||
intent={(errors.name && touched.name) && Intent.DANGER}
|
||||
{...formik.getFieldProps('name')}
|
||||
{...getFieldProps('name')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
@@ -172,13 +179,13 @@ const ItemForm = ({
|
||||
labelInfo={infoIcon}
|
||||
className={'form-group--item-sku'}
|
||||
intent={(errors.sku && touched.sku) && Intent.DANGER}
|
||||
helperText={<ErrorMessage {...formik} name="sku" />}
|
||||
helperText={<ErrorMessage {...{errors, touched}} name="sku" />}
|
||||
inline={true}
|
||||
>
|
||||
<InputGroup
|
||||
medium={true}
|
||||
intent={(errors.sku && touched.sku) && Intent.DANGER}
|
||||
{...formik.getFieldProps('sku')}
|
||||
{...getFieldProps('sku')}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
@@ -187,7 +194,7 @@ const ItemForm = ({
|
||||
labelInfo={infoIcon}
|
||||
inline={true}
|
||||
intent={(errors.category_id && touched.category_id) && Intent.DANGER}
|
||||
helperText={<ErrorMessage {...formik} name="category" />}
|
||||
helperText={<ErrorMessage {...{errors, touched}} name="category" />}
|
||||
className={classNames(
|
||||
'form-group--select-list',
|
||||
'form-group--category',
|
||||
@@ -195,7 +202,7 @@ const ItemForm = ({
|
||||
)}
|
||||
>
|
||||
<Select
|
||||
items={categoriesList}
|
||||
items={categories}
|
||||
itemRenderer={categoryItem}
|
||||
itemPredicate={filterAccounts}
|
||||
popoverProps={{ minimal: true }}
|
||||
@@ -218,7 +225,7 @@ const ItemForm = ({
|
||||
inline={true}
|
||||
label={'Active'}
|
||||
defaultChecked={values.active}
|
||||
{...formik.getFieldProps('active')}
|
||||
{...getFieldProps('active')}
|
||||
/>
|
||||
</FormGroup>
|
||||
</div>
|
||||
@@ -231,7 +238,7 @@ const ItemForm = ({
|
||||
label={'Selling Price'}
|
||||
className={'form-group--item-selling-price'}
|
||||
intent={(errors.selling_price && touched.selling_price) && Intent.DANGER}
|
||||
helperText={<ErrorMessage {...formik} name="selling_price" />}
|
||||
helperText={<ErrorMessage {...{errors, touched}} name="selling_price" />}
|
||||
inline={true}
|
||||
>
|
||||
<MoneyInputGroup
|
||||
@@ -249,7 +256,7 @@ const ItemForm = ({
|
||||
labelInfo={infoIcon}
|
||||
inline={true}
|
||||
intent={(errors.sell_account_id && touched.sell_account_id) && Intent.DANGER}
|
||||
helperText={<ErrorMessage {...formik} name="sell_account_id" />}
|
||||
helperText={<ErrorMessage {...{errors, touched}} name="sell_account_id" />}
|
||||
className={classNames(
|
||||
'form-group--sell-account',
|
||||
'form-group--select-list',
|
||||
@@ -280,7 +287,7 @@ const ItemForm = ({
|
||||
label={'Cost Price'}
|
||||
className={'form-group--item-cost-price'}
|
||||
intent={(errors.cost_price && touched.cost_price) && Intent.DANGER}
|
||||
helperText={<ErrorMessage {...formik} name="cost_price" />}
|
||||
helperText={<ErrorMessage {...{errors, touched}} name="cost_price" />}
|
||||
inline={true}
|
||||
>
|
||||
<MoneyInputGroup
|
||||
@@ -298,7 +305,7 @@ const ItemForm = ({
|
||||
labelInfo={infoIcon}
|
||||
inline={true}
|
||||
intent={(errors.cost_account_id && touched.cost_account_id) && Intent.DANGER}
|
||||
helperText={<ErrorMessage {...formik} name="cost_account_id" />}
|
||||
helperText={<ErrorMessage {...{errors, touched}} name="cost_account_id" />}
|
||||
className={classNames(
|
||||
'form-group--cost-account',
|
||||
'form-group--select-list',
|
||||
@@ -331,7 +338,7 @@ const ItemForm = ({
|
||||
label={'Inventory Account'}
|
||||
inline={true}
|
||||
intent={(errors.inventory_account_id && touched.inventory_account_id) && Intent.DANGER}
|
||||
helperText={<ErrorMessage {...formik} name="inventory_account_id" />}
|
||||
helperText={<ErrorMessage {...{errors, touched}} name="inventory_account_id" />}
|
||||
className={classNames(
|
||||
'form-group--item-inventory_account',
|
||||
'form-group--select-list',
|
||||
@@ -361,8 +368,8 @@ const ItemForm = ({
|
||||
>
|
||||
<InputGroup
|
||||
medium={true}
|
||||
intent={formik.errors.stock && Intent.DANGER}
|
||||
{...formik.getFieldProps('stock')}
|
||||
intent={errors.stock && Intent.DANGER}
|
||||
{...getFieldProps('stock')}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useCallback, useState, useMemo } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import Icon from 'components/Icon';
|
||||
import ItemsCategoryConnect from 'connectors/ItemsCategory.connect';
|
||||
import DialogConnect from 'connectors/Dialog.connector';
|
||||
@@ -11,8 +11,6 @@ import {
|
||||
Menu,
|
||||
MenuItem,
|
||||
Position,
|
||||
Classes,
|
||||
Tooltip,
|
||||
} from '@blueprintjs/core';
|
||||
|
||||
const ItemsCategoryList = ({
|
||||
@@ -22,6 +20,7 @@ const ItemsCategoryList = ({
|
||||
onEditCategory,
|
||||
openDialog,
|
||||
count,
|
||||
onSelectedRowsChange,
|
||||
}) => {
|
||||
const handelEditCategory = (category) => () => {
|
||||
openDialog('item-form', { action: 'edit', id: category.id });
|
||||
@@ -42,51 +41,51 @@ const ItemsCategoryList = ({
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'name',
|
||||
Header: 'Category Name',
|
||||
accessor: 'name',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
id: 'description',
|
||||
Header: 'Description',
|
||||
accessor: 'description',
|
||||
className: 'description',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
id: 'count',
|
||||
Header: 'Count',
|
||||
accessor: () => <span>{count}</span>,
|
||||
className: 'count',
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
Header: '',
|
||||
Cell: ({ cell }) => (
|
||||
<Popover
|
||||
content={actionMenuList(cell.row.original)}
|
||||
position={Position.RIGHT_BOTTOM}
|
||||
>
|
||||
<Button icon={<Icon icon='ellipsis-h' />} />
|
||||
</Popover>
|
||||
),
|
||||
className: 'actions',
|
||||
width: 50,
|
||||
// canResize: false
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
const columns = useMemo(() => [
|
||||
{
|
||||
id: 'name',
|
||||
Header: 'Category Name',
|
||||
accessor: 'name',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
id: 'description',
|
||||
Header: 'Description',
|
||||
accessor: 'description',
|
||||
className: 'description',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
id: 'count',
|
||||
Header: 'Count',
|
||||
accessor: (r) => r.count || '',
|
||||
className: 'count',
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
Header: '',
|
||||
Cell: ({ cell }) => (
|
||||
<Popover
|
||||
content={actionMenuList(cell.row.original)}
|
||||
position={Position.RIGHT_BOTTOM}
|
||||
>
|
||||
<Button icon={<Icon icon='ellipsis-h' />} />
|
||||
</Popover>
|
||||
),
|
||||
className: 'actions',
|
||||
width: 50,
|
||||
disableResizing: false
|
||||
},
|
||||
], [actionMenuList]);
|
||||
|
||||
const handelFetchData = useCallback(() => {
|
||||
onFetchData && onFetchData();
|
||||
}, []);
|
||||
|
||||
const handleSelectedRowsChange = useCallback((selectedRows) => {
|
||||
onSelectedRowsChange && onSelectedRowsChange(selectedRows.map(s => s.original));
|
||||
}, [onSelectedRowsChange]);
|
||||
|
||||
return (
|
||||
<LoadingIndicator spinnerSize={30}>
|
||||
@@ -97,10 +96,13 @@ const ItemsCategoryList = ({
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
expandable={true}
|
||||
treeGraph={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
/>
|
||||
</LoadingIndicator>
|
||||
);
|
||||
};
|
||||
|
||||
export default compose(DialogConnect, ItemsCategoryConnect)(ItemsCategoryList);
|
||||
export default compose(
|
||||
DialogConnect,
|
||||
ItemsCategoryConnect,
|
||||
)(ItemsCategoryList);
|
||||
|
||||
@@ -25,7 +25,9 @@ function ManualJournalActionsBar({
|
||||
views,
|
||||
getResourceFields,
|
||||
addManualJournalsTableQueries,
|
||||
onFilterChanged
|
||||
onFilterChanged,
|
||||
selectedRows,
|
||||
onBulkDelete
|
||||
}) {
|
||||
const { path } = useRouteMatch();
|
||||
const history = useHistory();
|
||||
@@ -50,6 +52,13 @@ function ManualJournalActionsBar({
|
||||
onFilterChanged && onFilterChanged(filterConditions);
|
||||
}
|
||||
});
|
||||
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [selectedRows]);
|
||||
|
||||
// Handle delete button click.
|
||||
const handleBulkDelete = useCallback(() => {
|
||||
onBulkDelete && onBulkDelete(selectedRows.map(r => r.id));
|
||||
}, [onBulkDelete, selectedRows]);
|
||||
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup>
|
||||
@@ -85,12 +94,13 @@ function ManualJournalActionsBar({
|
||||
/>
|
||||
</Popover>
|
||||
|
||||
{ (false) && (
|
||||
{(hasSelectedRows) && (
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon='trash' iconSize={15} />}
|
||||
text='Delete'
|
||||
intent={Intent.DANGER}
|
||||
onClick={handleBulkDelete}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
MenuDivider,
|
||||
Position,
|
||||
} from '@blueprintjs/core';
|
||||
import { useParams, useHistory } from 'react-router-dom';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import Icon from 'components/Icon';
|
||||
import { compose } from 'utils';
|
||||
import moment from 'moment';
|
||||
@@ -16,7 +16,7 @@ import ManualJournalsConnect from 'connectors/ManualJournals.connect';
|
||||
import DialogConnect from 'connectors/Dialog.connector';
|
||||
import DashboardConnect from 'connectors/Dashboard.connector';
|
||||
import ViewConnect from 'connectors/View.connector';
|
||||
import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import { useUpdateEffect } from 'hooks';
|
||||
import DataTable from 'components/DataTable';
|
||||
import Money from 'components/Money';
|
||||
|
||||
@@ -31,8 +31,16 @@ function ManualJournalsDataTable({
|
||||
onEditJournal,
|
||||
onDeleteJournal,
|
||||
onPublishJournal,
|
||||
onSelectedRowsChange,
|
||||
}) {
|
||||
const { custom_view_id: customViewId } = useParams();
|
||||
const [initialMount, setInitialMount] = useState(false);
|
||||
|
||||
useUpdateEffect(() => {
|
||||
if (!manualJournalsLoading) {
|
||||
setInitialMount(true);
|
||||
}
|
||||
}, [manualJournalsLoading, setInitialMount]);
|
||||
|
||||
useEffect(() => {
|
||||
const viewMeta = getViewItem(customViewId);
|
||||
@@ -42,7 +50,25 @@ function ManualJournalsDataTable({
|
||||
setTopbarEditView(customViewId);
|
||||
}
|
||||
changePageSubtitle(customViewId && viewMeta ? viewMeta.name : '');
|
||||
}, [customViewId]);
|
||||
}, [
|
||||
customViewId,
|
||||
changeCurrentView,
|
||||
changePageSubtitle,
|
||||
setTopbarEditView,
|
||||
getViewItem,
|
||||
]);
|
||||
|
||||
const handlePublishJournal = useCallback((journal) => () => {
|
||||
onPublishJournal && onPublishJournal(journal);
|
||||
}, [onPublishJournal]);
|
||||
|
||||
const handleEditJournal = useCallback((journal) => () => {
|
||||
onEditJournal && onEditJournal(journal);
|
||||
}, [onEditJournal]);
|
||||
|
||||
const handleDeleteJournal = useCallback((journal) => () => {
|
||||
onDeleteJournal && onDeleteJournal(journal);
|
||||
}, [onDeleteJournal]);
|
||||
|
||||
const actionMenuList = (journal) => (
|
||||
<Menu>
|
||||
@@ -51,21 +77,15 @@ function ManualJournalsDataTable({
|
||||
{!journal.status && (
|
||||
<MenuItem
|
||||
text="Publish Journal"
|
||||
onClick={() => {
|
||||
onPublishJournal && onPublishJournal(journal);
|
||||
}} />
|
||||
onClick={handlePublishJournal(journal)} />
|
||||
)}
|
||||
<MenuItem
|
||||
text='Edit Journal'
|
||||
onClick={() => {
|
||||
onEditJournal && onEditJournal(journal);
|
||||
}} />
|
||||
onClick={handleEditJournal(journal)} />
|
||||
<MenuItem
|
||||
text='Delete Journal'
|
||||
intent={Intent.DANGER}
|
||||
onClick={() => {
|
||||
onDeleteJournal && onDeleteJournal(journal);
|
||||
}} />
|
||||
onClick={handleDeleteJournal(journal)} />
|
||||
</Menu>
|
||||
);
|
||||
|
||||
@@ -143,26 +163,25 @@ function ManualJournalsDataTable({
|
||||
},
|
||||
], []);
|
||||
|
||||
const handleDataTableFetchData = useCallback(() => {
|
||||
onFetchData && onFetchData();
|
||||
const handleDataTableFetchData = useCallback((...args) => {
|
||||
onFetchData && onFetchData(...args);
|
||||
}, [onFetchData]);
|
||||
|
||||
const selectionColumn = useMemo(() => ({
|
||||
minWidth: 42,
|
||||
width: 42,
|
||||
maxWidth: 42,
|
||||
}), []);
|
||||
const handleSelectedRowsChange = useCallback((selectedRows) => {
|
||||
onSelectedRowsChange && onSelectedRowsChange(selectedRows.map(s => s.original));
|
||||
}, [onSelectedRowsChange]);
|
||||
|
||||
return (
|
||||
<LoadingIndicator loading={manualJournalsLoading} spinnerSize={30}>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={manualJournals}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={selectionColumn}
|
||||
/>
|
||||
</LoadingIndicator>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={manualJournals}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
loading={manualJournalsLoading && !initialMount}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
18
client/src/components/NProgress/AppProgress.js
Normal file
18
client/src/components/NProgress/AppProgress.js
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import Progress from './Progress';
|
||||
|
||||
function AppProgress({
|
||||
isAnimating,
|
||||
}) {
|
||||
return (
|
||||
<Progress isAnimating={isAnimating} />
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
isAnimating: state.dashboard.requestsLoading > 0,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(AppProgress);
|
||||
@@ -21,8 +21,11 @@ export default function SidebarMenu() {
|
||||
};
|
||||
return (
|
||||
(item.divider) ?
|
||||
<MenuDivider title={item.title} /> :
|
||||
<MenuDivider
|
||||
key={index}
|
||||
title={item.title} /> :
|
||||
<MenuItem
|
||||
key={index}
|
||||
active={isActive}
|
||||
icon={<Icon icon={item.icon} iconSize={item.iconSize} />}
|
||||
text={item.text}
|
||||
|
||||
@@ -21,8 +21,10 @@ export const mapStateToProps = (state, props) => {
|
||||
return {
|
||||
views: getResourceViews(state, 'items'),
|
||||
currentPageItems: getCurrentPageResults(
|
||||
state.items.items, viewPages, state.items.currentPage),
|
||||
|
||||
state.items.items,
|
||||
viewPages,
|
||||
state.items.currentPage,
|
||||
),
|
||||
bulkSelected: state.items.bulkActions,
|
||||
itemsTableLoading: state.items.loading,
|
||||
};
|
||||
|
||||
@@ -12,8 +12,7 @@ export const mapStateToProps = (state, props) => {
|
||||
const dialogPayload = getDialogPayload(state, 'item-form');
|
||||
|
||||
return {
|
||||
categories: state.itemCategories.categories,
|
||||
count: 1,
|
||||
categories: Object.values(state.itemCategories.categories),
|
||||
name: 'item-form',
|
||||
payload: { action: 'new', id: null },
|
||||
editItemCategory:
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
deleteManualJournal,
|
||||
fetchManualJournalsTable,
|
||||
publishManualJournal,
|
||||
deleteBulkManualJournals,
|
||||
} from 'store/manualJournals/manualJournals.actions';
|
||||
import { getResourceViews } from 'store/customViews/customViews.selectors';
|
||||
import t from 'store/types';
|
||||
@@ -26,14 +27,14 @@ const mapActionsToProps = (dispatch) => ({
|
||||
}),
|
||||
addManualJournalsTableQueries: (queries) =>
|
||||
dispatch({
|
||||
type: 'MANUAL_JOURNALS_TABLE_QUERIES_ADD',
|
||||
type: t.MANUAL_JOURNALS_TABLE_QUERIES_ADD,
|
||||
queries,
|
||||
}),
|
||||
fetchManualJournalsTable: (query = {}) =>
|
||||
dispatch(fetchManualJournalsTable({ query: { ...query } })),
|
||||
|
||||
requestPublishManualJournal: (id) =>
|
||||
dispatch(publishManualJournal({ id })),
|
||||
requestPublishManualJournal: (id) => dispatch(publishManualJournal({ id })),
|
||||
requestDeleteBulkManualJournals: (ids) => dispatch(deleteBulkManualJournals({ ids })),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapActionsToProps);
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
FormGroup,
|
||||
} from "@blueprintjs/core";
|
||||
import login from 'store/authentication/authentication.actions';
|
||||
import {hasErrorType, isAuthenticated} from 'store/authentication/authentication.reducer';
|
||||
import {hasErrorType} from 'store/authentication/authentication.reducer';
|
||||
import AuthenticationToaster from 'components/AppToaster';
|
||||
import t from 'store/types';
|
||||
|
||||
@@ -21,9 +21,6 @@ const ERRORS_TYPES = {
|
||||
};
|
||||
function Login({
|
||||
login,
|
||||
errors,
|
||||
clearErrors,
|
||||
hasError,
|
||||
}) {
|
||||
const intl = useIntl();
|
||||
const history = useHistory();
|
||||
@@ -51,36 +48,29 @@ function Login({
|
||||
login({
|
||||
crediential: values.crediential,
|
||||
password: values.password,
|
||||
}).then(() => {
|
||||
history.go('/dashboard/homepage');
|
||||
}).catch((errors) => {
|
||||
const toastBuilders = [];
|
||||
if (errors.find((e) => e.type === ERRORS_TYPES.INVALID_DETAILS)) {
|
||||
toastBuilders.push({
|
||||
message: intl.formatMessage({ id: 'invalid_email_or_phone_numner' }),
|
||||
intent: Intent.WARNING,
|
||||
});
|
||||
}
|
||||
if (errors.find((e) => e.type === ERRORS_TYPES.USER_INACTIVE)) {
|
||||
toastBuilders.push({
|
||||
message: intl.formatMessage({ id: 'the_user_has_been_suspended_from_admin' }),
|
||||
intent: Intent.WARNING,
|
||||
});
|
||||
}
|
||||
toastBuilders.forEach(builder => {
|
||||
AuthenticationToaster.show(builder);
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const toastBuilders = [];
|
||||
if (hasError(ERRORS_TYPES.INVALID_DETAILS)) {
|
||||
toastBuilders.push({
|
||||
message: intl.formatMessage({ id: 'invalid_email_or_phone_numner' }),
|
||||
intent: Intent.WARNING,
|
||||
});
|
||||
}
|
||||
if (hasError(ERRORS_TYPES.USER_INACTIVE)) {
|
||||
toastBuilders.push({
|
||||
message: intl.formatMessage({ id: 'the_user_has_been_suspended_from_admin' }),
|
||||
intent: Intent.WARNING,
|
||||
});
|
||||
}
|
||||
toastBuilders.forEach(builder => {
|
||||
AuthenticationToaster.show(builder);
|
||||
});
|
||||
}, [hasError, intl]);
|
||||
|
||||
// Handle unmount component
|
||||
useEffect(() => () => {
|
||||
if (errors.length > 0) {
|
||||
clearErrors();
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="login-page">
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
|
||||
@@ -12,17 +12,17 @@ import moment from 'moment';
|
||||
import {momentFormatter} from 'utils';
|
||||
import Icon from 'components/Icon';
|
||||
import CurrenciesSelectList from 'components/CurrenciesSelectList';
|
||||
|
||||
import ErrorMessage from 'components/ErrorMessage';
|
||||
|
||||
export default function MakeJournalEntriesHeader({
|
||||
formik
|
||||
formik: { errors, touched, setFieldValue, getFieldProps }
|
||||
}) {
|
||||
const intl = useIntl();
|
||||
|
||||
const handleDateChange = useCallback((date) => {
|
||||
const formatted = moment(date).format('YYYY-MM-DD');
|
||||
formik.setFieldValue('date', formatted);
|
||||
}, [formik]);
|
||||
setFieldValue('date', formatted);
|
||||
}, [setFieldValue]);
|
||||
|
||||
const infoIcon = useMemo(() =>
|
||||
(<Icon icon="info-circle" iconSize={12} />), []);
|
||||
@@ -35,22 +35,22 @@ export default function MakeJournalEntriesHeader({
|
||||
label={'Journal number'}
|
||||
labelInfo={infoIcon}
|
||||
className={'form-group--journal-number'}
|
||||
intent={formik.errors.journal_number && Intent.DANGER}
|
||||
helperText={formik.errors.journal_number && formik.errors.journal_number}
|
||||
intent={(errors.journal_number && touched.journal_number) && Intent.DANGER}
|
||||
helperText={<ErrorMessage name="journal_number" {...{errors, touched}} />}
|
||||
fill={true}>
|
||||
|
||||
<InputGroup
|
||||
intent={formik.errors.journal_number && Intent.DANGER}
|
||||
intent={(errors.journal_number && touched.journal_number) && Intent.DANGER}
|
||||
fill={true}
|
||||
{...formik.getFieldProps('journal_number')} />
|
||||
{...getFieldProps('journal_number')} />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={2}>
|
||||
<FormGroup
|
||||
label={intl.formatMessage({'id': 'date'})}
|
||||
intent={formik.errors.date && Intent.DANGER}
|
||||
helperText={formik.errors.date && formik.errors.date}
|
||||
intent={(errors.date && touched.date) && Intent.DANGER}
|
||||
helperText={<ErrorMessage name="date" {...{errors, touched}} />}
|
||||
minimal={true}>
|
||||
|
||||
<DateInput
|
||||
@@ -65,14 +65,14 @@ export default function MakeJournalEntriesHeader({
|
||||
<FormGroup
|
||||
label={intl.formatMessage({'id': 'description'})}
|
||||
className={'form-group--description'}
|
||||
intent={formik.errors.name && Intent.DANGER}
|
||||
helperText={formik.errors.name && formik.errors.label}
|
||||
intent={(errors.name && touched.name) && Intent.DANGER}
|
||||
helperText={<ErrorMessage name="description" {...{errors, touched}} />}
|
||||
fill={true}>
|
||||
|
||||
<InputGroup
|
||||
intent={formik.errors.name && Intent.DANGER}
|
||||
intent={(errors.name && touched.name) && Intent.DANGER}
|
||||
fill={true}
|
||||
{...formik.getFieldProps('description')} />
|
||||
{...getFieldProps('description')} />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
@@ -83,14 +83,14 @@ export default function MakeJournalEntriesHeader({
|
||||
label={'Reference'}
|
||||
labelInfo={infoIcon}
|
||||
className={'form-group--reference'}
|
||||
intent={formik.errors.reference && Intent.DANGER}
|
||||
helperText={formik.errors.reference && formik.errors.reference}
|
||||
intent={(errors.reference && touched.reference) && Intent.DANGER}
|
||||
helperText={<ErrorMessage name="reference" {...{errors, touched}} />}
|
||||
fill={true}>
|
||||
|
||||
<InputGroup
|
||||
intent={formik.errors.reference && Intent.DANGER}
|
||||
intent={(errors.reference && touched.reference) && Intent.DANGER}
|
||||
fill={true}
|
||||
{...formik.getFieldProps('reference')} />
|
||||
{...getFieldProps('reference')} />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, {useMemo, useCallback} from 'react';
|
||||
import { useParams, useHistory } from 'react-router-dom';
|
||||
import { useAsync } from 'react-use';
|
||||
import MakeJournalEntriesForm from './MakeJournalEntriesForm';
|
||||
import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import DashboardConnect from 'connectors/Dashboard.connector';
|
||||
import {compose} from 'utils';
|
||||
import MakeJournalEntriesConnect from 'connectors/MakeJournalEntries.connect';
|
||||
@@ -36,12 +36,12 @@ function MakeJournalEntriesPage({
|
||||
}, [history]);
|
||||
|
||||
return (
|
||||
<LoadingIndicator loading={fetchJournal.loading} mount={false}>
|
||||
<DashboardInsider loading={fetchJournal.pending} name={'make-journal-page'}>
|
||||
<MakeJournalEntriesForm
|
||||
onFormSubmit={handleFormSubmit}
|
||||
editJournal={editJournal}
|
||||
onCancelForm={handleCancel} />
|
||||
</LoadingIndicator>
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import ManualJournalsViewTabs from 'components/JournalEntry/ManualJournalsViewTabs';
|
||||
import ManualJournalsDataTable from 'components/JournalEntry/ManualJournalsDataTable';
|
||||
import DashboardActionsBar from 'components/JournalEntry/ManualJournalActionsBar';
|
||||
import ManualJournalsActionsBar from 'components/JournalEntry/ManualJournalActionsBar';
|
||||
import ManualJournalsConnect from 'connectors/ManualJournals.connect';
|
||||
import DashboardConnect from 'connectors/Dashboard.connector';
|
||||
import CustomViewConnect from 'connectors/CustomView.connector';
|
||||
@@ -16,13 +16,20 @@ import { compose } from 'utils';
|
||||
|
||||
function ManualJournalsTable({
|
||||
changePageTitle,
|
||||
|
||||
fetchResourceViews,
|
||||
fetchManualJournalsTable,
|
||||
|
||||
requestDeleteManualJournal,
|
||||
requestPublishManualJournal,
|
||||
requestDeleteBulkManualJournals,
|
||||
|
||||
addManualJournalsTableQueries
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const [deleteManualJournal, setDeleteManualJournal] = useState(false);
|
||||
const [selectedRows, setSelectedRows] = useState([]);
|
||||
const [bulkDelete, setBulkDelete] = useState(false);
|
||||
|
||||
const fetchHook = useAsync(async () => {
|
||||
await Promise.all([
|
||||
@@ -32,16 +39,23 @@ function ManualJournalsTable({
|
||||
|
||||
const fetchManualJournalsHook = useAsync(async () => {
|
||||
return fetchManualJournalsTable();
|
||||
}, false);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
changePageTitle('Manual Journals');
|
||||
}, []);
|
||||
}, [changePageTitle]);
|
||||
|
||||
const handleCancelManualJournalDelete = () => {
|
||||
// Handle delete manual journal click.
|
||||
const handleDeleteJournal = useCallback((journal) => {
|
||||
setDeleteManualJournal(journal);
|
||||
}, [setDeleteManualJournal]);
|
||||
|
||||
// Handle cancel delete manual journal.
|
||||
const handleCancelManualJournalDelete = useCallback(() => {
|
||||
setDeleteManualJournal(false);
|
||||
};
|
||||
}, [setDeleteManualJournal]);
|
||||
|
||||
// Handle confirm delete manual journal.
|
||||
const handleConfirmManualJournalDelete = useCallback(() => {
|
||||
requestDeleteManualJournal(deleteManualJournal.id).then(() => {
|
||||
setDeleteManualJournal(false);
|
||||
@@ -49,25 +63,53 @@ function ManualJournalsTable({
|
||||
});
|
||||
}, [deleteManualJournal, requestDeleteManualJournal]);
|
||||
|
||||
const handleBulkDelete = useCallback((accountsIds) => {
|
||||
setBulkDelete(accountsIds);
|
||||
}, [setBulkDelete]);
|
||||
|
||||
const handleConfirmBulkDelete = useCallback(() => {
|
||||
requestDeleteBulkManualJournals(bulkDelete).then(() => {
|
||||
setBulkDelete(false);
|
||||
AppToaster.show({ message: 'the_accounts_have_been_deleted' });
|
||||
}).catch((error) => {
|
||||
setBulkDelete(false);
|
||||
});
|
||||
}, [
|
||||
requestDeleteBulkManualJournals,
|
||||
bulkDelete,
|
||||
]);
|
||||
|
||||
const handleCancelBulkDelete = useCallback(() => {
|
||||
setBulkDelete(false);
|
||||
}, []);
|
||||
|
||||
const handleEditJournal = useCallback((journal) => {
|
||||
history.push(`/dashboard/accounting/manual-journals/${journal.id}/edit`);
|
||||
}, [history]);
|
||||
|
||||
const handleDeleteJournal = useCallback((journal) => {
|
||||
setDeleteManualJournal(journal);
|
||||
}, []);
|
||||
|
||||
// Handle filter change to re-fetch data-table.
|
||||
const handleFilterChanged = useCallback(() => {
|
||||
fetchManualJournalsHook.execute();
|
||||
}, []);
|
||||
}, [fetchManualJournalsHook]);
|
||||
|
||||
// Handle view change to re-fetch data table.
|
||||
const handleViewChanged = useCallback(() => {
|
||||
fetchManualJournalsHook.execute();
|
||||
}, []);
|
||||
}, [fetchManualJournalsHook]);
|
||||
|
||||
const handleFetchData = useCallback(() => {
|
||||
// Handle fetch data of manual jouranls datatable.
|
||||
const handleFetchData = useCallback(({ pageIndex, pageSize, sortBy }) => {
|
||||
addManualJournalsTableQueries({
|
||||
...(sortBy.length > 0) ? {
|
||||
column_sort_by: sortBy[0].id,
|
||||
sort_order: sortBy[0].desc ? 'desc' : 'asc',
|
||||
} : {},
|
||||
});
|
||||
fetchManualJournalsHook.execute();
|
||||
}, []);
|
||||
}, [
|
||||
fetchManualJournalsHook,
|
||||
addManualJournalsTableQueries,
|
||||
]);
|
||||
|
||||
const handlePublishJournal = useCallback((journal) => {
|
||||
requestPublishManualJournal(journal.id).then(() => {
|
||||
@@ -75,9 +117,16 @@ function ManualJournalsTable({
|
||||
})
|
||||
}, [requestPublishManualJournal]);
|
||||
|
||||
// Handle selected rows change.
|
||||
const handleSelectedRowsChange = useCallback((accounts) => {
|
||||
setSelectedRows(accounts);
|
||||
}, [setSelectedRows]);
|
||||
|
||||
return (
|
||||
<DashboardInsider loading={fetchHook.pending} name={'manual-journals'}>
|
||||
<DashboardActionsBar
|
||||
<ManualJournalsActionsBar
|
||||
onBulkDelete={handleBulkDelete}
|
||||
selectedRows={selectedRows}
|
||||
onFilterChanged={handleFilterChanged} />
|
||||
|
||||
<DashboardPageContent>
|
||||
@@ -97,7 +146,8 @@ function ManualJournalsTable({
|
||||
onDeleteJournal={handleDeleteJournal}
|
||||
onFetchData={handleFetchData}
|
||||
onEditJournal={handleEditJournal}
|
||||
onPublishJournal={handlePublishJournal} />
|
||||
onPublishJournal={handlePublishJournal}
|
||||
onSelectedRowsChange={handleSelectedRowsChange} />
|
||||
|
||||
<Alert
|
||||
cancelButtonText='Cancel'
|
||||
@@ -113,6 +163,21 @@ function ManualJournalsTable({
|
||||
able to restore it later, but it will become private to you.
|
||||
</p>
|
||||
</Alert>
|
||||
|
||||
<Alert
|
||||
cancelButtonText='Cancel'
|
||||
confirmButtonText='Move to Trash'
|
||||
icon='trash'
|
||||
intent={Intent.DANGER}
|
||||
isOpen={bulkDelete}
|
||||
onCancel={handleCancelBulkDelete}
|
||||
onConfirm={handleConfirmBulkDelete}
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to move <b>filename</b> to Trash? You will be
|
||||
able to restore it later, but it will become private to you.
|
||||
</p>
|
||||
</Alert>
|
||||
</DashboardPageContent>
|
||||
</DashboardInsider>
|
||||
);
|
||||
|
||||
@@ -26,8 +26,6 @@ function AccountsChart({
|
||||
requestFetchAccountsTable,
|
||||
addAccountsTableQueries,
|
||||
requestDeleteBulkAccounts,
|
||||
setDashboardRequestLoading,
|
||||
setDashboardRequestCompleted,
|
||||
}) {
|
||||
const [deleteAccount, setDeleteAccount] = useState(false);
|
||||
const [inactiveAccount, setInactiveAccount] = useState(false);
|
||||
@@ -36,23 +34,17 @@ function AccountsChart({
|
||||
|
||||
// Fetch accounts resource views and fields.
|
||||
const fetchHook = useAsync(async () => {
|
||||
setDashboardRequestLoading();
|
||||
|
||||
await Promise.all([
|
||||
fetchResourceViews('accounts'),
|
||||
fetchResourceFields('accounts'),
|
||||
]);
|
||||
setDashboardRequestCompleted();
|
||||
});
|
||||
|
||||
// Fetch accounts list according to the given custom view id.
|
||||
const fetchAccountsHook = useAsync(async () => {
|
||||
setDashboardRequestLoading();
|
||||
|
||||
await Promise.all([
|
||||
requestFetchAccountsTable(),
|
||||
]);
|
||||
setDashboardRequestCompleted();
|
||||
}, false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -102,7 +94,7 @@ function AccountsChart({
|
||||
requestFetchAccountsTable();
|
||||
AppToaster.show({ message: 'the_account_has_been_inactivated' });
|
||||
});
|
||||
}, [inactiveAccount]);
|
||||
}, [inactiveAccount, requestFetchAccountsTable, requestInactiveAccount]);
|
||||
|
||||
|
||||
const handleEditAccount = (account) => {
|
||||
|
||||
@@ -8,11 +8,7 @@ import {
|
||||
FormGroup,
|
||||
InputGroup,
|
||||
Intent,
|
||||
TextArea,
|
||||
MenuItem,
|
||||
Checkbox,
|
||||
Classes,
|
||||
HTMLSelect,
|
||||
} from '@blueprintjs/core';
|
||||
import UserFormDialogConnect from 'connectors/UserFormDialog.connector';
|
||||
import DialogReduxConnect from 'components/DialogReduxConnect';
|
||||
@@ -22,7 +18,6 @@ import { objectKeysTransform } from 'utils';
|
||||
import { pick, snakeCase } from 'lodash';
|
||||
import ErrorMessage from 'components/ErrorMessage';
|
||||
import classNames from 'classnames';
|
||||
import Icon from 'components/Icon';
|
||||
import { compose } from 'utils';
|
||||
|
||||
function UserFormDialog({
|
||||
@@ -32,7 +27,6 @@ function UserFormDialog({
|
||||
name,
|
||||
payload,
|
||||
isOpen,
|
||||
userDetails,
|
||||
closeDialog,
|
||||
}) {
|
||||
const intl = useIntl();
|
||||
@@ -84,11 +78,6 @@ function UserFormDialog({
|
||||
});
|
||||
const { values, errors, touched } = useMemo(() => formik, [formik]);
|
||||
|
||||
const statusOptions = [
|
||||
{ value: 1, label: 'Active' },
|
||||
{ value: 2, label: 'Inactive' },
|
||||
];
|
||||
|
||||
const onDialogOpening = () => {
|
||||
fetchHook.execute();
|
||||
};
|
||||
|
||||
@@ -15,11 +15,12 @@ const ItemFormContainer = ({
|
||||
requestFetchItemCategories,
|
||||
}) => {
|
||||
const { id } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
id ?
|
||||
changePageTitle('Edit Item Details') :
|
||||
changePageTitle('New Item');
|
||||
}, []);
|
||||
}, [id, changePageTitle]);
|
||||
|
||||
const fetchHook = useAsync(async () => {
|
||||
await Promise.all([
|
||||
|
||||
@@ -29,8 +29,8 @@ const ItemsActionsBar = ({
|
||||
getResourceViews,
|
||||
views,
|
||||
onFilterChanged,
|
||||
bulkSelected,
|
||||
addItemsTableQueries,
|
||||
selectedRows = [],
|
||||
}) => {
|
||||
const { path } = useRouteMatch();
|
||||
const history = useHistory();
|
||||
@@ -43,6 +43,7 @@ const ItemsActionsBar = ({
|
||||
history.push('/dashboard/items/new');
|
||||
};
|
||||
const itemsFields = getResourceFields('items');
|
||||
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [selectedRows]);
|
||||
|
||||
const filterDropdown = FilterDropdown({
|
||||
fields: itemsFields,
|
||||
@@ -54,12 +55,7 @@ const ItemsActionsBar = ({
|
||||
onFilterChanged && onFilterChanged(filterConditions);
|
||||
}
|
||||
});
|
||||
|
||||
const hasBulkActionsSelected = useMemo(
|
||||
() => !!Object.keys(bulkSelected).length,
|
||||
[bulkSelected]
|
||||
);
|
||||
|
||||
|
||||
const onClickNewCategory = useCallback(() => {
|
||||
openDialog('item-form', {});
|
||||
}, [openDialog]);
|
||||
@@ -108,7 +104,7 @@ const ItemsActionsBar = ({
|
||||
onClick={onClickNewCategory}
|
||||
/>
|
||||
|
||||
{hasBulkActionsSelected && (
|
||||
{hasSelectedRows && (
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
intent={Intent.DANGER}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import {} from 'reselect';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
||||
|
||||
import { compose } from 'utils';
|
||||
import {
|
||||
NavbarGroup,
|
||||
@@ -20,21 +18,24 @@ import DialogConnect from 'connectors/Dialog.connector';
|
||||
import FilterDropdown from 'components/FilterDropdown';
|
||||
import ResourceConnect from 'connectors/Resource.connector';
|
||||
|
||||
|
||||
const ItemsCategoryActionsBar = ({
|
||||
openDialog,
|
||||
onDeleteCategory,
|
||||
onFilterChanged,
|
||||
getResourceFields,
|
||||
selectedRows,
|
||||
}) => {
|
||||
const onClickNewCategory = () => {
|
||||
const onClickNewCategory = useCallback(() => {
|
||||
openDialog('item-form', {});
|
||||
};
|
||||
}, [openDialog]);
|
||||
|
||||
const handleDeleteCategory = (category) => {
|
||||
onDeleteCategory(category);
|
||||
};
|
||||
const handleDeleteCategory = useCallback((category) => {
|
||||
onDeleteCategory(selectedRows);
|
||||
}, [selectedRows, onDeleteCategory]);
|
||||
|
||||
const categoriesFields = getResourceFields('itemCategories');
|
||||
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [selectedRows]);
|
||||
|
||||
const filterDropdown = FilterDropdown({
|
||||
fields: categoriesFields,
|
||||
@@ -63,14 +64,15 @@ const ItemsCategoryActionsBar = ({
|
||||
/>
|
||||
</Popover>
|
||||
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon='trash' iconSize={15} />}
|
||||
text='Delete Category'
|
||||
intent={Intent.DANGER}
|
||||
onClick={handleDeleteCategory}
|
||||
/>
|
||||
|
||||
{ hasSelectedRows && (
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon='trash' iconSize={15} />}
|
||||
text='Delete'
|
||||
intent={Intent.DANGER}
|
||||
onClick={handleDeleteCategory}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon='file-import' />}
|
||||
|
||||
@@ -20,25 +20,29 @@ const ItemCategoriesList = ({
|
||||
}) => {
|
||||
const { id } = useParams();
|
||||
const [deleteCategory, setDeleteCategory] = useState(false);
|
||||
const [selectedRows, setSelectedRows] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
id
|
||||
? changePageTitle('Edit Item Details')
|
||||
: changePageTitle('Categories List');
|
||||
}, []);
|
||||
}, [id, changePageTitle]);
|
||||
|
||||
const fetchHook = useAsync(async () => {
|
||||
await Promise.all([requestFetchItemCategories()]);
|
||||
await Promise.all([
|
||||
requestFetchItemCategories(),
|
||||
]);
|
||||
}, false);
|
||||
|
||||
const handelDeleteCategory = category => {
|
||||
const handelDeleteCategory = useCallback((category) => {
|
||||
setDeleteCategory(category);
|
||||
};
|
||||
}, [setDeleteCategory]);
|
||||
|
||||
const handelEditCategory = category => {};
|
||||
const handelCancelCategoryDelete = () => {
|
||||
|
||||
const handelCancelCategoryDelete = useCallback(() => {
|
||||
setDeleteCategory(false);
|
||||
};
|
||||
}, [setDeleteCategory]);
|
||||
|
||||
const handelConfirmCategoryDelete = useCallback(() => {
|
||||
requestDeleteItemCategory(deleteCategory.id).then(() => {
|
||||
@@ -47,23 +51,30 @@ const ItemCategoriesList = ({
|
||||
message: 'the_category_has_been_delete'
|
||||
});
|
||||
});
|
||||
}, [deleteCategory]);
|
||||
}, [deleteCategory, requestDeleteItemCategory, setDeleteCategory]);
|
||||
|
||||
const handleFetchData = useCallback(() => {
|
||||
fetchHook.execute();
|
||||
}, []);
|
||||
|
||||
// Handle selected rows change.
|
||||
const handleSelectedRowsChange = useCallback((accounts) => {
|
||||
setSelectedRows(accounts);
|
||||
}, [setSelectedRows]);
|
||||
|
||||
return (
|
||||
<DashboardInsider loading={fetchHook.pending}>
|
||||
<ItemsCategoryActionsBar
|
||||
views={views}
|
||||
onDeleteCategory={handelDeleteCategory}
|
||||
selectedRows={selectedRows}
|
||||
/>
|
||||
<DashboardPageContent>
|
||||
<ItemsCategoryList
|
||||
onDeleteCategory={handelDeleteCategory}
|
||||
onFetchData={handleFetchData}
|
||||
onEditCategory={handelEditCategory}
|
||||
categories
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
/>
|
||||
|
||||
<Alert
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useEffect, useCallback, useMemo} from 'react';
|
||||
import React, {useState, useEffect, useCallback, useMemo} from 'react';
|
||||
import {
|
||||
Button,
|
||||
Popover,
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
MenuDivider,
|
||||
Position,
|
||||
} from '@blueprintjs/core'
|
||||
import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import CustomViewConnect from 'connectors/View.connector';
|
||||
import ItemsConnect from 'connectors/Items.connect';
|
||||
import {compose} from 'utils';
|
||||
@@ -22,7 +21,16 @@ const ItemsDataTable = ({
|
||||
onEditItem,
|
||||
onDeleteItem,
|
||||
onFetchData,
|
||||
onSelectedRowsChange,
|
||||
}) => {
|
||||
const [initialMount, setInitialMount] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!itemsTableLoading) {
|
||||
setInitialMount(true);
|
||||
}
|
||||
}, [itemsTableLoading, setInitialMount]);
|
||||
|
||||
const handleEditItem = (item) => () => { onEditItem(item); };
|
||||
const handleDeleteItem = (item) => () => { onDeleteItem(item); };
|
||||
|
||||
@@ -75,7 +83,6 @@ const ItemsDataTable = ({
|
||||
// accessor: 'inventory_account.name',
|
||||
// className: "inventory-account",
|
||||
// },
|
||||
|
||||
{
|
||||
id: 'actions',
|
||||
Cell: ({ cell }) => (
|
||||
@@ -98,16 +105,21 @@ const ItemsDataTable = ({
|
||||
|
||||
const handleFetchData = useCallback((...args) => {
|
||||
onFetchData && onFetchData(...args)
|
||||
}, [onFetchData])
|
||||
}, [onFetchData]);
|
||||
|
||||
const handleSelectedRowsChange = useCallback((selectedRows) => {
|
||||
onSelectedRowsChange && onSelectedRowsChange(selectedRows.map(s => s.original));
|
||||
}, [onSelectedRowsChange]);
|
||||
|
||||
return (
|
||||
<LoadingIndicator loading={itemsTableLoading} spinnerSize={30}>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={currentPageItems}
|
||||
selectionColumn={selectionColumn}
|
||||
onFetchData={handleFetchData} />
|
||||
</LoadingIndicator>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={currentPageItems}
|
||||
selectionColumn={selectionColumn}
|
||||
onFetchData={handleFetchData}
|
||||
loading={itemsTableLoading && !initialMount}
|
||||
noInitialFetch={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange} />
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ function ItemsList({
|
||||
addItemsTableQueries,
|
||||
}) {
|
||||
const [deleteItem, setDeleteItem] = useState(false);
|
||||
const [selectedRows, setSelectedRows] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
changePageTitle('Items List');
|
||||
@@ -49,16 +50,19 @@ function ItemsList({
|
||||
])
|
||||
});
|
||||
|
||||
// Handle click delete item.
|
||||
const handleDeleteItem = useCallback((item) => {
|
||||
setDeleteItem(item);
|
||||
}, [setDeleteItem]);
|
||||
|
||||
const handleEditItem = () => {};
|
||||
|
||||
// Handle cancel delete the item.
|
||||
const handleCancelDeleteItem = useCallback(() => {
|
||||
setDeleteItem(false);
|
||||
}, [setDeleteItem]);
|
||||
|
||||
// handle confirm delete item.
|
||||
const handleConfirmDeleteItem = useCallback(() => {
|
||||
requestDeleteItem(deleteItem.id).then(() => {
|
||||
AppToaster.show({ message: 'the_item_has_been_deleted' });
|
||||
@@ -69,25 +73,33 @@ function ItemsList({
|
||||
const handleFetchData = useCallback(({ pageIndex, pageSize, sortBy }) => {
|
||||
addItemsTableQueries({
|
||||
...(sortBy.length > 0) ? {
|
||||
column_sort_by: sortBy[0].id,
|
||||
sort_by: sortBy[0].desc ? 'desc' : 'asc',
|
||||
column_sort_order: sortBy[0].id,
|
||||
sort_order: sortBy[0].desc ? 'desc' : 'asc',
|
||||
} : {},
|
||||
});
|
||||
fetchItems.execute();
|
||||
}, [fetchItems, addItemsTableQueries]);
|
||||
|
||||
// Handle filter change to re-fetch the items.
|
||||
const handleFilterChanged = useCallback(() => {
|
||||
fetchItems.execute();
|
||||
}, [fetchItems]);
|
||||
|
||||
// Handle custom view change to re-fetch the items.
|
||||
const handleCustomViewChanged = useCallback(() => {
|
||||
fetchItems.execute();
|
||||
}, [fetchItems]);
|
||||
|
||||
// Handle selected rows change.
|
||||
const handleSelectedRowsChange = useCallback((accounts) => {
|
||||
setSelectedRows(accounts);
|
||||
}, [setSelectedRows]);
|
||||
|
||||
return (
|
||||
<DashboardInsider isLoading={fetchHook.pending} name={'items-list'}>
|
||||
<ItemsActionsBar
|
||||
onFilterChanged={handleFilterChanged}
|
||||
selectedRows={selectedRows}
|
||||
views={views} />
|
||||
|
||||
<DashboardPageContent>
|
||||
@@ -98,12 +110,14 @@ function ItemsList({
|
||||
'/dashboard/items/:custom_view_id/custom_view',
|
||||
'/dashboard/items'
|
||||
]}>
|
||||
<ItemsViewsTabs onViewChanged={handleCustomViewChanged} />
|
||||
<ItemsViewsTabs
|
||||
onViewChanged={handleCustomViewChanged} />
|
||||
|
||||
<ItemsDataTable
|
||||
onDeleteItem={handleDeleteItem}
|
||||
onEditItem={handleEditItem}
|
||||
onFetchData={handleFetchData} />
|
||||
onFetchData={handleFetchData}
|
||||
onSelectedRowsChange={handleSelectedRowsChange} />
|
||||
|
||||
<Alert
|
||||
cancelButtonText="Cancel"
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
import React from 'react';
|
||||
import React, {useCallback} from 'react';
|
||||
import {
|
||||
Tabs,
|
||||
Tab,
|
||||
Button,
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import PreferencesSubContent from 'components/Preferences/PreferencesSubContent';
|
||||
import connector from 'connectors/UsersPreferences.connector';
|
||||
|
||||
function UsersPreferences({
|
||||
openDialog,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const onChangeTabs = (currentTabId) => {
|
||||
|
||||
};
|
||||
|
||||
const onClickNewUser = () => {
|
||||
const onClickNewUser = useCallback(() => {
|
||||
openDialog('user-form');
|
||||
};
|
||||
}, [openDialog]);
|
||||
|
||||
return (
|
||||
<div class="preferences__inside-content preferences__inside-content--users-roles">
|
||||
<div class="preferences__tabs">
|
||||
|
||||
@@ -5,6 +5,7 @@ import { BrowserRouter } from 'react-router-dom';
|
||||
import App from 'components/App';
|
||||
import * as serviceWorker from 'serviceWorker';
|
||||
import createStore from 'store/createStore';
|
||||
import AppProgress from 'components/NProgress/AppProgress';
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={createStore}>
|
||||
@@ -15,6 +16,13 @@ ReactDOM.render(
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={createStore}>
|
||||
<AppProgress />
|
||||
</Provider>,
|
||||
document.getElementById('nprogress')
|
||||
);
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
// unregister() to register() below. Note this comes with some pitfalls.
|
||||
// Learn more about service workers: https://bit.ly/CRA-PWA
|
||||
|
||||
@@ -14,7 +14,7 @@ export default [
|
||||
path: `${BASE_URL}/register`,
|
||||
name: 'auth.register',
|
||||
component: LazyLoader({
|
||||
loader: () => import('containers/Authentication/Register'),
|
||||
loader: () => import('containers/Authentication/Register'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -6,17 +6,14 @@ export default [
|
||||
// Homepage
|
||||
{
|
||||
path: `${BASE_URL}/homepage`,
|
||||
name: 'dashboard.homepage',
|
||||
component: LazyLoader({
|
||||
loader: () => import('containers/Dashboard/Homepage')
|
||||
}),
|
||||
exact: true
|
||||
},
|
||||
|
||||
// Accounts.
|
||||
{
|
||||
path: `${BASE_URL}/accounts`,
|
||||
name: 'dashboard.accounts',
|
||||
component: LazyLoader({
|
||||
loader: () => import('containers/Dashboard/Accounts/AccountsChart')
|
||||
})
|
||||
@@ -25,14 +22,12 @@ export default [
|
||||
// Custom views.
|
||||
{
|
||||
path: `${BASE_URL}/custom_views/:resource_slug/new`,
|
||||
name: 'dashboard.custom_view.new',
|
||||
component: LazyLoader({
|
||||
loader: () => import('containers/Dashboard/Views/ViewFormPage')
|
||||
})
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/custom_views/:view_id/edit`,
|
||||
name: 'dashboard.custom_view.edit',
|
||||
component: LazyLoader({
|
||||
loader: () => import('containers/Dashboard/Views/ViewFormPage')
|
||||
})
|
||||
@@ -41,15 +36,12 @@ export default [
|
||||
// Expenses.
|
||||
{
|
||||
path: `${BASE_URL}/expenses/new`,
|
||||
name: 'dashboard.expense.new',
|
||||
component: LazyLoader({
|
||||
loader: () => import('containers/Dashboard/Expenses/ExpenseForm')
|
||||
}),
|
||||
text: 'New Expense'
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/expenses`,
|
||||
name: 'dashboard.expeneses.list',
|
||||
component: LazyLoader({
|
||||
loader: () => import('containers/Dashboard/Expenses/ExpensesList')
|
||||
})
|
||||
@@ -58,39 +50,31 @@ export default [
|
||||
// Accounting
|
||||
{
|
||||
path: `${BASE_URL}/accounting/make-journal-entry`,
|
||||
name: 'dashboard.accounting.make.journal',
|
||||
component: LazyLoader({
|
||||
loader: () =>
|
||||
import('containers/Dashboard/Accounting/MakeJournalEntriesPage')
|
||||
}),
|
||||
text: 'Make Journal Entry'
|
||||
},
|
||||
|
||||
{
|
||||
path: `${BASE_URL}/accounting/manual-journals/:id/edit`,
|
||||
name: 'dashboard.manual.journal.edit',
|
||||
component: LazyLoader({
|
||||
loader: () =>
|
||||
import('containers/Dashboard/Accounting/MakeJournalEntriesPage')
|
||||
}),
|
||||
},
|
||||
|
||||
{
|
||||
path: `${BASE_URL}/accounting/manual-journals`,
|
||||
component: LazyLoader({
|
||||
loader: () =>
|
||||
import('containers/Dashboard/Accounting/ManualJournalsTable')
|
||||
}),
|
||||
text: 'Manual Journals'
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/items/categories`,
|
||||
component: LazyLoader({
|
||||
loader: () => import('containers/Dashboard/Items/ItemsCategoryList')
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/items/new`,
|
||||
component: LazyLoader({
|
||||
@@ -109,7 +93,6 @@ export default [
|
||||
// Financial Reports.
|
||||
{
|
||||
path: `${BASE_URL}/accounting/general-ledger`,
|
||||
name: 'dashboard.accounting.general.ledger',
|
||||
component: LazyLoader({
|
||||
loader: () =>
|
||||
import(
|
||||
@@ -119,7 +102,6 @@ export default [
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/accounting/balance-sheet`,
|
||||
name: 'dashboard.accounting.balance.sheet',
|
||||
component: LazyLoader({
|
||||
loader: () =>
|
||||
import(
|
||||
@@ -129,7 +111,6 @@ export default [
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/accounting/trial-balance-sheet`,
|
||||
name: 'dashboard.accounting.trial.balance',
|
||||
component: LazyLoader({
|
||||
loader: () =>
|
||||
import(
|
||||
@@ -139,7 +120,6 @@ export default [
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/accounting/profit-loss-sheet`,
|
||||
name: 'dashboard.accounting.profit.loss.sheet',
|
||||
component: LazyLoader({
|
||||
loader: () =>
|
||||
import(
|
||||
@@ -149,10 +129,9 @@ export default [
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/accounting/journal-sheet`,
|
||||
name: 'dashboard.accounting.journal.sheet',
|
||||
component: LazyLoader({
|
||||
loader: () =>
|
||||
import('containers/Dashboard/FinancialStatements/Journal/Journal')
|
||||
})
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
@@ -18,25 +18,32 @@ export const fetchAccountTypes = () => {
|
||||
};
|
||||
|
||||
export const fetchAccountsList = ({ query } = {}) => {
|
||||
return dispatch =>
|
||||
new Promise((resolve, reject) => {
|
||||
ApiService.get('accounts', { params: query })
|
||||
.then(response => {
|
||||
dispatch({
|
||||
type: t.ACCOUNTS_PAGE_SET,
|
||||
accounts: response.data.accounts,
|
||||
customViewId: response.data.customViewId
|
||||
});
|
||||
dispatch({
|
||||
type: t.ACCOUNTS_ITEMS_SET,
|
||||
accounts: response.data.accounts
|
||||
});
|
||||
resolve(response);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
return dispatch => new Promise((resolve, reject) => {
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_LOADING,
|
||||
});
|
||||
ApiService.get('accounts', { params: query }).then(response => {
|
||||
dispatch({
|
||||
type: t.ACCOUNTS_PAGE_SET,
|
||||
accounts: response.data.accounts,
|
||||
customViewId: response.data.customViewId
|
||||
});
|
||||
dispatch({
|
||||
type: t.ACCOUNTS_ITEMS_SET,
|
||||
accounts: response.data.accounts
|
||||
});
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
resolve(response);
|
||||
})
|
||||
.catch((error) => {
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchAccountsTable = ({ query } = {}) => {
|
||||
@@ -54,6 +61,9 @@ export const fetchAccountsTable = ({ query } = {}) => {
|
||||
type: t.ACCOUNTS_TABLE_LOADING,
|
||||
loading: true,
|
||||
});
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_LOADING,
|
||||
});
|
||||
ApiService.get('accounts', { params: { ...pageQuery, ...query } })
|
||||
.then((response) => {
|
||||
dispatch({
|
||||
@@ -69,9 +79,15 @@ export const fetchAccountsTable = ({ query } = {}) => {
|
||||
type: t.ACCOUNTS_TABLE_LOADING,
|
||||
loading: false,
|
||||
});
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
resolve(response);
|
||||
})
|
||||
.catch((error) => {
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
@@ -96,12 +112,17 @@ export const fetchAccountsDataTable = ({ query }) => {
|
||||
export const submitAccount = ({ form }) => {
|
||||
return dispatch =>
|
||||
new Promise((resolve, reject) => {
|
||||
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_LOADING,
|
||||
});
|
||||
ApiService.post('accounts', form)
|
||||
.then(response => {
|
||||
dispatch({
|
||||
type: t.ACCOUNT_ERRORS_CLEAR,
|
||||
});
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
resolve(response);
|
||||
})
|
||||
.catch(error => {
|
||||
@@ -118,31 +139,42 @@ export const submitAccount = ({ form }) => {
|
||||
payload: { errors },
|
||||
});
|
||||
}
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
reject(errors);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const editAccount = ({ id, form }) => {
|
||||
return dispatch =>
|
||||
new Promise((resolve, reject) => {
|
||||
ApiService.post(`accounts/${id}`, form)
|
||||
.then(response => {
|
||||
dispatch({ type: t.CLEAR_ACCOUNT_FORM_ERRORS });
|
||||
resolve(response);
|
||||
})
|
||||
.catch(error => {
|
||||
const { response } = error;
|
||||
const { data } = response;
|
||||
const { errors } = data;
|
||||
|
||||
dispatch({ type: t.CLEAR_ACCOUNT_FORM_ERRORS });
|
||||
if (errors) {
|
||||
dispatch({ type: t.ACCOUNT_FORM_ERRORS, errors });
|
||||
}
|
||||
reject(errors);
|
||||
});
|
||||
return dispatch => new Promise((resolve, reject) => {
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_LOADING,
|
||||
});
|
||||
ApiService.post(`accounts/${id}`, form)
|
||||
.then(response => {
|
||||
dispatch({ type: t.CLEAR_ACCOUNT_FORM_ERRORS });
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
resolve(response);
|
||||
})
|
||||
.catch(error => {
|
||||
const { response } = error;
|
||||
const { data } = response;
|
||||
const { errors } = data;
|
||||
|
||||
dispatch({ type: t.CLEAR_ACCOUNT_FORM_ERRORS });
|
||||
if (errors) {
|
||||
dispatch({ type: t.ACCOUNT_FORM_ERRORS, errors });
|
||||
}
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
reject(errors);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const activeAccount = ({ id }) => {
|
||||
|
||||
@@ -21,16 +21,9 @@ export default function login({ form }) {
|
||||
}).catch((error) => {
|
||||
const { response } = error;
|
||||
const { data } = response;
|
||||
const { errors } = data;
|
||||
const { errors = [] } = data;
|
||||
|
||||
dispatch({type: t.LOGIN_CLEAR_ERRORS});
|
||||
|
||||
if (errors){
|
||||
dispatch({
|
||||
type: t.LOGIN_FAILURE, errors,
|
||||
});
|
||||
}
|
||||
reject(error);
|
||||
reject(errors);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,20 +8,25 @@ export const submitItemCategory = ({ form }) => {
|
||||
};
|
||||
|
||||
export const fetchItemCategories = () => {
|
||||
return (dispatch, getState) =>
|
||||
new Promise((resolve, reject) => {
|
||||
ApiService.get('item_categories')
|
||||
.then((response) => {
|
||||
dispatch({
|
||||
type: t.ITEMS_CATEGORY_LIST_SET,
|
||||
categories: response.data.categories,
|
||||
});
|
||||
resolve(response);
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error);
|
||||
});
|
||||
return (dispatch, getState) => new Promise((resolve, reject) => {
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_LOADING,
|
||||
});
|
||||
ApiService.get('item_categories')
|
||||
.then((response) => {
|
||||
dispatch({
|
||||
type: t.ITEMS_CATEGORY_LIST_SET,
|
||||
categories: response.data.categories,
|
||||
});
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
resolve(response);
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const editItemCategory = (id, form) => {
|
||||
|
||||
@@ -11,12 +11,15 @@ export const editItem = ({ id, form }) => {
|
||||
|
||||
export const fetchItems = ({ query }) => {
|
||||
return (dispatch, getState) => new Promise((resolve, reject) => {
|
||||
const pageQuery = getState().accounts.tableQuery;
|
||||
const pageQuery = getState().items.tableQuery;
|
||||
|
||||
dispatch({
|
||||
type: t.ITEMS_TABLE_LOADING,
|
||||
payload: { loading: true },
|
||||
});
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_LOADING,
|
||||
});
|
||||
ApiService.get(`items`, { params: { ...pageQuery, ...query } }).then(response => {
|
||||
dispatch({
|
||||
type: t.ITEMS_SET,
|
||||
@@ -32,8 +35,16 @@ export const fetchItems = ({ query }) => {
|
||||
type: t.ITEMS_TABLE_LOADING,
|
||||
payload: { loading: false },
|
||||
});
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
resolve(response);
|
||||
}).catch(error => { reject(error); });
|
||||
}).catch((error) => {
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -47,6 +47,22 @@ export const deleteManualJournal = ({ id }) => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
export const deleteBulkManualJournals = ({ ids }) => {
|
||||
return (dispatch) => new Promise((resolve, reject) => {
|
||||
ApiService.delete('accounting/manual-journals', { params: { ids } })
|
||||
.then((response) => {
|
||||
dispatch({
|
||||
type: t.MANUAL_JOURNALS_BULK_DELETE,
|
||||
payload: { ids },
|
||||
});
|
||||
resolve(response);
|
||||
}).catch((error) => {
|
||||
reject(error.response.data.errors || []);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const publishManualJournal = ({ id }) => {
|
||||
return (dispatch) =>
|
||||
new Promise((resolve, reject) => {
|
||||
@@ -66,6 +82,9 @@ export const fetchManualJournalsTable = ({ query } = {}) => {
|
||||
return (dispatch, getState) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const pageQuery = getState().manualJournals.tableQuery;
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_LOADING,
|
||||
});
|
||||
dispatch({
|
||||
type: t.MANUAL_JOURNALS_TABLE_LOADING,
|
||||
loading: true,
|
||||
@@ -74,20 +93,22 @@ export const fetchManualJournalsTable = ({ query } = {}) => {
|
||||
params: { ...pageQuery, ...query },
|
||||
})
|
||||
.then((response) => {
|
||||
|
||||
dispatch({
|
||||
type: t.MANUAL_JOURNALS_PAGE_SET,
|
||||
manual_journals: response.data.manualJournals,
|
||||
customViewId: response.data.customViewId,
|
||||
manual_journals: response.data.manualJournals.results,
|
||||
customViewId: response.data.customViewId || -1,
|
||||
});
|
||||
dispatch({
|
||||
type: t.MANUAL_JOURNALS_ITEMS_SET,
|
||||
manual_journals: response.data.manualJournals,
|
||||
manual_journals: response.data.manualJournals.results,
|
||||
});
|
||||
dispatch({
|
||||
type: t.MANUAL_JOURNALS_TABLE_LOADING,
|
||||
loading: false,
|
||||
});
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
resolve(response);
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import t from 'store/types';
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { createTableQueryReducers } from 'store/queryReducers';
|
||||
import { omit } from 'lodash';
|
||||
|
||||
const initialState = {
|
||||
@@ -10,7 +11,7 @@ const initialState = {
|
||||
tableQuery: {},
|
||||
};
|
||||
|
||||
export default createReducer(initialState, {
|
||||
const reducer = createReducer(initialState, {
|
||||
|
||||
[t.MANUAL_JOURNAL_SET]: (state, action) => {
|
||||
const { id, manualJournal } = action.payload;
|
||||
@@ -59,9 +60,22 @@ export default createReducer(initialState, {
|
||||
[t.MANUAL_JOURNAL_REMOVE]: (state, action) => {
|
||||
const { id } = action.payload;
|
||||
state.items = omit(state.items, [id]);
|
||||
}
|
||||
},
|
||||
|
||||
[t.MANUAL_JOURNALS_BULK_DELETE]: (state, action) => {
|
||||
const { ids } = action.payload;
|
||||
const items = { ...state.items };
|
||||
|
||||
ids.forEach((id) => {
|
||||
if (typeof items[id] !== 'undefined') {
|
||||
delete items[id];
|
||||
}
|
||||
});
|
||||
state.items = items;
|
||||
},
|
||||
});
|
||||
|
||||
export default createTableQueryReducers('manual_journals', reducer);
|
||||
|
||||
export const getManualJournal = (state, id) => {
|
||||
return state.manualJournals.items[id];
|
||||
|
||||
@@ -10,4 +10,5 @@ export default {
|
||||
MANUAL_JOURNAL_REMOVE: 'MANUAL_JOURNAL_REMOVE',
|
||||
|
||||
MANUAL_JOURNAL_PUBLISH: 'MANUAL_JOURNAL_PUBLISH',
|
||||
MANUAL_JOURNALS_BULK_DELETE: 'MANUAL_JOURNALS_BULK_DELETE',
|
||||
};
|
||||
|
||||
@@ -3,12 +3,18 @@ import t from 'store/types';
|
||||
|
||||
export const fetchResourceColumns = ({ resourceSlug }) => {
|
||||
return (dispatch) => new Promise((resolve, reject) => {
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_LOADING,
|
||||
});
|
||||
ApiService.get(`resources/${resourceSlug}/columns`).then((response) => {
|
||||
dispatch({
|
||||
type: t.RESOURCE_COLUMNS_SET,
|
||||
columns: response.data.resource_columns,
|
||||
resource_slug: resourceSlug,
|
||||
});
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
resolve(response);
|
||||
}).catch((error) => { reject(error); });
|
||||
});
|
||||
@@ -16,12 +22,18 @@ export const fetchResourceColumns = ({ resourceSlug }) => {
|
||||
|
||||
export const fetchResourceFields = ({ resourceSlug }) => {
|
||||
return (dispatch) => new Promise((resolve, reject) => {
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_LOADING,
|
||||
});
|
||||
ApiService.get(`resources/${resourceSlug}/fields`).then((response) => {
|
||||
dispatch({
|
||||
type: t.RESOURCE_FIELDS_SET,
|
||||
fields: response.data.resource_fields,
|
||||
resource_slug: resourceSlug,
|
||||
});
|
||||
dispatch({
|
||||
type: t.SET_DASHBOARD_REQUEST_COMPLETED,
|
||||
});
|
||||
resolve(response);
|
||||
}).catch((error) => { reject(error); });
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ export const pickItemsFromIds = (items, ids) => {
|
||||
export const getCurrentPageResults = (items, pages, pageNumber) => {
|
||||
const currentPage = pages[pageNumber]
|
||||
return typeof currentPage == 'undefined' ?
|
||||
[] : Object.values(pick(items || [], currentPage.ids));
|
||||
[] : pickItemsFromIds(items, currentPage.ids);
|
||||
}
|
||||
|
||||
export const getCurrentTotalResultsCount = (pagination, name) => {
|
||||
|
||||
@@ -164,7 +164,8 @@
|
||||
|
||||
h1{
|
||||
font-size: 26px;
|
||||
font-weight: 100;
|
||||
font-weight: 200;
|
||||
color: #4d4c4c;
|
||||
margin: 0;
|
||||
}
|
||||
h3{
|
||||
|
||||
@@ -40,7 +40,7 @@ $sidebar-popover-submenu-bg: rgb(1, 20, 62);
|
||||
margin-top: 4px;
|
||||
|
||||
svg{
|
||||
opacity: 0.35;
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user