This commit is contained in:
elforjani3
2020-11-18 15:18:44 +02:00
49 changed files with 1050 additions and 244 deletions

View File

@@ -1,6 +1,7 @@
import { Classes } from '@blueprintjs/core'; import { Classes } from '@blueprintjs/core';
const CLASSES = { const CLASSES = {
DASHBOARD_DATATABLE: 'dashboard__datatable',
DATATABLE_EDITOR: 'datatable-editor', DATATABLE_EDITOR: 'datatable-editor',
DATATABLE_EDITOR_ACTIONS: 'datatable-editor__actions', DATATABLE_EDITOR_ACTIONS: 'datatable-editor__actions',
DATATABLE_EDITOR_ITEMS_ENTRIES: 'items-entries-table', DATATABLE_EDITOR_ITEMS_ENTRIES: 'items-entries-table',
@@ -30,8 +31,11 @@ const CLASSES = {
CLOUD_SPINNER: 'cloud-spinner', CLOUD_SPINNER: 'cloud-spinner',
IS_LOADING: 'is-loading', IS_LOADING: 'is-loading',
DATATABLE_EMPTY_STATE: 'datatable-empty-state', DATATABLE_EMPTY_STATUS: 'datatable-empty-status',
DATATABLE_EMPTY_STATE_TITLE: 'datatable-empty-state__title', DATATABLE_EMPTY_STATUS_TITLE: 'datatable-empty-status__title',
DATATABLE_EMPTY_STATUS_DESC: 'datatable-empty-status__desc',
DATATABLE_EMPTY_STATUS_ACTIONS: 'datatable-empty-status__actions',
...Classes, ...Classes,
}; };

View File

@@ -0,0 +1,22 @@
import React from 'react';
import classNames from 'classnames';
import { CLASSES } from 'common/classes';
export default function EmptyStatuts({ title, description, action, children }) {
return (
<div className={classNames(CLASSES.DATATABLE_EMPTY_STATUS)}>
<h1 className={classNames(CLASSES.DATATABLE_EMPTY_STATUS_TITLE)}>
{title}
</h1>
<div className={classNames(CLASSES.DATATABLE_EMPTY_STATUS_DESC)}>
{description}
</div>
<div className={classNames(CLASSES.DATATABLE_EMPTY_STATUS_ACTIONS)}>
{action}
</div>
{children}
</div>
);
}

View File

@@ -1,39 +1,53 @@
import React, {useState, useEffect, useMemo} from 'react'; import React, { useState, useEffect, useMemo } from 'react';
import { Spinner } from '@blueprintjs/core'; import { Spinner } from '@blueprintjs/core';
export default function LoadingIndicator({ export default function LoadingIndicator({
loading, loading,
spinnerSize = 40, spinnerSize = 40,
children, children,
mount = true, mount = false,
}) { }) {
const [rendered, setRendered] = useState(mount); const [rendered, setRendered] = useState(mount);
useEffect(() => { useEffect(() => {
if (!loading) { setRendered(true); } if (!loading) {
setRendered(true);
}
}, [loading]); }, [loading]);
const componentStyle = useMemo(() => { const componentStyle = useMemo(() => {
return {display: !loading ? 'block' : 'none'}; return { display: !loading ? 'block' : 'none' };
}, [loading]); }, [loading]);
const loadingComponent = useMemo(() => ( const loadingComponent = useMemo(
<div class='dashboard__loading-indicator'> () => (
<Spinner size={spinnerSize} value={null} /> <div class="dashboard__loading-indicator">
</div> <Spinner size={spinnerSize} value={null} />
), [spinnerSize]); </div>
),
[spinnerSize],
);
const renderComponent = useMemo(() => ( // Renders children with wrapper or without wrapper, in mount mode
<div style={componentStyle}>{ children }</div> // rendering with wrapper.
), [children, componentStyle]); const renderChildren = useMemo(
() => (mount ? <div style={componentStyle}>{children}</div> : children),
[children, mount, componentStyle],
);
const maybeRenderComponent = (rendered && children) && renderComponent; // Render children component or not in loading and in mount mode rendering
// anyway.
const renderComponent = useMemo(
() => (!loading || mount ? renderChildren : null),
[renderChildren, loading, mount],
);
const maybeRenderComponent = rendered && children && renderComponent;
const maybeRenderLoadingSpinner = loading && loadingComponent; const maybeRenderLoadingSpinner = loading && loadingComponent;
return ( return (
<> <>
{ maybeRenderLoadingSpinner } {maybeRenderLoadingSpinner}
{ maybeRenderComponent } {maybeRenderComponent}
</> </>
); );
} }

View File

@@ -1,3 +1,4 @@
import If from './Utils/If'; import If from './Utils/If';
import Money from './Money'; import Money from './Money';
import Icon from './Icon'; import Icon from './Icon';
@@ -36,6 +37,7 @@ import SalutationList from './SalutationList';
import DisplayNameList from './DisplayNameList'; import DisplayNameList from './DisplayNameList';
import MoneyInputGroup from './MoneyInputGroup'; import MoneyInputGroup from './MoneyInputGroup';
import Dragzone from './Dragzone'; import Dragzone from './Dragzone';
import EmptyStatus from './EmptyStatus';
const Hint = FieldHint; const Hint = FieldHint;
@@ -79,4 +81,5 @@ export {
SalutationList, SalutationList,
MoneyInputGroup, MoneyInputGroup,
Dragzone, Dragzone,
EmptyStatus
}; };

View File

@@ -25,6 +25,8 @@ import {
} from 'components'; } from 'components';
import { useIsValuePassed } from 'hooks'; import { useIsValuePassed } from 'hooks';
import ManualJournalsEmptyStatus from './ManualJournalsEmptyStatus';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withManualJournals from 'containers/Accounting/withManualJournals'; import withManualJournals from 'containers/Accounting/withManualJournals';
import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions'; import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions';
@@ -76,6 +78,7 @@ function ManualJournalsDataTable({
manualJournalsLoading, manualJournalsLoading,
manualJournalsPagination, manualJournalsPagination,
manualJournalsTableQuery, manualJournalsTableQuery,
manualJournalsCurrentViewId,
// #withManualJournalsActions // #withManualJournalsActions
addManualJournalsTableQueries, addManualJournalsTableQueries,
@@ -248,26 +251,39 @@ function ManualJournalsDataTable({
[onSelectedRowsChange], [onSelectedRowsChange],
); );
const showEmptyStatus = [
manualJournalsCurrentViewId === -1,
manualJournalsCurrentPage.length === 0,
].every(condition => condition === true);
return ( return (
<LoadingIndicator loading={manualJournalsLoading && !isLoadedBefore}> <LoadingIndicator loading={manualJournalsLoading && !isLoadedBefore}>
<DataTable <Choose>
noInitialFetch={true} <Choose.When condition={showEmptyStatus}>
columns={columns} <ManualJournalsEmptyStatus />
data={manualJournalsCurrentPage} </Choose.When>
onFetchData={handleDataTableFetchData}
manualSortBy={true} <Choose.Otherwise>
selectionColumn={true} <DataTable
expandable={true} noInitialFetch={true}
sticky={true} columns={columns}
onSelectedRowsChange={handleSelectedRowsChange} data={manualJournalsCurrentPage}
rowContextMenu={onRowContextMenu} onFetchData={handleDataTableFetchData}
pagesCount={manualJournalsPagination.pagesCount} manualSortBy={true}
pagination={true} selectionColumn={true}
initialPageSize={manualJournalsTableQuery.page_size} expandable={true}
initialPageIndex={manualJournalsTableQuery.page - 1} sticky={true}
autoResetSortBy={false} onSelectedRowsChange={handleSelectedRowsChange}
autoResetPage={false} rowContextMenu={onRowContextMenu}
/> pagesCount={manualJournalsPagination.pagesCount}
pagination={true}
initialPageSize={manualJournalsTableQuery.page_size}
initialPageIndex={manualJournalsTableQuery.page - 1}
autoResetSortBy={false}
autoResetPage={false}
/>
</Choose.Otherwise>
</Choose>
</LoadingIndicator> </LoadingIndicator>
); );
} }
@@ -282,11 +298,13 @@ export default compose(
manualJournalsLoading, manualJournalsLoading,
manualJournalsPagination, manualJournalsPagination,
manualJournalsTableQuery, manualJournalsTableQuery,
manualJournalsCurrentViewId,
}) => ({ }) => ({
manualJournalsCurrentPage, manualJournalsCurrentPage,
manualJournalsLoading, manualJournalsLoading,
manualJournalsPagination, manualJournalsPagination,
manualJournalsTableQuery, manualJournalsTableQuery,
manualJournalsCurrentViewId
}), }),
), ),
)(ManualJournalsDataTable); )(ManualJournalsDataTable);

View File

@@ -0,0 +1,37 @@
import React from 'react';
import { Button, Intent } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { EmptyStatus } from 'components';
export default function ManualJournalsEmptyStatus() {
const history = useHistory();
return (
<EmptyStatus
title={'Create your first journal entries on accounts chart.'}
description={
<p>
It is a long established fact that a reader will be distracted by the
readable content of a page when looking at its layout.
</p>
}
action={
<>
<Button
intent={Intent.PRIMARY}
large={true}
onClick={() => {
history.push('/invoices/new');
}}
>
Make journal
</Button>
<Button intent={Intent.NONE} large={true}>
Learn more
</Button>
</>
}
/>
);
}

View File

@@ -4,10 +4,12 @@ import {
getManualJournalsItems, getManualJournalsItems,
getManualJournalsPagination, getManualJournalsPagination,
getManualJournalsTableQuery, getManualJournalsTableQuery,
getManualJournalsCurrentViewIdFactory
} from 'store/manualJournals/manualJournals.selectors'; } from 'store/manualJournals/manualJournals.selectors';
export default (mapState) => { export default (mapState) => {
const getManualJournalsCurrentViewId = getManualJournalsCurrentViewIdFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const query = getManualJournalsTableQuery(state, props); const query = getManualJournalsTableQuery(state, props);
@@ -21,6 +23,8 @@ export default (mapState) => {
manualJournalsLoading: state.manualJournals.loading, manualJournalsLoading: state.manualJournals.loading,
journalNumberChanged: state.manualJournals.journalNumberChanged, journalNumberChanged: state.manualJournals.journalNumberChanged,
manualJournalsCurrentViewId: getManualJournalsCurrentViewId(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -1,4 +1,4 @@
import React, { useRef, useEffect, useCallback, useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import { import {
Button, Button,
Popover, Popover,
@@ -11,8 +11,8 @@ import {
import { FormattedMessage as T, useIntl } from 'react-intl'; import { FormattedMessage as T, useIntl } from 'react-intl';
import { useIsValuePassed } from 'hooks'; import { useIsValuePassed } from 'hooks';
import LoadingIndicator from 'components/LoadingIndicator'; import CustomersEmptyStatus from './CustomersEmptyStatus';
import { DataTable, Icon, Money } from 'components'; import { DataTable, Icon, Money, Choose, LoadingIndicator } from 'components';
import withCustomers from './withCustomers'; import withCustomers from './withCustomers';
import withCustomersActions from './withCustomersActions'; import withCustomersActions from './withCustomersActions';
@@ -29,6 +29,7 @@ const CustomerTable = ({
customersLoading, customersLoading,
customerPagination, customerPagination,
customersTableQuery, customersTableQuery,
customersCurrentViewId,
// #withCustomersActions // #withCustomersActions
addCustomersTableQueries, addCustomersTableQueries,
@@ -182,31 +183,44 @@ const CustomerTable = ({
onDeleteCustomer, onDeleteCustomer,
}); });
const showEmptyStatus = [
customersCurrentViewId === -1,
customers.length === 0,
].every(condition => condition === true);
return ( return (
<LoadingIndicator <LoadingIndicator
loading={customersLoading && !isLoadedBefore} loading={customersLoading && !isLoadedBefore}
mount={false} mount={false}
> >
<DataTable <Choose>
noInitialFetch={true} <Choose.When condition={showEmptyStatus}>
columns={columns} <CustomersEmptyStatus />
data={customers} </Choose.When>
// loading={customersLoading}
onFetchData={handleFetchData} <Choose.Otherwise>
selectionColumn={true} <DataTable
expandable={false} noInitialFetch={true}
sticky={true} columns={columns}
onSelectedRowsChange={handleSelectedRowsChange} data={customers}
spinnerProps={{ size: 30 }} // loading={customersLoading}
rowContextMenu={rowContextMenu} onFetchData={handleFetchData}
pagination={true} selectionColumn={true}
manualSortBy={true} expandable={false}
pagesCount={customerPagination.pagesCount} sticky={true}
autoResetSortBy={false} onSelectedRowsChange={handleSelectedRowsChange}
autoResetPage={false} spinnerProps={{ size: 30 }}
initialPageSize={customersTableQuery.page_size} rowContextMenu={rowContextMenu}
initialPageIndex={customersTableQuery.page - 1} pagination={true}
/> manualSortBy={true}
pagesCount={customerPagination.pagesCount}
autoResetSortBy={false}
autoResetPage={false}
initialPageSize={customersTableQuery.page_size}
initialPageIndex={customersTableQuery.page - 1}
/>
</Choose.Otherwise>
</Choose>
</LoadingIndicator> </LoadingIndicator>
); );
}; };
@@ -218,11 +232,13 @@ export default compose(
customersLoading, customersLoading,
customerPagination, customerPagination,
customersTableQuery, customersTableQuery,
customersCurrentViewId,
}) => ({ }) => ({
customers, customers,
customersLoading, customersLoading,
customerPagination, customerPagination,
customersTableQuery, customersTableQuery,
customersCurrentViewId
}), }),
), ),
withCustomersActions, withCustomersActions,

View File

@@ -0,0 +1,37 @@
import React from 'react';
import { Button, Intent } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { EmptyStatus } from 'components';
export default function CustomersEmptyStatus() {
const history = useHistory();
return (
<EmptyStatus
title={"Create and manage your organization's customers."}
description={
<p>
Here a list of your organization products and services, to be used
when you create invoices or bills to your customers or vendors.
</p>
}
action={
<>
<Button
intent={Intent.PRIMARY}
large={true}
onClick={() => {
history.push('/customers/new');
}}
>
New customer
</Button>
<Button intent={Intent.NONE} large={true}>
Learn more
</Button>
</>
}
/>
);
}

View File

@@ -4,11 +4,13 @@ import {
getCustomerCurrentPageFactory, getCustomerCurrentPageFactory,
getCustomerPaginationMetaFactory, getCustomerPaginationMetaFactory,
getCustomerTableQueryFactory, getCustomerTableQueryFactory,
getCustomersCurrentViewIdFactory,
} from 'store/customers/customers.selectors'; } from 'store/customers/customers.selectors';
export default (mapState) => { export default (mapState) => {
const getCustomersList = getCustomerCurrentPageFactory(); const getCustomersList = getCustomerCurrentPageFactory();
const getCustomerPaginationMeta = getCustomerPaginationMetaFactory(); const getCustomerPaginationMeta = getCustomerPaginationMetaFactory();
const getCustomersCurrentViewId = getCustomersCurrentViewIdFactory();
const getCustomerTableQuery = getCustomerTableQueryFactory(); const getCustomerTableQuery = getCustomerTableQueryFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
@@ -21,6 +23,7 @@ export default (mapState) => {
customerPagination: getCustomerPaginationMeta(state, props, query), customerPagination: getCustomerPaginationMeta(state, props, query),
customersLoading: state.customers.loading, customersLoading: state.customers.loading,
customersItems: state.customers.items, customersItems: state.customers.items,
customersCurrentViewId: getCustomersCurrentViewId(state, props),
// customerErrors: state.customers.errors, // customerErrors: state.customers.errors,
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;

View File

@@ -20,9 +20,9 @@ import Icon from 'components/Icon';
import { compose, saveInvoke } from 'utils'; import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks'; import { useIsValuePassed } from 'hooks';
import LoadingIndicator from 'components/LoadingIndicator'; import { If, Money, Choose, LoadingIndicator } from 'components';
import { If, Money } from 'components';
import DataTable from 'components/DataTable'; import DataTable from 'components/DataTable';
import ExpensesEmptyStatus from './ExpensesEmptyStatus';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
@@ -37,6 +37,7 @@ function ExpensesDataTable({
expensesLoading, expensesLoading,
expensesPagination, expensesPagination,
expensesTableQuery, expensesTableQuery,
expensesCurrentViewId,
// #withExpensesActions // #withExpensesActions
addExpensesTableQueries, addExpensesTableQueries,
@@ -265,28 +266,41 @@ function ExpensesDataTable({
[onSelectedRowsChange], [onSelectedRowsChange],
); );
const showEmptyStatus = [
expensesCurrentViewId === -1,
expensesCurrentPage.length === 0
].every(condition => condition === true);
return ( return (
<LoadingIndicator <LoadingIndicator
loading={expensesLoading && !isLoadedBefore} loading={expensesLoading && !isLoadedBefore}
mount={false} mount={false}
> >
<DataTable <Choose>
columns={columns} <Choose.When condition={showEmptyStatus}>
data={expensesCurrentPage} <ExpensesEmptyStatus />
manualSortBy={true} </Choose.When>
selectionColumn={true}
noInitialFetch={true} <Choose.Otherwise>
sticky={true} <DataTable
onSelectedRowsChange={handleSelectedRowsChange} columns={columns}
onFetchData={handleFetchData} data={expensesCurrentPage}
rowContextMenu={onRowContextMenu} manualSortBy={true}
pagination={true} selectionColumn={true}
pagesCount={expensesPagination.pagesCount} noInitialFetch={true}
autoResetSortBy={false} sticky={true}
autoResetPage={false} onSelectedRowsChange={handleSelectedRowsChange}
initialPageSize={expensesTableQuery.page_size} onFetchData={handleFetchData}
initialPageIndex={expensesTableQuery.page - 1} rowContextMenu={onRowContextMenu}
/> pagination={true}
pagesCount={expensesPagination.pagesCount}
autoResetSortBy={false}
autoResetPage={false}
initialPageSize={expensesTableQuery.page_size}
initialPageIndex={expensesTableQuery.page - 1}
/>
</Choose.Otherwise>
</Choose>
</LoadingIndicator> </LoadingIndicator>
); );
} }
@@ -303,11 +317,13 @@ export default compose(
expensesLoading, expensesLoading,
expensesPagination, expensesPagination,
expensesTableQuery, expensesTableQuery,
expensesCurrentViewId,
}) => ({ }) => ({
expensesCurrentPage, expensesCurrentPage,
expensesLoading, expensesLoading,
expensesPagination, expensesPagination,
expensesTableQuery, expensesTableQuery,
expensesCurrentViewId,
}), }),
), ),
withViewDetails(), withViewDetails(),

View File

@@ -0,0 +1,40 @@
import React from 'react';
function DatatableEmptyState({
title,
description,
newButtonText,
newButtonUrl,
learnMoreButtonText,
learnMoreButtonUrl,
}) {
return (
<div class={'datatable-empty-state'}>
<h1 class={CLASSES.DATATABLE_EMPTY_STATE_TITLE}>
{ title }
</h1>
</div>
)
}
export default function ExpensesEmptyState({
}) {
return (
<DatatableEmptyState
title={''}
description={''}
newButtonText={''}
newButtonUrl={''}
learnMoreButtonText={''}
learnMoreButtonUrl={''}
/>
);
}

View File

@@ -0,0 +1,37 @@
import React from 'react';
import { Button, Intent } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { EmptyStatus } from 'components';
export default function InvoicesEmptyStatus() {
const history = useHistory();
return (
<EmptyStatus
title={"Create and manage your organization's expenses"}
description={
<p>
It is a long established fact that a reader will be distracted by the
readable content of a page when looking at its layout.
</p>
}
action={
<>
<Button
intent={Intent.PRIMARY}
large={true}
onClick={() => {
history.push('/expenses/new');
}}
>
New expense
</Button>
<Button intent={Intent.NONE} large={true}>
Learn more
</Button>
</>
}
/>
);
}

View File

@@ -5,11 +5,13 @@ import {
getExpenseByIdFactory, getExpenseByIdFactory,
getExpensesTableQuery, getExpensesTableQuery,
getExpensesPaginationMetaFactory, getExpensesPaginationMetaFactory,
getExpensesCurrentViewIdFactory,
} from 'store/expenses/expenses.selectors'; } from 'store/expenses/expenses.selectors';
export default (mapState) => { export default (mapState) => {
const getExpensesItems = getExpensesCurrentPageFactory(); const getExpensesItems = getExpensesCurrentPageFactory();
const getExpensesPaginationMeta = getExpensesPaginationMetaFactory(); const getExpensesPaginationMeta = getExpensesPaginationMetaFactory();
const getExpensesCurrentViewId = getExpensesCurrentViewIdFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const query = getExpensesTableQuery(state, props); const query = getExpensesTableQuery(state, props);
@@ -21,6 +23,7 @@ export default (mapState) => {
expensesTableQuery: query, expensesTableQuery: query,
expensesPagination: getExpensesPaginationMeta(state, props), expensesPagination: getExpensesPaginationMeta(state, props),
expensesLoading: state.expenses.loading, expensesLoading: state.expenses.loading,
expensesCurrentViewId: getExpensesCurrentViewId(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -50,7 +50,6 @@ const ItemFormContainer = ({
); );
const handleCancel = useCallback(() => { const handleCancel = useCallback(() => {
// history.push('/items');
history.goBack(); history.goBack();
}, [history]); }, [history]);

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback, useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import { import {
Button, Button,
Popover, Popover,
@@ -10,14 +10,18 @@ import {
Tag, Tag,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { FormattedMessage as T, useIntl } from 'react-intl'; import { FormattedMessage as T, useIntl } from 'react-intl';
import { Icon, DataTable, Money } from 'components'; import classNames from 'classnames';
import { useIsValuePassed } from 'hooks';
import { Icon, DataTable, Money, LoadingIndicator, Choose } from 'components';
import ItemsEmptyStatus from './ItemsEmptyStatus';
import { useIsValuePassed } from 'hooks';
import { CLASSES } from 'common/classes';
import LoadingIndicator from 'components/LoadingIndicator';
import withItems from 'containers/Items/withItems'; import withItems from 'containers/Items/withItems';
import withItemsActions from 'containers/Items/withItemsActions'; import withItemsActions from 'containers/Items/withItemsActions';
import { compose, saveInvoke } from 'utils'; import { compose, saveInvoke } from 'utils';
// Items datatable.
function ItemsDataTable({ function ItemsDataTable({
// #withItems // #withItems
itemsTableLoading, itemsTableLoading,
@@ -181,31 +185,38 @@ function ItemsDataTable({
); );
return ( return (
<LoadingIndicator <div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
loading={itemsTableLoading && !isLoadedBefore} <LoadingIndicator loading={itemsTableLoading && !isLoadedBefore}>
mount={false} <Choose>
> <Choose.When condition={true}>
<DataTable <ItemsEmptyStatus />
columns={columns} </Choose.When>
data={itemsCurrentPage}
onFetchData={handleFetchData} <Choose.Otherwise>
noInitialFetch={true} <DataTable
expandable={true} columns={columns}
selectionColumn={true} data={itemsCurrentPage}
spinnerProps={{ size: 30 }} onFetchData={handleFetchData}
onSelectedRowsChange={handleSelectedRowsChange} noInitialFetch={true}
rowContextMenu={handleRowContextMenu} expandable={true}
sticky={true} selectionColumn={true}
pagination={true} spinnerProps={{ size: 30 }}
pagesCount={2} onSelectedRowsChange={handleSelectedRowsChange}
autoResetSortBy={false} rowContextMenu={handleRowContextMenu}
autoResetPage={false} sticky={true}
initialPageSize={itemsTableQuery.page_size} pagination={true}
initialPageIndex={itemsTableQuery.page - 1} pagesCount={2}
/> autoResetSortBy={false}
</LoadingIndicator> autoResetPage={false}
initialPageSize={itemsTableQuery.page_size}
initialPageIndex={itemsTableQuery.page - 1}
/>
</Choose.Otherwise>
</Choose>
</LoadingIndicator>
</div>
); );
}; }
export default compose( export default compose(
withItems(({ itemsCurrentPage, itemsTableLoading, itemsTableQuery }) => ({ withItems(({ itemsCurrentPage, itemsTableLoading, itemsTableQuery }) => ({

View File

@@ -0,0 +1,36 @@
import React from 'react';
import { Button, Intent } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { EmptyStatus } from 'components';
export default function ItemsEmptyStatus() {
const history = useHistory();
return (
<EmptyStatus
title={'Manage the organizations services and products.'}
description={
<p>
Here a list of your organization products and services, to be used when you create invoices or bills to your customers or vendors.
</p>
}
action={
<>
<Button
intent={Intent.PRIMARY}
large={true}
onClick={() => {
history.push('/items/new');
}}
>
New Item
</Button>
<Button intent={Intent.NONE} large={true}>
Learn more
</Button>
</>
}
/>
);
}

View File

@@ -50,7 +50,7 @@ function ItemsList({
useEffect(() => { useEffect(() => {
changePageTitle(formatMessage({ id: 'items_list' })); changePageTitle(formatMessage({ id: 'items_list' }));
}, [changePageTitle]); }, [changePageTitle, formatMessage]);
// Handle fetching the resource views. // Handle fetching the resource views.
const fetchResourceViews = useQuery( const fetchResourceViews = useQuery(

View File

@@ -19,8 +19,9 @@ import Icon from 'components/Icon';
import { compose, saveInvoke } from 'utils'; import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks'; import { useIsValuePassed } from 'hooks';
import LoadingIndicator from 'components/LoadingIndicator'; import { LoadingIndicator, Choose } from 'components';
import DataTable from 'components/DataTable'; import DataTable from 'components/DataTable';
import BillsEmptyStatus from './BillsEmptyStatus';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
@@ -30,11 +31,13 @@ import withBills from './withBills';
import withBillActions from './withBillActions'; import withBillActions from './withBillActions';
import withCurrentView from 'containers/Views/withCurrentView'; import withCurrentView from 'containers/Views/withCurrentView';
// Bills transactions datatable.
function BillsDataTable({ function BillsDataTable({
//#withBills // #withBills
billsCurrentPage, billsCurrentPage,
billsLoading, billsLoading,
billsPageination, billsPageination,
billsCurrentViewId,
// #withDashboardActions // #withDashboardActions
changeCurrentView, changeCurrentView,
@@ -215,23 +218,36 @@ function BillsDataTable({
[onSelectedRowsChange], [onSelectedRowsChange],
); );
const showEmptyStatus = [
billsCurrentViewId === -1,
billsCurrentPage.length === 0,
].every(condition => condition === true);
return ( return (
<LoadingIndicator loading={billsLoading && !isLoadedBefore} mount={false}> <LoadingIndicator loading={billsLoading && !isLoadedBefore} mount={false}>
<DataTable <Choose>
columns={columns} <Choose.When condition={showEmptyStatus}>
data={billsCurrentPage} <BillsEmptyStatus />
onFetchData={handleFetchData} </Choose.When>
manualSortBy={true}
selectionColumn={true} <Choose.Otherwise>
noInitialFetch={true} <DataTable
sticky={true} columns={columns}
onSelectedRowsChange={handleSelectedRowsChange} data={billsCurrentPage}
rowContextMenu={onRowContextMenu} onFetchData={handleFetchData}
pagination={true} manualSortBy={true}
pagesCount={billsPageination.pagesCount} selectionColumn={true}
initialPageSize={billsPageination.pageSize} noInitialFetch={true}
initialPageIndex={billsPageination.page - 1} sticky={true}
/> onSelectedRowsChange={handleSelectedRowsChange}
rowContextMenu={onRowContextMenu}
pagination={true}
pagesCount={billsPageination.pagesCount}
initialPageSize={billsPageination.pageSize}
initialPageIndex={billsPageination.page - 1}
/>
</Choose.Otherwise>
</Choose>
</LoadingIndicator> </LoadingIndicator>
); );
} }
@@ -248,11 +264,13 @@ export default compose(
billsLoading, billsLoading,
billsPageination, billsPageination,
billsTableQuery, billsTableQuery,
billsCurrentViewId
}) => ({ }) => ({
billsCurrentPage, billsCurrentPage,
billsLoading, billsLoading,
billsPageination, billsPageination,
billsTableQuery, billsTableQuery,
billsCurrentViewId
}), }),
), ),
withViewDetails(), withViewDetails(),

View File

@@ -0,0 +1,36 @@
import React from 'react';
import { Button, Intent } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { EmptyStatus } from 'components';
export default function BillsEmptyStatus() {
const history = useHistory();
return (
<EmptyStatus
title={'Manage the organizations services and products.'}
description={
<p>
Here a list of your organization products and services, to be used when you create invoices or bills to your customers or vendors.
</p>
}
action={
<>
<Button
intent={Intent.PRIMARY}
large={true}
onClick={() => {
history.push('/bills/new');
}}
>
New bill
</Button>
<Button intent={Intent.NONE} large={true}>
Learn more
</Button>
</>
}
/>
);
}

View File

@@ -6,6 +6,7 @@ import {
getBillTableQueryFactory, getBillTableQueryFactory,
getVendorPayableBillsFactory, getVendorPayableBillsFactory,
getVendorPayableBillsEntriesFactory, getVendorPayableBillsEntriesFactory,
getBillsCurrentViewIdFactory,
} from 'store/Bills/bills.selectors'; } from 'store/Bills/bills.selectors';
export default (mapState) => { export default (mapState) => {
@@ -14,12 +15,14 @@ export default (mapState) => {
const getBillTableQuery = getBillTableQueryFactory(); const getBillTableQuery = getBillTableQueryFactory();
const getVendorPayableBills = getVendorPayableBillsFactory(); const getVendorPayableBills = getVendorPayableBillsFactory();
const getVendorPayableBillsEntries = getVendorPayableBillsEntriesFactory(); const getVendorPayableBillsEntries = getVendorPayableBillsEntriesFactory();
const getBillsCurrentViewId = getBillsCurrentViewIdFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const tableQuery = getBillTableQuery(state, props); const tableQuery = getBillTableQuery(state, props);
const mapped = { const mapped = {
billsCurrentPage: getBillsItems(state, props, tableQuery), billsCurrentPage: getBillsItems(state, props, tableQuery),
billsCurrentViewId: getBillsCurrentViewId(state),
billsViews: getResourceViews(state, props, 'bills'), billsViews: getResourceViews(state, props, 'bills'),
billsItems: state.bills.items, billsItems: state.bills.items,
billsTableQuery: tableQuery, billsTableQuery: tableQuery,
@@ -29,6 +32,7 @@ export default (mapState) => {
nextBillNumberChanged: state.bills.nextBillNumberChanged, nextBillNumberChanged: state.bills.nextBillNumberChanged,
vendorPayableBills: getVendorPayableBills(state, props), vendorPayableBills: getVendorPayableBills(state, props),
vendorPayableBillsEntries: getVendorPayableBillsEntries(state, props), vendorPayableBillsEntries: getVendorPayableBillsEntries(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -15,8 +15,8 @@ import moment from 'moment';
import { compose, saveInvoke } from 'utils'; import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks'; import { useIsValuePassed } from 'hooks';
import LoadingIndicator from 'components/LoadingIndicator'; import { DataTable, Money, Icon, Choose, LoadingIndicator } from 'components';
import { DataTable, Money, Icon } from 'components'; import PaymentMadesEmptyStatus from './PaymentMadesEmptyStatus';
import withPaymentMade from './withPaymentMade'; import withPaymentMade from './withPaymentMade';
import withPaymentMadeActions from './withPaymentMadeActions'; import withPaymentMadeActions from './withPaymentMadeActions';
@@ -31,6 +31,7 @@ function PaymentMadeDataTable({
paymentMadePageination, paymentMadePageination,
paymentMadesLoading, paymentMadesLoading,
paymentMadeTableQuery, paymentMadeTableQuery,
paymentMadesCurrentViewId,
// #withPaymentMadeActions // #withPaymentMadeActions
addPaymentMadesTableQueries, addPaymentMadesTableQueries,
@@ -178,25 +179,38 @@ function PaymentMadeDataTable({
[onSelectedRowsChange], [onSelectedRowsChange],
); );
const showEmptyStatuts = [
paymentMadeCurrentPage.length === 0,
paymentMadesCurrentViewId === -1,
].every(condition => condition === true);
return ( return (
<LoadingIndicator loading={paymentMadesLoading && !isLoaded} mount={false}> <LoadingIndicator loading={paymentMadesLoading && !isLoaded}>
<DataTable <Choose>
columns={columns} <Choose.When condition={showEmptyStatuts}>
data={paymentMadeCurrentPage} <PaymentMadesEmptyStatus />
onFetchData={handleDataTableFetchData} </Choose.When>
manualSortBy={true}
selectionColumn={true} <Choose.Otherwise>
noInitialFetch={true} <DataTable
sticky={true} columns={columns}
onSelectedRowsChange={handleSelectedRowsChange} data={paymentMadeCurrentPage}
rowContextMenu={onRowContextMenu} onFetchData={handleDataTableFetchData}
pagination={true} manualSortBy={true}
pagesCount={paymentMadePageination.pagesCount} selectionColumn={true}
initialPageSize={paymentMadeTableQuery.page_size} noInitialFetch={true}
initialPageIndex={paymentMadeTableQuery.page - 1} sticky={true}
autoResetSortBy={false} onSelectedRowsChange={handleSelectedRowsChange}
autoResetPage={false} rowContextMenu={onRowContextMenu}
/> pagination={true}
pagesCount={paymentMadePageination.pagesCount}
initialPageSize={paymentMadeTableQuery.page_size}
initialPageIndex={paymentMadeTableQuery.page - 1}
autoResetSortBy={false}
autoResetPage={false}
/>
</Choose.Otherwise>
</Choose>
</LoadingIndicator> </LoadingIndicator>
); );
} }
@@ -211,11 +225,13 @@ export default compose(
paymentMadesLoading, paymentMadesLoading,
paymentMadePageination, paymentMadePageination,
paymentMadeTableQuery, paymentMadeTableQuery,
paymentMadesCurrentViewId
}) => ({ }) => ({
paymentMadeCurrentPage, paymentMadeCurrentPage,
paymentMadesLoading, paymentMadesLoading,
paymentMadePageination, paymentMadePageination,
paymentMadeTableQuery, paymentMadeTableQuery,
paymentMadesCurrentViewId
}), }),
), ),
)(PaymentMadeDataTable); )(PaymentMadeDataTable);

View File

@@ -0,0 +1,37 @@
import React from 'react';
import { Button, Intent } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { EmptyStatus } from 'components';
export default function PaymentMadesEmptyStatus() {
const history = useHistory();
return (
<EmptyStatus
title={'The organization does not have invoices, yet!'}
description={
<p>
It is a long established fact that a reader will be distracted by the
readable content of a page when looking at its layout.
</p>
}
action={
<>
<Button
intent={Intent.PRIMARY}
large={true}
onClick={() => {
history.push('/payment-made/new');
}}
>
New bill payment
</Button>
<Button intent={Intent.NONE} large={true}>
Learn more
</Button>
</>
}
/>
);
}

View File

@@ -1,20 +1,22 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { getResourceViews } from 'store/customViews/customViews.selectors'; import { getResourceViews } from 'store/customViews/customViews.selectors';
import { import {
getPaymentMadeCurrentPageFactory, getPaymentMadeCurrentPageFactory,
getPaymentMadePaginationMetaFactory, getPaymentMadePaginationMetaFactory,
getPaymentMadeTableQuery, getPaymentMadeTableQuery,
getPaymentMadeEntriesFactory getPaymentMadeEntriesFactory,
getPaymentMadesCurrentViewIdFactory
} from 'store/PaymentMades/paymentMade.selector'; } from 'store/PaymentMades/paymentMade.selector';
export default (mapState) => { export default (mapState) => {
const getPyamentMadesItems = getPaymentMadeCurrentPageFactory(); const getPyamentMadesItems = getPaymentMadeCurrentPageFactory();
const getPyamentMadesPaginationMeta = getPaymentMadePaginationMetaFactory(); const getPyamentMadesPaginationMeta = getPaymentMadePaginationMetaFactory();
const getPaymentMadeEntries = getPaymentMadeEntriesFactory(); const getPaymentMadeEntries = getPaymentMadeEntriesFactory();
const getPaymentMadesCurrentViewId = getPaymentMadesCurrentViewIdFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const query = getPaymentMadeTableQuery(state, props); const query = getPaymentMadeTableQuery(state, props);
const mapped = { const mapped = {
paymentMadeCurrentPage: getPyamentMadesItems(state, props, query), paymentMadeCurrentPage: getPyamentMadesItems(state, props, query),
paymentMadeViews: getResourceViews(state, props, 'bill_payments'), paymentMadeViews: getResourceViews(state, props, 'bill_payments'),
@@ -28,6 +30,8 @@ export default (mapState) => {
paymentMadesLoading: state.paymentMades.loading, paymentMadesLoading: state.paymentMades.loading,
nextPaymentNumberChanged: state.paymentMades.nextPaymentNumberChanged, nextPaymentNumberChanged: state.paymentMades.nextPaymentNumberChanged,
paymentMadeEntries: getPaymentMadeEntries(state, props), paymentMadeEntries: getPaymentMadeEntries(state, props),
paymentMadesCurrentViewId: getPaymentMadesCurrentViewId(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -76,7 +76,6 @@ function EstimateViewTabs({
history.push('/custom_views/estimates/new'); history.push('/custom_views/estimates/new');
}; };
console.log(estimateViews, 'estimateViews');
return ( return (
<Navbar className={'navbar--dashboard-views'}> <Navbar className={'navbar--dashboard-views'}>
<NavbarGroup align={Alignment.LEFT}> <NavbarGroup align={Alignment.LEFT}>

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useCallback, useState, useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import { import {
Intent, Intent,
Button, Button,
@@ -8,15 +8,17 @@ import {
MenuDivider, MenuDivider,
Position, Position,
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { withRouter } from 'react-router'; import classNames from 'classnames';
import { FormattedMessage as T, useIntl } from 'react-intl'; import { FormattedMessage as T, useIntl } from 'react-intl';
import moment from 'moment'; import moment from 'moment';
import { CLASSES } from 'common/classes';
import { compose, saveInvoke } from 'utils'; import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks'; import { useIsValuePassed } from 'hooks';
import LoadingIndicator from 'components/LoadingIndicator'; import LoadingIndicator from 'components/LoadingIndicator';
import { DataTable, Money, Icon } from 'components'; import { DataTable, Money, Choose, Icon } from 'components';
import EstimatesEmptyStatus from './EstimatesEmptyStatus';
import withEstimates from './withEstimates'; import withEstimates from './withEstimates';
import withEstimateActions from './withEstimateActions'; import withEstimateActions from './withEstimateActions';
@@ -28,6 +30,7 @@ function EstimatesDataTable({
estimatesLoading, estimatesLoading,
estimatesPageination, estimatesPageination,
estimatesTableQuery, estimatesTableQuery,
estimatesCurrentViewId,
// #withEstimatesActions // #withEstimatesActions
addEstimatesTableQueries, addEstimatesTableQueries,
@@ -177,35 +180,57 @@ function EstimatesDataTable({
[onSelectedRowsChange], [onSelectedRowsChange],
); );
const showEmptyStatus = [
estimatesCurrentPage.length === 0,
estimatesCurrentViewId === -1,
].every(d => d === true);
return ( return (
<LoadingIndicator loading={estimatesLoading && !isLoaded} mount={false}> <div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
<DataTable <LoadingIndicator loading={estimatesLoading && !isLoaded} mount={false}>
columns={columns} <Choose>
data={estimatesCurrentPage} <Choose.When condition={showEmptyStatus}>
onFetchData={handleFetchData} <EstimatesEmptyStatus />
manualSortBy={true} </Choose.When>
selectionColumn={true}
noInitialFetch={true} <Choose.Otherwise>
sticky={true} <DataTable
onSelectedRowsChange={handleSelectedRowsChange} columns={columns}
rowContextMenu={onRowContextMenu} data={estimatesCurrentPage}
pagination={true} onFetchData={handleFetchData}
pagesCount={estimatesPageination.pagesCount} manualSortBy={true}
initialPageSize={estimatesTableQuery.page_size} selectionColumn={true}
initialPageIndex={estimatesTableQuery.page - 1} noInitialFetch={true}
/> sticky={true}
</LoadingIndicator> onSelectedRowsChange={handleSelectedRowsChange}
rowContextMenu={onRowContextMenu}
pagination={true}
pagesCount={estimatesPageination.pagesCount}
initialPageSize={estimatesTableQuery.page_size}
initialPageIndex={estimatesTableQuery.page - 1}
/>
</Choose.Otherwise>
</Choose>
</LoadingIndicator>
</div>
); );
} }
export default compose( export default compose(
withEstimateActions, withEstimateActions,
withEstimates( withEstimates(
({ estimatesCurrentPage, estimatesLoading, estimatesPageination, estimatesTableQuery }) => ({ ({
estimatesCurrentPage, estimatesCurrentPage,
estimatesLoading, estimatesLoading,
estimatesPageination, estimatesPageination,
estimatesTableQuery estimatesTableQuery,
estimatesCurrentViewId,
}) => ({
estimatesCurrentPage,
estimatesLoading,
estimatesPageination,
estimatesTableQuery,
estimatesCurrentViewId,
}), }),
), ),
)(EstimatesDataTable); )(EstimatesDataTable);

View File

@@ -0,0 +1,36 @@
import React from 'react';
import { Button, Intent } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { EmptyStatus } from 'components';
export default function EstimatesEmptyStatus() {
const history = useHistory();
return (
<EmptyStatus
title={"It's time to send estimates to your customers."}
description={
<p>
It is a long established fact that a reader will be distracted by the
readable content of a page when looking at its layout.
</p>
}
action={
<>
<Button
intent={Intent.PRIMARY}
large={true}
onClick={() => {
history.push('/estimates/new');
}}
>
New sale estimate
</Button>
<Button intent={Intent.NONE} large={true}>
Learn more
</Button>
</>
}
/>
);
}

View File

@@ -4,18 +4,22 @@ import {
getEstimateCurrentPageFactory, getEstimateCurrentPageFactory,
getEstimatesTableQueryFactory, getEstimatesTableQueryFactory,
getEstimatesPaginationMetaFactory, getEstimatesPaginationMetaFactory,
getEstimatesCurrentViewIdFactory,
} from 'store/Estimate/estimates.selectors'; } from 'store/Estimate/estimates.selectors';
export default (mapState) => { export default (mapState) => {
const getEstimatesItems = getEstimateCurrentPageFactory(); const getEstimatesItems = getEstimateCurrentPageFactory();
const getEstimatesPaginationMeta = getEstimatesPaginationMetaFactory(); const getEstimatesPaginationMeta = getEstimatesPaginationMetaFactory();
const getEstimatesTableQuery = getEstimatesTableQueryFactory(); const getEstimatesTableQuery = getEstimatesTableQueryFactory();
const getEstimatesCurrentViewId = getEstimatesCurrentViewIdFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const query = getEstimatesTableQuery(state, props); const query = getEstimatesTableQuery(state, props);
const mapped = { const mapped = {
estimatesCurrentPage: getEstimatesItems(state, props, query), estimatesCurrentPage: getEstimatesItems(state, props, query),
estimatesCurrentViewId: getEstimatesCurrentViewId(state, props),
estimateViews: getResourceViews(state, props, 'sales_estimates'), estimateViews: getResourceViews(state, props, 'sales_estimates'),
estimateItems: state.salesEstimates.items, estimateItems: state.salesEstimates.items,

View File

@@ -11,12 +11,15 @@ import {
import { withRouter } from 'react-router'; import { withRouter } from 'react-router';
import { FormattedMessage as T, useIntl } from 'react-intl'; import { FormattedMessage as T, useIntl } from 'react-intl';
import moment from 'moment'; import moment from 'moment';
import classNames from 'classnames';
import { CLASSES } from 'common/classes';
import { compose, saveInvoke } from 'utils'; import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks'; import { useIsValuePassed } from 'hooks';
import LoadingIndicator from 'components/LoadingIndicator'; import { LoadingIndicator, Choose, DataTable, Money, Icon } from 'components';
import { DataTable, Money, Icon } from 'components'; import InvoicesEmptyStatus from './InvoicesEmptyStatus';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
@@ -32,6 +35,7 @@ function InvoicesDataTable({
invoicesCurrentPage, invoicesCurrentPage,
invoicesLoading, invoicesLoading,
invoicesPageination, invoicesPageination,
invoicesCurrentViewId,
// #withInvoicesActions // #withInvoicesActions
addInvoiceTableQueries, addInvoiceTableQueries,
@@ -186,29 +190,41 @@ function InvoicesDataTable({
[onSelectedRowsChange], [onSelectedRowsChange],
); );
const showEmptyStatus = [
invoicesCurrentPage.length === 0,
invoicesCurrentViewId === -1,
].every((d) => d === true);
return ( return (
<LoadingIndicator <div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
loading={invoicesLoading && !isLoadedBefore} <LoadingIndicator loading={invoicesLoading && !isLoadedBefore}>
mount={false} <Choose>
> <Choose.When condition={showEmptyStatus}>
<DataTable <InvoicesEmptyStatus />
columns={columns} </Choose.When>
data={invoicesCurrentPage}
onFetchData={handleDataTableFetchData} <Choose.Otherwise>
manualSortBy={true} <DataTable
selectionColumn={true} columns={columns}
noInitialFetch={true} data={invoicesCurrentPage}
sticky={true} onFetchData={handleDataTableFetchData}
onSelectedRowsChange={handleSelectedRowsChange} manualSortBy={true}
rowContextMenu={onRowContextMenu} selectionColumn={true}
pagination={true} noInitialFetch={true}
autoResetSortBy={false} sticky={true}
autoResetPage={false} onSelectedRowsChange={handleSelectedRowsChange}
pagesCount={invoicesPageination.pagesCount} rowContextMenu={onRowContextMenu}
initialPageSize={invoicesPageination.pageSize} pagination={true}
initialPageIndex={invoicesPageination.page - 1} autoResetSortBy={false}
/> autoResetPage={false}
</LoadingIndicator> pagesCount={invoicesPageination.pagesCount}
initialPageSize={invoicesPageination.pageSize}
initialPageIndex={invoicesPageination.page - 1}
/>
</Choose.Otherwise>
</Choose>
</LoadingIndicator>
</div>
); );
} }
@@ -224,11 +240,13 @@ export default compose(
invoicesLoading, invoicesLoading,
invoicesPageination, invoicesPageination,
invoicesTableQuery, invoicesTableQuery,
invoicesCurrentViewId,
}) => ({ }) => ({
invoicesCurrentPage, invoicesCurrentPage,
invoicesLoading, invoicesLoading,
invoicesPageination, invoicesPageination,
invoicesTableQuery, invoicesTableQuery,
invoicesCurrentViewId,
}), }),
), ),
withViewDetails(), withViewDetails(),

View File

@@ -0,0 +1,37 @@
import React from 'react';
import { Button, Intent } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { EmptyStatus } from 'components';
export default function EstimatesEmptyStatus() {
const history = useHistory();
return (
<EmptyStatus
title={'The organization does not have invoices, yet!'}
description={
<p>
It is a long established fact that a reader will be distracted by the
readable content of a page when looking at its layout.
</p>
}
action={
<>
<Button
intent={Intent.PRIMARY}
large={true}
onClick={() => {
history.push('/invoices/new');
}}
>
New sale invoice
</Button>
<Button intent={Intent.NONE} large={true}>
Learn more
</Button>
</>
}
/>
);
}

View File

@@ -5,6 +5,7 @@ import {
getInvoicePaginationMetaFactory, getInvoicePaginationMetaFactory,
getInvoiceTableQueryFactory, getInvoiceTableQueryFactory,
getCustomerReceivableInvoicesEntriesFactory, getCustomerReceivableInvoicesEntriesFactory,
getInvoicesCurrentViewIdFactory,
} from 'store/Invoice/invoices.selector'; } from 'store/Invoice/invoices.selector';
export default (mapState) => { export default (mapState) => {
@@ -15,11 +16,15 @@ export default (mapState) => {
const getCustomerReceivableInvoicesEntries = getCustomerReceivableInvoicesEntriesFactory(); const getCustomerReceivableInvoicesEntries = getCustomerReceivableInvoicesEntriesFactory();
const getInvoicesCurrentViewId = getInvoicesCurrentViewIdFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const query = getInvoiceTableQuery(state, props); const query = getInvoiceTableQuery(state, props);
const mapped = { const mapped = {
invoicesCurrentPage: getInvoicesItems(state, props, query), invoicesCurrentPage: getInvoicesItems(state, props, query),
invoicesCurrentViewId: getInvoicesCurrentViewId(state, props),
invoicesViews: getResourceViews(state, props, 'sales_invoices'), invoicesViews: getResourceViews(state, props, 'sales_invoices'),
invoicesItems: state.salesInvoices.items, invoicesItems: state.salesInvoices.items,
invoicesTableQuery: query, invoicesTableQuery: query,

View File

@@ -15,8 +15,8 @@ import moment from 'moment';
import { compose, saveInvoke } from 'utils'; import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks'; import { useIsValuePassed } from 'hooks';
import LoadingIndicator from 'components/LoadingIndicator'; import PaymentReceivesEmptyStatus from './PaymentReceivesEmptyStatus';
import { DataTable, Money, Icon } from 'components'; import { LoadingIndicator, DataTable, Choose, Money, Icon } from 'components';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
@@ -32,6 +32,7 @@ function PaymentReceivesDataTable({
paymentReceivesPageination, paymentReceivesPageination,
paymentReceivesLoading, paymentReceivesLoading,
paymentReceivesTableQuery, paymentReceivesTableQuery,
paymentReceivesCurrentViewId,
// #withPaymentReceivesActions // #withPaymentReceivesActions
addPaymentReceivesTableQueries, addPaymentReceivesTableQueries,
@@ -179,28 +180,41 @@ function PaymentReceivesDataTable({
[actionMenuList, formatMessage], [actionMenuList, formatMessage],
); );
const showEmptyStatus = [
paymentReceivesCurrentViewId === -1,
PaymentReceivesCurrentPage.length === 0,
].every(condition => condition === true);
return ( return (
<LoadingIndicator <LoadingIndicator
loading={paymentReceivesLoading && !isLoaded} loading={paymentReceivesLoading && !isLoaded}
mount={false} mount={false}
> >
<DataTable <Choose>
columns={columns} <Choose.When condition={showEmptyStatus}>
data={PaymentReceivesCurrentPage} <PaymentReceivesEmptyStatus />
onFetchData={handleDataTableFetchData} </Choose.When>
manualSortBy={true}
selectionColumn={true} <Choose.Otherwise>
noInitialFetch={true} <DataTable
sticky={true} columns={columns}
onSelectedRowsChange={handleSelectedRowsChange} data={PaymentReceivesCurrentPage}
rowContextMenu={onRowContextMenu} onFetchData={handleDataTableFetchData}
pagination={true} manualSortBy={true}
autoResetSortBy={false} selectionColumn={true}
autoResetPage={false} noInitialFetch={true}
pagesCount={paymentReceivesPageination.pagesCount} sticky={true}
initialPageSize={paymentReceivesTableQuery.page_size} onSelectedRowsChange={handleSelectedRowsChange}
initialPageIndex={paymentReceivesTableQuery.page - 1} rowContextMenu={onRowContextMenu}
/> pagination={true}
autoResetSortBy={false}
autoResetPage={false}
pagesCount={paymentReceivesPageination.pagesCount}
initialPageSize={paymentReceivesTableQuery.page_size}
initialPageIndex={paymentReceivesTableQuery.page - 1}
/>
</Choose.Otherwise>
</Choose>
</LoadingIndicator> </LoadingIndicator>
); );
} }
@@ -216,12 +230,14 @@ export default compose(
PaymentReceivesCurrentPage, PaymentReceivesCurrentPage,
paymentReceivesLoading, paymentReceivesLoading,
paymentReceivesPageination, paymentReceivesPageination,
paymentReceivesTableQuery paymentReceivesTableQuery,
paymentReceivesCurrentViewId,
}) => ({ }) => ({
PaymentReceivesCurrentPage, PaymentReceivesCurrentPage,
paymentReceivesLoading, paymentReceivesLoading,
paymentReceivesPageination, paymentReceivesPageination,
paymentReceivesTableQuery paymentReceivesTableQuery,
paymentReceivesCurrentViewId,
}), }),
), ),
withViewDetails(), withViewDetails(),

View File

@@ -0,0 +1,37 @@
import React from 'react';
import { Button, Intent } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { EmptyStatus } from 'components';
export default function PaymentReceivesEmptyStatus() {
const history = useHistory();
return (
<EmptyStatus
title={"The organization does't receive money, yet!"}
description={
<p>
It is a long established fact that a reader will be distracted by the
readable content of a page when looking at its layout.
</p>
}
action={
<>
<Button
intent={Intent.PRIMARY}
large={true}
onClick={() => {
history.push('/payment-receive/new');
}}
>
New payment receive
</Button>
<Button intent={Intent.NONE} large={true}>
Learn more
</Button>
</>
}
/>
);
}

View File

@@ -4,11 +4,14 @@ import {
getPaymentReceiveCurrentPageFactory, getPaymentReceiveCurrentPageFactory,
getPaymentReceivePaginationMetaFactory, getPaymentReceivePaginationMetaFactory,
getPaymentReceiveTableQuery, getPaymentReceiveTableQuery,
getPaymentReceivesCurrentViewIdFactory,
} from 'store/PaymentReceive/paymentReceive.selector'; } from 'store/PaymentReceive/paymentReceive.selector';
export default (mapState) => { export default (mapState) => {
const getPyamentReceivesItems = getPaymentReceiveCurrentPageFactory(); const getPyamentReceivesItems = getPaymentReceiveCurrentPageFactory();
const getPyamentReceivesPaginationMeta = getPaymentReceivePaginationMetaFactory(); const getPyamentReceivesPaginationMeta = getPaymentReceivePaginationMetaFactory();
const getPaymentReceivesCurrentViewId = getPaymentReceivesCurrentViewIdFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const query = getPaymentReceiveTableQuery(state, props); const query = getPaymentReceiveTableQuery(state, props);
const mapped = { const mapped = {
@@ -23,6 +26,7 @@ export default (mapState) => {
), ),
paymentReceivesLoading: state.paymentReceives.loading, paymentReceivesLoading: state.paymentReceives.loading,
paymentReceiveNumberChanged: state.paymentReceives.journalNumberChanged, paymentReceiveNumberChanged: state.paymentReceives.journalNumberChanged,
paymentReceivesCurrentViewId: getPaymentReceivesCurrentViewId(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -15,7 +15,9 @@ import moment from 'moment';
import { compose, saveInvoke } from 'utils'; import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks'; import { useIsValuePassed } from 'hooks';
import { LoadingIndicator, DataTable, Money, Icon } from 'components'; import { Choose, LoadingIndicator, DataTable, Money, Icon } from 'components';
import ReceiptsEmptyStatus from './ReceiptsEmptyStatus';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
@@ -24,16 +26,17 @@ import withReceipts from './withReceipts';
import withReceiptActions from './withReceiptActions'; import withReceiptActions from './withReceiptActions';
function ReceiptsDataTable({ function ReceiptsDataTable({
//#withReceipts // #withReceipts
receiptsCurrentPage, receiptsCurrentPage,
receiptsLoading, receiptsLoading,
receiptsPagination, receiptsPagination,
receiptTableQuery, receiptTableQuery,
receiptsCurrentViewId,
// #withReceiptsActions // #withReceiptsActions
addReceiptsTableQueries, addReceiptsTableQueries,
// #Own Props // #ownProps
loading, loading,
onEditReceipt, onEditReceipt,
onDeleteReceipt, onDeleteReceipt,
@@ -186,28 +189,38 @@ function ReceiptsDataTable({
[onSelectedRowsChange], [onSelectedRowsChange],
); );
const showEmptyStatus = [
receiptsCurrentViewId === -1,
receiptsCurrentPage.length === 0,
].every(condition => condition === true);
return ( return (
<LoadingIndicator <LoadingIndicator loading={receiptsLoading && !isLoadedBefore}>
loading={receiptsLoading && !isLoadedBefore} <Choose>
mount={false} <Choose.When condition={showEmptyStatus}>
> <ReceiptsEmptyStatus />
<DataTable </Choose.When>
columns={columns}
data={receiptsCurrentPage} <Choose.Otherwise>
onFetchData={handleDataTableFetchData} <DataTable
manualSortBy={true} columns={columns}
selectionColumn={true} data={receiptsCurrentPage}
noInitialFetch={true} onFetchData={handleDataTableFetchData}
sticky={true} manualSortBy={true}
onSelectedRowsChange={handleSelectedRowsChange} selectionColumn={true}
rowContextMenu={onRowContextMenu} noInitialFetch={true}
pagination={true} sticky={true}
pagesCount={receiptsPagination.pagesCount} onSelectedRowsChange={handleSelectedRowsChange}
autoResetSortBy={false} rowContextMenu={onRowContextMenu}
autoResetPage={false} pagination={true}
initialPageSize={receiptTableQuery.page_size} pagesCount={receiptsPagination.pagesCount}
initialPageIndex={receiptTableQuery.page - 1} autoResetSortBy={false}
/> autoResetPage={false}
initialPageSize={receiptTableQuery.page_size}
initialPageIndex={receiptTableQuery.page - 1}
/>
</Choose.Otherwise>
</Choose>
</LoadingIndicator> </LoadingIndicator>
); );
} }
@@ -223,11 +236,13 @@ export default compose(
receiptsLoading, receiptsLoading,
receiptsPagination, receiptsPagination,
receiptTableQuery, receiptTableQuery,
receiptsCurrentViewId
}) => ({ }) => ({
receiptsCurrentPage, receiptsCurrentPage,
receiptsLoading, receiptsLoading,
receiptsPagination, receiptsPagination,
receiptTableQuery, receiptTableQuery,
receiptsCurrentViewId
}), }),
), ),
)(ReceiptsDataTable); )(ReceiptsDataTable);

View File

@@ -0,0 +1,36 @@
import React from 'react';
import { Button, Intent } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { EmptyStatus } from 'components';
export default function ReceiptsEmptyStatus() {
const history = useHistory();
return (
<EmptyStatus
title={'Manage the organizations services and products.'}
description={
<p>
Here a list of your organization products and services, to be used when you create invoices or bills to your customers or vendors.
</p>
}
action={
<>
<Button
intent={Intent.PRIMARY}
large={true}
onClick={() => {
history.push('/receipts/new');
}}
>
New receipt
</Button>
<Button intent={Intent.NONE} large={true}>
Learn more
</Button>
</>
}
/>
);
}

View File

@@ -4,12 +4,14 @@ import {
getReceiptCurrentPageFactory, getReceiptCurrentPageFactory,
getReceiptsTableQueryFactory, getReceiptsTableQueryFactory,
getReceiptsPaginationMetaFactory, getReceiptsPaginationMetaFactory,
getReceiptsCurrentViewIdFactory
} from 'store/receipt/receipt.selector'; } from 'store/receipt/receipt.selector';
export default (mapState) => { export default (mapState) => {
const getReceiptsItems = getReceiptCurrentPageFactory(); const getReceiptsItems = getReceiptCurrentPageFactory();
const getReceiptPaginationMeta = getReceiptsPaginationMetaFactory(); const getReceiptPaginationMeta = getReceiptsPaginationMetaFactory();
const getReceiptsTableQuery = getReceiptsTableQueryFactory(); const getReceiptsTableQuery = getReceiptsTableQueryFactory();
const getReceiptsCurrentViewId = getReceiptsCurrentViewIdFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const tableQuery = getReceiptsTableQuery(state, props); const tableQuery = getReceiptsTableQuery(state, props);
@@ -23,6 +25,8 @@ export default (mapState) => {
receiptsLoading: state.salesReceipts.loading, receiptsLoading: state.salesReceipts.loading,
receiptNumberChanged: state.salesReceipts.journalNumberChanged, receiptNumberChanged: state.salesReceipts.journalNumberChanged,
receiptsCurrentViewId: getReceiptsCurrentViewId(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;

View File

@@ -31,6 +31,8 @@ const billPaginationSelector = (state, props) => {
return state.bills.views?.[viewId]; return state.bills.views?.[viewId];
}; };
const getBillsCurrentViewIdSelector = (state) => state.bills.currentViewId;
export const getBillTableQueryFactory = () => export const getBillTableQueryFactory = () =>
createSelector( createSelector(
paginationLocationQuery, paginationLocationQuery,
@@ -108,3 +110,12 @@ export const getVendorPayableBillsEntriesFactory = () =>
})); }));
}, },
); );
// Retreive the current bills view id.
export const getBillsCurrentViewIdFactory = () =>
createSelector(
getBillsCurrentViewIdSelector,
(currentViewId) => {
return currentViewId;
}
);

View File

@@ -19,6 +19,10 @@ const estimatesPageSelector = (state, props, query) => {
return state.salesEstimates.views?.[viewId]?.pages?.[currentPageId]; return state.salesEstimates.views?.[viewId]?.pages?.[currentPageId];
}; };
const getEstimatesCurrentViewIdSelector = (state, props) => {
return state.salesEstimates.currentViewId;
};
// Retrieve estimates table query. // Retrieve estimates table query.
export const getEstimatesTableQueryFactory = () => export const getEstimatesTableQueryFactory = () =>
createSelector( createSelector(
@@ -58,3 +62,12 @@ export const getEstimatesPaginationMetaFactory = () =>
...(estimateView?.paginationMeta || {}), ...(estimateView?.paginationMeta || {}),
}; };
}); });
// Retrieve estimates current view id.
export const getEstimatesCurrentViewIdFactory = () =>
createSelector(
getEstimatesCurrentViewIdSelector,
(currentViewId) => {
return currentViewId;
});

View File

@@ -27,6 +27,8 @@ const invoicesItemsSelector = (state) => state.salesInvoices.items;
const invoicesReceiableCustomerSelector = (state, props) => const invoicesReceiableCustomerSelector = (state, props) =>
state.salesInvoices.receivable.byCustomerId[props.customerId]; state.salesInvoices.receivable.byCustomerId[props.customerId];
const getInvoicesCurrentViewIdSelector = (state) => state.salesInvoices.currentViewId;
export const getInvoiceTableQueryFactory = () => export const getInvoiceTableQueryFactory = () =>
createSelector( createSelector(
paginationLocationQuery, paginationLocationQuery,
@@ -51,6 +53,8 @@ export const getInvoiceCurrentPageFactory = () =>
}, },
); );
// Retrieve specific invoice by the passed invoice id. // Retrieve specific invoice by the passed invoice id.
export const getInvoiecsByIdFactory = () => export const getInvoiecsByIdFactory = () =>
createSelector(invoicesByIdSelector, (invoice) => { createSelector(invoicesByIdSelector, (invoice) => {
@@ -83,3 +87,12 @@ export const getCustomerReceivableInvoicesEntriesFactory = () =>
})); }));
}, },
); );
// Retrieve sale invoices current view id.
export const getInvoicesCurrentViewIdFactory = () =>
createSelector(
getInvoicesCurrentViewIdSelector,
(currentViewId) => {
return currentViewId;
}
);

View File

@@ -27,12 +27,17 @@ const paymentMadeById = (state, props) =>
state.paymentMades.items[props.paymentMadeId]; state.paymentMades.items[props.paymentMadeId];
const paymentMadeEntries = (state, props) => props.paymentMadeEntries; const paymentMadeEntries = (state, props) => props.paymentMadeEntries;
const billsItemsSelector = (state, props) => state.bills.items; const billsItemsSelector = (state, props) => state.bills.items;
const billsPayableByPaymentMadeSelector = (state, props) => const billsPayableByPaymentMadeSelector = (state, props) =>
state.bills.payable.byBillPayamentId[props.paymentMadeId]; state.bills.payable.byBillPayamentId[props.paymentMadeId];
const paymentMadeBillsSelector = (state, props) => const paymentMadeBillsSelector = (state, props) =>
state.bills.byBillPayamentId[props.paymentMadeId]; state.bills.byBillPayamentId[props.paymentMadeId];
const paymentMadesCurrentViewIdSelector = (state) => state.paymentMades.currentViewId;
export const getPaymentMadeCurrentPageFactory = () => export const getPaymentMadeCurrentPageFactory = () =>
createSelector( createSelector(
paymentMadesPageSelector, paymentMadesPageSelector,
@@ -113,3 +118,12 @@ export const getPaymentMadeEntriesFactory = () =>
}); });
}, },
); );
// Retrieve payment mades current view id.
export const getPaymentMadesCurrentViewIdFactory = () =>
createSelector(
paymentMadesCurrentViewIdSelector,
(currentViewId) => {
return currentViewId;
}
);

View File

@@ -35,6 +35,9 @@ const paymentReceiveInvoicesSelector = (state, props) =>
const paymentReceiveByIdSelector = (state, props) => const paymentReceiveByIdSelector = (state, props) =>
state.paymentReceives.items[props.paymentReceiveId]; state.paymentReceives.items[props.paymentReceiveId];
const paymentReceivesCurrentViewIdSelector = (state) =>
state.paymentReceives.currentViewId;
// Retrieve payment receive current page results. // Retrieve payment receive current page results.
export const getPaymentReceiveCurrentPageFactory = () => export const getPaymentReceiveCurrentPageFactory = () =>
createSelector( createSelector(
@@ -124,3 +127,10 @@ export const getPaymentReceiveEntriesFactory = () =>
}); });
}, },
); );
// Retrieve payment receives current view id.
export const getPaymentReceivesCurrentViewIdFactory = () =>
createSelector(
paymentReceivesCurrentViewIdSelector,
(currentViewId) => currentViewId,
);

View File

@@ -26,6 +26,8 @@ const customerPageSelector = (state, props) => {
const customersItemsSelector = (state) => state.customers.items; const customersItemsSelector = (state) => state.customers.items;
const customersCurrentViewIdSelector = (state) => state.customers.currentViewId;
export const getCustomerTableQueryFactory = () => export const getCustomerTableQueryFactory = () =>
createSelector( createSelector(
paginationLocationQuery, paginationLocationQuery,
@@ -61,3 +63,8 @@ export const getCustomerPaginationMetaFactory = () =>
...(customerPage?.paginationMeta || {}), ...(customerPage?.paginationMeta || {}),
}; };
}); });
export const getCustomersCurrentViewIdFactory = () =>
createSelector(customersCurrentViewIdSelector, (currentViewId) => {
return currentViewId;
});

View File

@@ -8,6 +8,8 @@ const getPageExpensesQuery = (state, props) => {
return currentPageId || 0; return currentPageId || 0;
}; };
const getExpensesCurrentViewIdSelector = (state) => state.expenses.currentViewId;
const expensesPageSelector = (state, props, query) => { const expensesPageSelector = (state, props, query) => {
const viewId = state.expenses.currentViewId; const viewId = state.expenses.currentViewId;
const currentPageId = getPageExpensesQuery(state, { viewId }); const currentPageId = getPageExpensesQuery(state, { viewId });
@@ -61,3 +63,11 @@ export const getExpensesPaginationMetaFactory = () => createSelector(
return expensesPage?.paginationMeta || {}; return expensesPage?.paginationMeta || {};
}, },
); );
// Retrieve expenses current view id.
export const getExpensesCurrentViewIdFactory = () => createSelector(
getExpensesCurrentViewIdSelector,
(currentViewId) => {
return currentViewId;
},
);

View File

@@ -1,6 +1,8 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { pickItemsFromIds, paginationLocationQuery, defaultPaginationMeta } from 'store/selectors'; import { pickItemsFromIds, paginationLocationQuery, defaultPaginationMeta } from 'store/selectors';
const manualJournalsCurrentViewIdSelector = (state) => state.manualJournals.currentViewId;
const manualJournalsPageSelector = (state) => { const manualJournalsPageSelector = (state) => {
const viewId = state.manualJournals.currentViewId; const viewId = state.manualJournals.currentViewId;
const currentView = state.manualJournals.views?.[viewId]; const currentView = state.manualJournals.views?.[viewId];
@@ -51,3 +53,12 @@ export const getManualJournalsTableQuery = createSelector(
}; };
}, },
); );
// Retrieve manual journals current view id.
export const getManualJournalsCurrentViewIdFactory = () =>
createSelector(
manualJournalsCurrentViewIdSelector,
(currentViewId) => {
return currentViewId;
},
);

View File

@@ -20,6 +20,8 @@ const receiptTableQuery = (state) => state.salesReceipts.tableQuery;
const receiptByIdSelector = (state, props) => state.salesReceipts.items[props.receiptId]; const receiptByIdSelector = (state, props) => state.salesReceipts.items[props.receiptId];
const receiptsCurrentViewIdSelector = (state) => state.salesReceipts.currentViewId;
// Retrieve current page sale receipts results. // Retrieve current page sale receipts results.
export const getReceiptCurrentPageFactory = () => export const getReceiptCurrentPageFactory = () =>
createSelector( createSelector(
@@ -56,3 +58,9 @@ export const getReceiptsPaginationMetaFactory = () =>
createSelector(receiptsPaginationSelector, (receiptPage) => { createSelector(receiptsPaginationSelector, (receiptPage) => {
return receiptPage?.paginationMeta || {}; return receiptPage?.paginationMeta || {};
}); });
// Retrieve receipts current view id.
export const getReceiptsCurrentViewIdFactory = () =>
createSelector(
receiptsCurrentViewIdSelector,
(currentViewId) => currentViewId);

View File

@@ -463,3 +463,40 @@ body.authentication {
} }
} }
} }
.datatable-empty-status{
max-width: 550px;
width: 100%;
margin: 0 auto;
text-align: center;
margin-top: 200px;
&__title{
font-size: 20px;
color: #2c3a5d;
font-weight: 600;
margin-left: auto;
margin-bottom: 12px;
margin-right: auto;
margin-top: 0;
line-height: 1.4;
}
&__desc{
font-size: 16px;
color: #1f3255;
opacity: 0.8;
line-height: 1.6;
}
&__actions{
margin-top: 26px;
.bp3-button{
min-height: 36px;
& + .bp3-button{
margin-left: 10px;
}
}
}
}

View File

@@ -23,9 +23,14 @@
} }
} }
.bp3-button:not([class*="bp3-intent-"]):not(.bp3-minimal){ .bp3-button{
min-width: 32px; min-width: 32px;
min-height: 32px; min-height: 32px;
padding-left: 12px;
padding-right: 12px;
}
.bp3-button:not([class*="bp3-intent-"]):not(.bp3-minimal){
background-color: #E6EFFB; background-color: #E6EFFB;
color: #555555; color: #555555;
box-shadow: 0 0 0 transparent; box-shadow: 0 0 0 transparent;

View File

@@ -239,6 +239,7 @@
} }
&__insider{ &__insider{
margin-bottom: 40px; margin-bottom: 40px;
flex: 1 0 0;
} }
&__offline-badge{ &__offline-badge{
@@ -276,16 +277,19 @@
} }
&__insider{ &__insider{
display: flex;
flex-direction: column;
&--loading{ > .dashboard__loading-indicator{
display: flex; margin-top: auto;
align-items: center; margin-bottom: auto;
justify-content: center;
height: 100%;
} }
} }
&__page-content{ &__page-content{
display: flex;
flex-direction: column;
flex: 1 0 0;
.bigcapital-datatable{ .bigcapital-datatable{
@@ -305,6 +309,18 @@
} }
} }
&__datatable{
display: flex;
flex: 1 0 0;
flex-direction: column;
.datatable-empty-status{
margin-top: auto;
margin-bottom: auto;
padding-bottom: 40px;
}
}
&__preferences-topbar{ &__preferences-topbar{
border-bottom: 1px solid #E5E5E5; border-bottom: 1px solid #E5E5E5;
// height: 70px; // height: 70px;