From 1465100a4b1f7cc0f71c96d400783ef9d92836f1 Mon Sep 17 00:00:00 2001
From: Ahmed Bouhuolia
Date: Tue, 17 Nov 2020 11:31:49 +0200
Subject: [PATCH] feat: tables empty status.
---
client/src/common/classes.js | 8 ++-
client/src/components/EmptyStatus.js | 22 ++++++
client/src/components/LoadingIndicator.js | 44 ++++++++----
client/src/components/index.js | 3 +
.../Accounting/ManualJournalsDataTable.js | 54 ++++++++++-----
.../Accounting/ManualJournalsEmptyStatus.js | 37 ++++++++++
.../Accounting/withManualJournals.js | 4 ++
.../src/containers/Customers/CustomerTable.js | 62 ++++++++++-------
.../Customers/CustomersEmptyStatus.js | 37 ++++++++++
.../src/containers/Customers/withCustomers.js | 3 +
.../containers/Expenses/ExpenseDataTable.js | 54 ++++++++++-----
.../containers/Expenses/ExpensesEmptyState.js | 40 +++++++++++
.../Expenses/ExpensesEmptyStatus.js | 37 ++++++++++
.../src/containers/Expenses/withExpenses.js | 3 +
client/src/containers/Items/ItemFormPage.js | 1 -
client/src/containers/Items/ItemsDataTable.js | 67 ++++++++++--------
.../src/containers/Items/ItemsEmptyStatus.js | 36 ++++++++++
client/src/containers/Items/ItemsList.js | 2 +-
.../Purchases/Bill/BillsDataTable.js | 52 +++++++++-----
.../Purchases/Bill/BillsEmptyStatus.js | 36 ++++++++++
.../containers/Purchases/Bill/withBills.js | 4 ++
.../PaymentMades/PaymentMadeDataTable.js | 56 +++++++++------
.../PaymentMades/PaymentMadesEmptyStatus.js | 37 ++++++++++
.../Purchases/PaymentMades/withPaymentMade.js | 8 ++-
.../Sales/Estimate/EstimateViewTabs.js | 1 -
.../Sales/Estimate/EstimatesDataTable.js | 69 +++++++++++++------
.../Sales/Estimate/EstimatesEmptyStatus.js | 36 ++++++++++
.../Sales/Estimate/withEstimates.js | 4 ++
.../Sales/Invoice/InvoicesDataTable.js | 66 +++++++++++-------
.../Sales/Invoice/InvoicesEmptyStatus.js | 37 ++++++++++
.../containers/Sales/Invoice/withInvoices.js | 5 ++
.../PaymentReceivesDataTable.js | 58 ++++++++++------
.../PaymentReceivesEmptyStatus.js | 37 ++++++++++
.../PaymentReceive/withPaymentReceives.js | 4 ++
.../Sales/Receipt/ReceiptsDataTable.js | 63 ++++++++++-------
.../Sales/Receipt/ReceiptsEmptyStatus.js | 36 ++++++++++
.../containers/Sales/Receipt/withReceipts.js | 4 ++
client/src/store/Bills/bills.selectors.js | 11 +++
.../src/store/Estimate/estimates.selectors.js | 13 ++++
client/src/store/Invoice/invoices.selector.js | 13 ++++
.../PaymentMades/paymentMade.selector.js | 14 ++++
.../PaymentReceive/paymentReceive.selector.js | 10 +++
.../store/customers/customers.selectors.js | 7 ++
.../src/store/expenses/expenses.selectors.js | 10 +++
.../manualJournals.selectors.js | 11 +++
client/src/store/receipt/receipt.selector.js | 8 +++
client/src/style/App.scss | 37 ++++++++++
client/src/style/objects/buttons.scss | 7 +-
client/src/style/pages/dashboard.scss | 26 +++++--
49 files changed, 1050 insertions(+), 244 deletions(-)
create mode 100644 client/src/components/EmptyStatus.js
create mode 100644 client/src/containers/Accounting/ManualJournalsEmptyStatus.js
create mode 100644 client/src/containers/Customers/CustomersEmptyStatus.js
create mode 100644 client/src/containers/Expenses/ExpensesEmptyState.js
create mode 100644 client/src/containers/Expenses/ExpensesEmptyStatus.js
create mode 100644 client/src/containers/Items/ItemsEmptyStatus.js
create mode 100644 client/src/containers/Purchases/Bill/BillsEmptyStatus.js
create mode 100644 client/src/containers/Purchases/PaymentMades/PaymentMadesEmptyStatus.js
create mode 100644 client/src/containers/Sales/Estimate/EstimatesEmptyStatus.js
create mode 100644 client/src/containers/Sales/Invoice/InvoicesEmptyStatus.js
create mode 100644 client/src/containers/Sales/PaymentReceive/PaymentReceivesEmptyStatus.js
create mode 100644 client/src/containers/Sales/Receipt/ReceiptsEmptyStatus.js
diff --git a/client/src/common/classes.js b/client/src/common/classes.js
index 22d3c1b2f..570417074 100644
--- a/client/src/common/classes.js
+++ b/client/src/common/classes.js
@@ -1,6 +1,7 @@
import { Classes } from '@blueprintjs/core';
const CLASSES = {
+ DASHBOARD_DATATABLE: 'dashboard__datatable',
DATATABLE_EDITOR: 'datatable-editor',
DATATABLE_EDITOR_ACTIONS: 'datatable-editor__actions',
DATATABLE_EDITOR_ITEMS_ENTRIES: 'items-entries-table',
@@ -30,8 +31,11 @@ const CLASSES = {
CLOUD_SPINNER: 'cloud-spinner',
IS_LOADING: 'is-loading',
- DATATABLE_EMPTY_STATE: 'datatable-empty-state',
- DATATABLE_EMPTY_STATE_TITLE: 'datatable-empty-state__title',
+ DATATABLE_EMPTY_STATUS: 'datatable-empty-status',
+ 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,
};
diff --git a/client/src/components/EmptyStatus.js b/client/src/components/EmptyStatus.js
new file mode 100644
index 000000000..4a5c2ec07
--- /dev/null
+++ b/client/src/components/EmptyStatus.js
@@ -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 (
+
+
+ {title}
+
+
+
+ {description}
+
+
+
+ {action}
+
+ {children}
+
+ );
+}
diff --git a/client/src/components/LoadingIndicator.js b/client/src/components/LoadingIndicator.js
index cad74aa56..7f88d3842 100644
--- a/client/src/components/LoadingIndicator.js
+++ b/client/src/components/LoadingIndicator.js
@@ -1,39 +1,53 @@
-import React, {useState, useEffect, useMemo} from 'react';
+import React, { useState, useEffect, useMemo } from 'react';
import { Spinner } from '@blueprintjs/core';
export default function LoadingIndicator({
loading,
spinnerSize = 40,
children,
- mount = true,
+ mount = false,
}) {
const [rendered, setRendered] = useState(mount);
useEffect(() => {
- if (!loading) { setRendered(true); }
+ if (!loading) {
+ setRendered(true);
+ }
}, [loading]);
const componentStyle = useMemo(() => {
- return {display: !loading ? 'block' : 'none'};
+ return { display: !loading ? 'block' : 'none' };
}, [loading]);
- const loadingComponent = useMemo(() => (
-
-
-
- ), [spinnerSize]);
+ const loadingComponent = useMemo(
+ () => (
+
+
+
+ ),
+ [spinnerSize],
+ );
- const renderComponent = useMemo(() => (
- { children }
- ), [children, componentStyle]);
+ // Renders children with wrapper or without wrapper, in mount mode
+ // rendering with wrapper.
+ const renderChildren = useMemo(
+ () => (mount ? {children}
: 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;
return (
<>
- { maybeRenderLoadingSpinner }
- { maybeRenderComponent }
+ {maybeRenderLoadingSpinner}
+ {maybeRenderComponent}
>
);
}
diff --git a/client/src/components/index.js b/client/src/components/index.js
index 41042cb7e..5d7d8e9cc 100644
--- a/client/src/components/index.js
+++ b/client/src/components/index.js
@@ -1,3 +1,4 @@
+
import If from './Utils/If';
import Money from './Money';
import Icon from './Icon';
@@ -36,6 +37,7 @@ import SalutationList from './SalutationList';
import DisplayNameList from './DisplayNameList';
import MoneyInputGroup from './MoneyInputGroup';
import Dragzone from './Dragzone';
+import EmptyStatus from './EmptyStatus';
const Hint = FieldHint;
@@ -79,4 +81,5 @@ export {
SalutationList,
MoneyInputGroup,
Dragzone,
+ EmptyStatus
};
diff --git a/client/src/containers/Accounting/ManualJournalsDataTable.js b/client/src/containers/Accounting/ManualJournalsDataTable.js
index 484a4d545..055754c9f 100644
--- a/client/src/containers/Accounting/ManualJournalsDataTable.js
+++ b/client/src/containers/Accounting/ManualJournalsDataTable.js
@@ -25,6 +25,8 @@ import {
} from 'components';
import { useIsValuePassed } from 'hooks';
+import ManualJournalsEmptyStatus from './ManualJournalsEmptyStatus';
+
import withDialogActions from 'containers/Dialog/withDialogActions';
import withManualJournals from 'containers/Accounting/withManualJournals';
import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions';
@@ -76,6 +78,7 @@ function ManualJournalsDataTable({
manualJournalsLoading,
manualJournalsPagination,
manualJournalsTableQuery,
+ manualJournalsCurrentViewId,
// #withManualJournalsActions
addManualJournalsTableQueries,
@@ -248,26 +251,39 @@ function ManualJournalsDataTable({
[onSelectedRowsChange],
);
+ const showEmptyStatus = [
+ manualJournalsCurrentViewId === -1,
+ manualJournalsCurrentPage.length === 0,
+ ].every(condition => condition === true);
+
return (
-
+
+
+
+
+
+
+
+
+
);
}
@@ -282,11 +298,13 @@ export default compose(
manualJournalsLoading,
manualJournalsPagination,
manualJournalsTableQuery,
+ manualJournalsCurrentViewId,
}) => ({
manualJournalsCurrentPage,
manualJournalsLoading,
manualJournalsPagination,
manualJournalsTableQuery,
+ manualJournalsCurrentViewId
}),
),
)(ManualJournalsDataTable);
diff --git a/client/src/containers/Accounting/ManualJournalsEmptyStatus.js b/client/src/containers/Accounting/ManualJournalsEmptyStatus.js
new file mode 100644
index 000000000..d77d998a7
--- /dev/null
+++ b/client/src/containers/Accounting/ManualJournalsEmptyStatus.js
@@ -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 (
+
+ It is a long established fact that a reader will be distracted by the
+ readable content of a page when looking at its layout.
+
+ }
+ action={
+ <>
+ {
+ history.push('/invoices/new');
+ }}
+ >
+ Make journal
+
+
+
+ Learn more
+
+ >
+ }
+ />
+ );
+}
diff --git a/client/src/containers/Accounting/withManualJournals.js b/client/src/containers/Accounting/withManualJournals.js
index 83bdd4d4a..02642aff9 100644
--- a/client/src/containers/Accounting/withManualJournals.js
+++ b/client/src/containers/Accounting/withManualJournals.js
@@ -4,10 +4,12 @@ import {
getManualJournalsItems,
getManualJournalsPagination,
getManualJournalsTableQuery,
+ getManualJournalsCurrentViewIdFactory
} from 'store/manualJournals/manualJournals.selectors';
export default (mapState) => {
+ const getManualJournalsCurrentViewId = getManualJournalsCurrentViewIdFactory();
const mapStateToProps = (state, props) => {
const query = getManualJournalsTableQuery(state, props);
@@ -21,6 +23,8 @@ export default (mapState) => {
manualJournalsLoading: state.manualJournals.loading,
journalNumberChanged: state.manualJournals.journalNumberChanged,
+
+ manualJournalsCurrentViewId: getManualJournalsCurrentViewId(state, props),
};
return mapState ? mapState(mapped, state, props) : mapped;
};
diff --git a/client/src/containers/Customers/CustomerTable.js b/client/src/containers/Customers/CustomerTable.js
index dbe4226c6..9fae8acbf 100644
--- a/client/src/containers/Customers/CustomerTable.js
+++ b/client/src/containers/Customers/CustomerTable.js
@@ -1,4 +1,4 @@
-import React, { useRef, useEffect, useCallback, useMemo } from 'react';
+import React, { useCallback, useMemo } from 'react';
import {
Button,
Popover,
@@ -11,8 +11,8 @@ import {
import { FormattedMessage as T, useIntl } from 'react-intl';
import { useIsValuePassed } from 'hooks';
-import LoadingIndicator from 'components/LoadingIndicator';
-import { DataTable, Icon, Money } from 'components';
+import CustomersEmptyStatus from './CustomersEmptyStatus';
+import { DataTable, Icon, Money, Choose, LoadingIndicator } from 'components';
import withCustomers from './withCustomers';
import withCustomersActions from './withCustomersActions';
@@ -29,6 +29,7 @@ const CustomerTable = ({
customersLoading,
customerPagination,
customersTableQuery,
+ customersCurrentViewId,
// #withCustomersActions
addCustomersTableQueries,
@@ -182,31 +183,44 @@ const CustomerTable = ({
onDeleteCustomer,
});
+ const showEmptyStatus = [
+ customersCurrentViewId === -1,
+ customers.length === 0,
+ ].every(condition => condition === true);
+
return (
-
+
+
+
+
+
+
+
+
+
);
};
@@ -218,11 +232,13 @@ export default compose(
customersLoading,
customerPagination,
customersTableQuery,
+ customersCurrentViewId,
}) => ({
customers,
customersLoading,
customerPagination,
customersTableQuery,
+ customersCurrentViewId
}),
),
withCustomersActions,
diff --git a/client/src/containers/Customers/CustomersEmptyStatus.js b/client/src/containers/Customers/CustomersEmptyStatus.js
new file mode 100644
index 000000000..a957e8b8e
--- /dev/null
+++ b/client/src/containers/Customers/CustomersEmptyStatus.js
@@ -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 (
+
+ Here a list of your organization products and services, to be used
+ when you create invoices or bills to your customers or vendors.
+
+ }
+ action={
+ <>
+ {
+ history.push('/customers/new');
+ }}
+ >
+ New customer
+
+
+
+ Learn more
+
+ >
+ }
+ />
+ );
+}
diff --git a/client/src/containers/Customers/withCustomers.js b/client/src/containers/Customers/withCustomers.js
index 72fba99c2..5dce50e19 100644
--- a/client/src/containers/Customers/withCustomers.js
+++ b/client/src/containers/Customers/withCustomers.js
@@ -4,11 +4,13 @@ import {
getCustomerCurrentPageFactory,
getCustomerPaginationMetaFactory,
getCustomerTableQueryFactory,
+ getCustomersCurrentViewIdFactory,
} from 'store/customers/customers.selectors';
export default (mapState) => {
const getCustomersList = getCustomerCurrentPageFactory();
const getCustomerPaginationMeta = getCustomerPaginationMetaFactory();
+ const getCustomersCurrentViewId = getCustomersCurrentViewIdFactory();
const getCustomerTableQuery = getCustomerTableQueryFactory();
const mapStateToProps = (state, props) => {
@@ -21,6 +23,7 @@ export default (mapState) => {
customerPagination: getCustomerPaginationMeta(state, props, query),
customersLoading: state.customers.loading,
customersItems: state.customers.items,
+ customersCurrentViewId: getCustomersCurrentViewId(state, props),
// customerErrors: state.customers.errors,
};
return mapState ? mapState(mapped, state, props) : mapped;
diff --git a/client/src/containers/Expenses/ExpenseDataTable.js b/client/src/containers/Expenses/ExpenseDataTable.js
index 0abc80b35..cb2c9b954 100644
--- a/client/src/containers/Expenses/ExpenseDataTable.js
+++ b/client/src/containers/Expenses/ExpenseDataTable.js
@@ -20,9 +20,9 @@ import Icon from 'components/Icon';
import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks';
-import LoadingIndicator from 'components/LoadingIndicator';
-import { If, Money } from 'components';
+import { If, Money, Choose, LoadingIndicator } from 'components';
import DataTable from 'components/DataTable';
+import ExpensesEmptyStatus from './ExpensesEmptyStatus';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
@@ -37,6 +37,7 @@ function ExpensesDataTable({
expensesLoading,
expensesPagination,
expensesTableQuery,
+ expensesCurrentViewId,
// #withExpensesActions
addExpensesTableQueries,
@@ -265,28 +266,41 @@ function ExpensesDataTable({
[onSelectedRowsChange],
);
+ const showEmptyStatus = [
+ expensesCurrentViewId === -1,
+ expensesCurrentPage.length === 0
+ ].every(condition => condition === true);
+
return (
-
+
+
+
+
+
+
+
+
+
);
}
@@ -303,11 +317,13 @@ export default compose(
expensesLoading,
expensesPagination,
expensesTableQuery,
+ expensesCurrentViewId,
}) => ({
expensesCurrentPage,
expensesLoading,
expensesPagination,
expensesTableQuery,
+ expensesCurrentViewId,
}),
),
withViewDetails(),
diff --git a/client/src/containers/Expenses/ExpensesEmptyState.js b/client/src/containers/Expenses/ExpensesEmptyState.js
new file mode 100644
index 000000000..6860f7455
--- /dev/null
+++ b/client/src/containers/Expenses/ExpensesEmptyState.js
@@ -0,0 +1,40 @@
+import React from 'react';
+
+function DatatableEmptyState({
+ title,
+ description,
+ newButtonText,
+ newButtonUrl,
+
+ learnMoreButtonText,
+ learnMoreButtonUrl,
+}) {
+
+
+ return (
+
+
+ { title }
+
+
+ )
+}
+
+
+export default function ExpensesEmptyState({
+
+}) {
+
+
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/client/src/containers/Expenses/ExpensesEmptyStatus.js b/client/src/containers/Expenses/ExpensesEmptyStatus.js
new file mode 100644
index 000000000..b48c5e79b
--- /dev/null
+++ b/client/src/containers/Expenses/ExpensesEmptyStatus.js
@@ -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 (
+
+ It is a long established fact that a reader will be distracted by the
+ readable content of a page when looking at its layout.
+
+ }
+ action={
+ <>
+ {
+ history.push('/expenses/new');
+ }}
+ >
+ New expense
+
+
+
+ Learn more
+
+ >
+ }
+ />
+ );
+}
diff --git a/client/src/containers/Expenses/withExpenses.js b/client/src/containers/Expenses/withExpenses.js
index 4eaeb6053..a7bfd0029 100644
--- a/client/src/containers/Expenses/withExpenses.js
+++ b/client/src/containers/Expenses/withExpenses.js
@@ -5,11 +5,13 @@ import {
getExpenseByIdFactory,
getExpensesTableQuery,
getExpensesPaginationMetaFactory,
+ getExpensesCurrentViewIdFactory,
} from 'store/expenses/expenses.selectors';
export default (mapState) => {
const getExpensesItems = getExpensesCurrentPageFactory();
const getExpensesPaginationMeta = getExpensesPaginationMetaFactory();
+ const getExpensesCurrentViewId = getExpensesCurrentViewIdFactory();
const mapStateToProps = (state, props) => {
const query = getExpensesTableQuery(state, props);
@@ -21,6 +23,7 @@ export default (mapState) => {
expensesTableQuery: query,
expensesPagination: getExpensesPaginationMeta(state, props),
expensesLoading: state.expenses.loading,
+ expensesCurrentViewId: getExpensesCurrentViewId(state, props),
};
return mapState ? mapState(mapped, state, props) : mapped;
};
diff --git a/client/src/containers/Items/ItemFormPage.js b/client/src/containers/Items/ItemFormPage.js
index 28af781ae..a1514437c 100644
--- a/client/src/containers/Items/ItemFormPage.js
+++ b/client/src/containers/Items/ItemFormPage.js
@@ -50,7 +50,6 @@ const ItemFormContainer = ({
);
const handleCancel = useCallback(() => {
- // history.push('/items');
history.goBack();
}, [history]);
diff --git a/client/src/containers/Items/ItemsDataTable.js b/client/src/containers/Items/ItemsDataTable.js
index 4f073b292..738e3e401 100644
--- a/client/src/containers/Items/ItemsDataTable.js
+++ b/client/src/containers/Items/ItemsDataTable.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect, useCallback, useMemo } from 'react';
+import React, { useCallback, useMemo } from 'react';
import {
Button,
Popover,
@@ -10,14 +10,18 @@ import {
Tag,
} from '@blueprintjs/core';
import { FormattedMessage as T, useIntl } from 'react-intl';
-import { Icon, DataTable, Money } from 'components';
-import { useIsValuePassed } from 'hooks';
+import classNames from 'classnames';
+
+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 withItemsActions from 'containers/Items/withItemsActions';
import { compose, saveInvoke } from 'utils';
+// Items datatable.
function ItemsDataTable({
// #withItems
itemsTableLoading,
@@ -181,31 +185,38 @@ function ItemsDataTable({
);
return (
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
);
-};
+}
export default compose(
withItems(({ itemsCurrentPage, itemsTableLoading, itemsTableQuery }) => ({
diff --git a/client/src/containers/Items/ItemsEmptyStatus.js b/client/src/containers/Items/ItemsEmptyStatus.js
new file mode 100644
index 000000000..01682e478
--- /dev/null
+++ b/client/src/containers/Items/ItemsEmptyStatus.js
@@ -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 (
+
+ Here a list of your organization products and services, to be used when you create invoices or bills to your customers or vendors.
+
+ }
+ action={
+ <>
+ {
+ history.push('/items/new');
+ }}
+ >
+ New Item
+
+
+
+ Learn more
+
+ >
+ }
+ />
+ );
+}
diff --git a/client/src/containers/Items/ItemsList.js b/client/src/containers/Items/ItemsList.js
index 387d1bba4..4c7d89f9a 100644
--- a/client/src/containers/Items/ItemsList.js
+++ b/client/src/containers/Items/ItemsList.js
@@ -50,7 +50,7 @@ function ItemsList({
useEffect(() => {
changePageTitle(formatMessage({ id: 'items_list' }));
- }, [changePageTitle]);
+ }, [changePageTitle, formatMessage]);
// Handle fetching the resource views.
const fetchResourceViews = useQuery(
diff --git a/client/src/containers/Purchases/Bill/BillsDataTable.js b/client/src/containers/Purchases/Bill/BillsDataTable.js
index bb73b2574..50cf57c0b 100644
--- a/client/src/containers/Purchases/Bill/BillsDataTable.js
+++ b/client/src/containers/Purchases/Bill/BillsDataTable.js
@@ -19,8 +19,9 @@ import Icon from 'components/Icon';
import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks';
-import LoadingIndicator from 'components/LoadingIndicator';
+import { LoadingIndicator, Choose } from 'components';
import DataTable from 'components/DataTable';
+import BillsEmptyStatus from './BillsEmptyStatus';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
@@ -30,11 +31,13 @@ import withBills from './withBills';
import withBillActions from './withBillActions';
import withCurrentView from 'containers/Views/withCurrentView';
+// Bills transactions datatable.
function BillsDataTable({
- //#withBills
+ // #withBills
billsCurrentPage,
billsLoading,
billsPageination,
+ billsCurrentViewId,
// #withDashboardActions
changeCurrentView,
@@ -215,23 +218,36 @@ function BillsDataTable({
[onSelectedRowsChange],
);
+ const showEmptyStatus = [
+ billsCurrentViewId === -1,
+ billsCurrentPage.length === 0,
+ ].every(condition => condition === true);
+
return (
-
+
+
+
+
+
+
+
+
+
);
}
@@ -248,11 +264,13 @@ export default compose(
billsLoading,
billsPageination,
billsTableQuery,
+ billsCurrentViewId
}) => ({
billsCurrentPage,
billsLoading,
billsPageination,
billsTableQuery,
+ billsCurrentViewId
}),
),
withViewDetails(),
diff --git a/client/src/containers/Purchases/Bill/BillsEmptyStatus.js b/client/src/containers/Purchases/Bill/BillsEmptyStatus.js
new file mode 100644
index 000000000..fd42a941d
--- /dev/null
+++ b/client/src/containers/Purchases/Bill/BillsEmptyStatus.js
@@ -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 (
+
+ Here a list of your organization products and services, to be used when you create invoices or bills to your customers or vendors.
+
+ }
+ action={
+ <>
+ {
+ history.push('/bills/new');
+ }}
+ >
+ New bill
+
+
+
+ Learn more
+
+ >
+ }
+ />
+ );
+}
diff --git a/client/src/containers/Purchases/Bill/withBills.js b/client/src/containers/Purchases/Bill/withBills.js
index 94bebc7e2..8cb6c5bfe 100644
--- a/client/src/containers/Purchases/Bill/withBills.js
+++ b/client/src/containers/Purchases/Bill/withBills.js
@@ -6,6 +6,7 @@ import {
getBillTableQueryFactory,
getVendorPayableBillsFactory,
getVendorPayableBillsEntriesFactory,
+ getBillsCurrentViewIdFactory,
} from 'store/Bills/bills.selectors';
export default (mapState) => {
@@ -14,12 +15,14 @@ export default (mapState) => {
const getBillTableQuery = getBillTableQueryFactory();
const getVendorPayableBills = getVendorPayableBillsFactory();
const getVendorPayableBillsEntries = getVendorPayableBillsEntriesFactory();
+ const getBillsCurrentViewId = getBillsCurrentViewIdFactory();
const mapStateToProps = (state, props) => {
const tableQuery = getBillTableQuery(state, props);
const mapped = {
billsCurrentPage: getBillsItems(state, props, tableQuery),
+ billsCurrentViewId: getBillsCurrentViewId(state),
billsViews: getResourceViews(state, props, 'bills'),
billsItems: state.bills.items,
billsTableQuery: tableQuery,
@@ -29,6 +32,7 @@ export default (mapState) => {
nextBillNumberChanged: state.bills.nextBillNumberChanged,
vendorPayableBills: getVendorPayableBills(state, props),
vendorPayableBillsEntries: getVendorPayableBillsEntries(state, props),
+
};
return mapState ? mapState(mapped, state, props) : mapped;
};
diff --git a/client/src/containers/Purchases/PaymentMades/PaymentMadeDataTable.js b/client/src/containers/Purchases/PaymentMades/PaymentMadeDataTable.js
index edb49e75c..d265cce53 100644
--- a/client/src/containers/Purchases/PaymentMades/PaymentMadeDataTable.js
+++ b/client/src/containers/Purchases/PaymentMades/PaymentMadeDataTable.js
@@ -15,8 +15,8 @@ import moment from 'moment';
import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks';
-import LoadingIndicator from 'components/LoadingIndicator';
-import { DataTable, Money, Icon } from 'components';
+import { DataTable, Money, Icon, Choose, LoadingIndicator } from 'components';
+import PaymentMadesEmptyStatus from './PaymentMadesEmptyStatus';
import withPaymentMade from './withPaymentMade';
import withPaymentMadeActions from './withPaymentMadeActions';
@@ -31,6 +31,7 @@ function PaymentMadeDataTable({
paymentMadePageination,
paymentMadesLoading,
paymentMadeTableQuery,
+ paymentMadesCurrentViewId,
// #withPaymentMadeActions
addPaymentMadesTableQueries,
@@ -178,25 +179,38 @@ function PaymentMadeDataTable({
[onSelectedRowsChange],
);
+ const showEmptyStatuts = [
+ paymentMadeCurrentPage.length === 0,
+ paymentMadesCurrentViewId === -1,
+ ].every(condition => condition === true);
+
return (
-
-
+
+
+
+
+
+
+
+
+
+
);
}
@@ -211,11 +225,13 @@ export default compose(
paymentMadesLoading,
paymentMadePageination,
paymentMadeTableQuery,
+ paymentMadesCurrentViewId
}) => ({
paymentMadeCurrentPage,
paymentMadesLoading,
paymentMadePageination,
paymentMadeTableQuery,
+ paymentMadesCurrentViewId
}),
),
)(PaymentMadeDataTable);
diff --git a/client/src/containers/Purchases/PaymentMades/PaymentMadesEmptyStatus.js b/client/src/containers/Purchases/PaymentMades/PaymentMadesEmptyStatus.js
new file mode 100644
index 000000000..781a804cd
--- /dev/null
+++ b/client/src/containers/Purchases/PaymentMades/PaymentMadesEmptyStatus.js
@@ -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 (
+
+ It is a long established fact that a reader will be distracted by the
+ readable content of a page when looking at its layout.
+
+ }
+ action={
+ <>
+ {
+ history.push('/payment-made/new');
+ }}
+ >
+ New bill payment
+
+
+
+ Learn more
+
+ >
+ }
+ />
+ );
+}
diff --git a/client/src/containers/Purchases/PaymentMades/withPaymentMade.js b/client/src/containers/Purchases/PaymentMades/withPaymentMade.js
index 4aa1bf8b9..e44dc19b9 100644
--- a/client/src/containers/Purchases/PaymentMades/withPaymentMade.js
+++ b/client/src/containers/Purchases/PaymentMades/withPaymentMade.js
@@ -1,20 +1,22 @@
import { connect } from 'react-redux';
-
import { getResourceViews } from 'store/customViews/customViews.selectors';
import {
getPaymentMadeCurrentPageFactory,
getPaymentMadePaginationMetaFactory,
getPaymentMadeTableQuery,
- getPaymentMadeEntriesFactory
+ getPaymentMadeEntriesFactory,
+ getPaymentMadesCurrentViewIdFactory
} from 'store/PaymentMades/paymentMade.selector';
export default (mapState) => {
const getPyamentMadesItems = getPaymentMadeCurrentPageFactory();
const getPyamentMadesPaginationMeta = getPaymentMadePaginationMetaFactory();
const getPaymentMadeEntries = getPaymentMadeEntriesFactory();
+ const getPaymentMadesCurrentViewId = getPaymentMadesCurrentViewIdFactory();
const mapStateToProps = (state, props) => {
const query = getPaymentMadeTableQuery(state, props);
+
const mapped = {
paymentMadeCurrentPage: getPyamentMadesItems(state, props, query),
paymentMadeViews: getResourceViews(state, props, 'bill_payments'),
@@ -28,6 +30,8 @@ export default (mapState) => {
paymentMadesLoading: state.paymentMades.loading,
nextPaymentNumberChanged: state.paymentMades.nextPaymentNumberChanged,
paymentMadeEntries: getPaymentMadeEntries(state, props),
+
+ paymentMadesCurrentViewId: getPaymentMadesCurrentViewId(state, props),
};
return mapState ? mapState(mapped, state, props) : mapped;
};
diff --git a/client/src/containers/Sales/Estimate/EstimateViewTabs.js b/client/src/containers/Sales/Estimate/EstimateViewTabs.js
index 1583aebd7..5d2ec86cd 100644
--- a/client/src/containers/Sales/Estimate/EstimateViewTabs.js
+++ b/client/src/containers/Sales/Estimate/EstimateViewTabs.js
@@ -76,7 +76,6 @@ function EstimateViewTabs({
history.push('/custom_views/estimates/new');
};
- console.log(estimateViews, 'estimateViews');
return (
diff --git a/client/src/containers/Sales/Estimate/EstimatesDataTable.js b/client/src/containers/Sales/Estimate/EstimatesDataTable.js
index 543288541..54c206ed0 100644
--- a/client/src/containers/Sales/Estimate/EstimatesDataTable.js
+++ b/client/src/containers/Sales/Estimate/EstimatesDataTable.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useCallback, useState, useMemo } from 'react';
+import React, { useCallback, useMemo } from 'react';
import {
Intent,
Button,
@@ -8,15 +8,17 @@ import {
MenuDivider,
Position,
} from '@blueprintjs/core';
-import { withRouter } from 'react-router';
+import classNames from 'classnames';
import { FormattedMessage as T, useIntl } from 'react-intl';
import moment from 'moment';
+import { CLASSES } from 'common/classes';
import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks';
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 withEstimateActions from './withEstimateActions';
@@ -28,6 +30,7 @@ function EstimatesDataTable({
estimatesLoading,
estimatesPageination,
estimatesTableQuery,
+ estimatesCurrentViewId,
// #withEstimatesActions
addEstimatesTableQueries,
@@ -177,35 +180,57 @@ function EstimatesDataTable({
[onSelectedRowsChange],
);
+ const showEmptyStatus = [
+ estimatesCurrentPage.length === 0,
+ estimatesCurrentViewId === -1,
+ ].every(d => d === true);
+
return (
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
export default compose(
withEstimateActions,
withEstimates(
- ({ estimatesCurrentPage, estimatesLoading, estimatesPageination, estimatesTableQuery }) => ({
+ ({
estimatesCurrentPage,
estimatesLoading,
estimatesPageination,
- estimatesTableQuery
+ estimatesTableQuery,
+ estimatesCurrentViewId,
+ }) => ({
+ estimatesCurrentPage,
+ estimatesLoading,
+ estimatesPageination,
+ estimatesTableQuery,
+ estimatesCurrentViewId,
}),
),
)(EstimatesDataTable);
diff --git a/client/src/containers/Sales/Estimate/EstimatesEmptyStatus.js b/client/src/containers/Sales/Estimate/EstimatesEmptyStatus.js
new file mode 100644
index 000000000..7b49174bd
--- /dev/null
+++ b/client/src/containers/Sales/Estimate/EstimatesEmptyStatus.js
@@ -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 (
+
+ It is a long established fact that a reader will be distracted by the
+ readable content of a page when looking at its layout.
+
+ }
+ action={
+ <>
+ {
+ history.push('/estimates/new');
+ }}
+ >
+ New sale estimate
+
+
+ Learn more
+
+ >
+ }
+ />
+ );
+}
diff --git a/client/src/containers/Sales/Estimate/withEstimates.js b/client/src/containers/Sales/Estimate/withEstimates.js
index b16cae887..589e4a032 100644
--- a/client/src/containers/Sales/Estimate/withEstimates.js
+++ b/client/src/containers/Sales/Estimate/withEstimates.js
@@ -4,18 +4,22 @@ import {
getEstimateCurrentPageFactory,
getEstimatesTableQueryFactory,
getEstimatesPaginationMetaFactory,
+ getEstimatesCurrentViewIdFactory,
} from 'store/Estimate/estimates.selectors';
export default (mapState) => {
const getEstimatesItems = getEstimateCurrentPageFactory();
const getEstimatesPaginationMeta = getEstimatesPaginationMetaFactory();
const getEstimatesTableQuery = getEstimatesTableQueryFactory();
+ const getEstimatesCurrentViewId = getEstimatesCurrentViewIdFactory();
const mapStateToProps = (state, props) => {
const query = getEstimatesTableQuery(state, props);
const mapped = {
estimatesCurrentPage: getEstimatesItems(state, props, query),
+ estimatesCurrentViewId: getEstimatesCurrentViewId(state, props),
+
estimateViews: getResourceViews(state, props, 'sales_estimates'),
estimateItems: state.salesEstimates.items,
diff --git a/client/src/containers/Sales/Invoice/InvoicesDataTable.js b/client/src/containers/Sales/Invoice/InvoicesDataTable.js
index 4f1c3d5d6..54191b1a4 100644
--- a/client/src/containers/Sales/Invoice/InvoicesDataTable.js
+++ b/client/src/containers/Sales/Invoice/InvoicesDataTable.js
@@ -11,12 +11,15 @@ import {
import { withRouter } from 'react-router';
import { FormattedMessage as T, useIntl } from 'react-intl';
import moment from 'moment';
+import classNames from 'classnames';
+
+import { CLASSES } from 'common/classes';
import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks';
-import LoadingIndicator from 'components/LoadingIndicator';
-import { DataTable, Money, Icon } from 'components';
+import { LoadingIndicator, Choose, DataTable, Money, Icon } from 'components';
+import InvoicesEmptyStatus from './InvoicesEmptyStatus';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
@@ -32,6 +35,7 @@ function InvoicesDataTable({
invoicesCurrentPage,
invoicesLoading,
invoicesPageination,
+ invoicesCurrentViewId,
// #withInvoicesActions
addInvoiceTableQueries,
@@ -186,29 +190,41 @@ function InvoicesDataTable({
[onSelectedRowsChange],
);
+ const showEmptyStatus = [
+ invoicesCurrentPage.length === 0,
+ invoicesCurrentViewId === -1,
+ ].every((d) => d === true);
+
return (
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
@@ -224,11 +240,13 @@ export default compose(
invoicesLoading,
invoicesPageination,
invoicesTableQuery,
+ invoicesCurrentViewId,
}) => ({
invoicesCurrentPage,
invoicesLoading,
invoicesPageination,
invoicesTableQuery,
+ invoicesCurrentViewId,
}),
),
withViewDetails(),
diff --git a/client/src/containers/Sales/Invoice/InvoicesEmptyStatus.js b/client/src/containers/Sales/Invoice/InvoicesEmptyStatus.js
new file mode 100644
index 000000000..80bd64d3b
--- /dev/null
+++ b/client/src/containers/Sales/Invoice/InvoicesEmptyStatus.js
@@ -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 (
+
+ It is a long established fact that a reader will be distracted by the
+ readable content of a page when looking at its layout.
+
+ }
+ action={
+ <>
+ {
+ history.push('/invoices/new');
+ }}
+ >
+ New sale invoice
+
+
+
+ Learn more
+
+ >
+ }
+ />
+ );
+ }
diff --git a/client/src/containers/Sales/Invoice/withInvoices.js b/client/src/containers/Sales/Invoice/withInvoices.js
index 4ac74e14a..3cba569f8 100644
--- a/client/src/containers/Sales/Invoice/withInvoices.js
+++ b/client/src/containers/Sales/Invoice/withInvoices.js
@@ -5,6 +5,7 @@ import {
getInvoicePaginationMetaFactory,
getInvoiceTableQueryFactory,
getCustomerReceivableInvoicesEntriesFactory,
+ getInvoicesCurrentViewIdFactory,
} from 'store/Invoice/invoices.selector';
export default (mapState) => {
@@ -15,11 +16,15 @@ export default (mapState) => {
const getCustomerReceivableInvoicesEntries = getCustomerReceivableInvoicesEntriesFactory();
+ const getInvoicesCurrentViewId = getInvoicesCurrentViewIdFactory();
+
const mapStateToProps = (state, props) => {
const query = getInvoiceTableQuery(state, props);
const mapped = {
invoicesCurrentPage: getInvoicesItems(state, props, query),
+ invoicesCurrentViewId: getInvoicesCurrentViewId(state, props),
+
invoicesViews: getResourceViews(state, props, 'sales_invoices'),
invoicesItems: state.salesInvoices.items,
invoicesTableQuery: query,
diff --git a/client/src/containers/Sales/PaymentReceive/PaymentReceivesDataTable.js b/client/src/containers/Sales/PaymentReceive/PaymentReceivesDataTable.js
index bae523957..74f406bf5 100644
--- a/client/src/containers/Sales/PaymentReceive/PaymentReceivesDataTable.js
+++ b/client/src/containers/Sales/PaymentReceive/PaymentReceivesDataTable.js
@@ -15,8 +15,8 @@ import moment from 'moment';
import { compose, saveInvoke } from 'utils';
import { useIsValuePassed } from 'hooks';
-import LoadingIndicator from 'components/LoadingIndicator';
-import { DataTable, Money, Icon } from 'components';
+import PaymentReceivesEmptyStatus from './PaymentReceivesEmptyStatus';
+import { LoadingIndicator, DataTable, Choose, Money, Icon } from 'components';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
@@ -32,6 +32,7 @@ function PaymentReceivesDataTable({
paymentReceivesPageination,
paymentReceivesLoading,
paymentReceivesTableQuery,
+ paymentReceivesCurrentViewId,
// #withPaymentReceivesActions
addPaymentReceivesTableQueries,
@@ -179,28 +180,41 @@ function PaymentReceivesDataTable({
[actionMenuList, formatMessage],
);
+ const showEmptyStatus = [
+ paymentReceivesCurrentViewId === -1,
+ PaymentReceivesCurrentPage.length === 0,
+ ].every(condition => condition === true);
+
return (
-
+
+
+
+
+
+
+
+
+
);
}
@@ -216,12 +230,14 @@ export default compose(
PaymentReceivesCurrentPage,
paymentReceivesLoading,
paymentReceivesPageination,
- paymentReceivesTableQuery
+ paymentReceivesTableQuery,
+ paymentReceivesCurrentViewId,
}) => ({
PaymentReceivesCurrentPage,
paymentReceivesLoading,
paymentReceivesPageination,
- paymentReceivesTableQuery
+ paymentReceivesTableQuery,
+ paymentReceivesCurrentViewId,
}),
),
withViewDetails(),
diff --git a/client/src/containers/Sales/PaymentReceive/PaymentReceivesEmptyStatus.js b/client/src/containers/Sales/PaymentReceive/PaymentReceivesEmptyStatus.js
new file mode 100644
index 000000000..1a6f0caaf
--- /dev/null
+++ b/client/src/containers/Sales/PaymentReceive/PaymentReceivesEmptyStatus.js
@@ -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 (
+
+ It is a long established fact that a reader will be distracted by the
+ readable content of a page when looking at its layout.
+
+ }
+ action={
+ <>
+ {
+ history.push('/payment-receive/new');
+ }}
+ >
+ New payment receive
+
+
+
+ Learn more
+
+ >
+ }
+ />
+ );
+}
diff --git a/client/src/containers/Sales/PaymentReceive/withPaymentReceives.js b/client/src/containers/Sales/PaymentReceive/withPaymentReceives.js
index 97c13e74f..8069f3a9b 100644
--- a/client/src/containers/Sales/PaymentReceive/withPaymentReceives.js
+++ b/client/src/containers/Sales/PaymentReceive/withPaymentReceives.js
@@ -4,11 +4,14 @@ import {
getPaymentReceiveCurrentPageFactory,
getPaymentReceivePaginationMetaFactory,
getPaymentReceiveTableQuery,
+ getPaymentReceivesCurrentViewIdFactory,
} from 'store/PaymentReceive/paymentReceive.selector';
export default (mapState) => {
const getPyamentReceivesItems = getPaymentReceiveCurrentPageFactory();
const getPyamentReceivesPaginationMeta = getPaymentReceivePaginationMetaFactory();
+ const getPaymentReceivesCurrentViewId = getPaymentReceivesCurrentViewIdFactory();
+
const mapStateToProps = (state, props) => {
const query = getPaymentReceiveTableQuery(state, props);
const mapped = {
@@ -23,6 +26,7 @@ export default (mapState) => {
),
paymentReceivesLoading: state.paymentReceives.loading,
paymentReceiveNumberChanged: state.paymentReceives.journalNumberChanged,
+ paymentReceivesCurrentViewId: getPaymentReceivesCurrentViewId(state, props),
};
return mapState ? mapState(mapped, state, props) : mapped;
};
diff --git a/client/src/containers/Sales/Receipt/ReceiptsDataTable.js b/client/src/containers/Sales/Receipt/ReceiptsDataTable.js
index cf1526d7c..f38e1a104 100644
--- a/client/src/containers/Sales/Receipt/ReceiptsDataTable.js
+++ b/client/src/containers/Sales/Receipt/ReceiptsDataTable.js
@@ -15,7 +15,9 @@ import moment from 'moment';
import { compose, saveInvoke } from 'utils';
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 withDashboardActions from 'containers/Dashboard/withDashboardActions';
@@ -24,16 +26,17 @@ import withReceipts from './withReceipts';
import withReceiptActions from './withReceiptActions';
function ReceiptsDataTable({
- //#withReceipts
+ // #withReceipts
receiptsCurrentPage,
receiptsLoading,
receiptsPagination,
receiptTableQuery,
+ receiptsCurrentViewId,
// #withReceiptsActions
addReceiptsTableQueries,
- // #Own Props
+ // #ownProps
loading,
onEditReceipt,
onDeleteReceipt,
@@ -186,28 +189,38 @@ function ReceiptsDataTable({
[onSelectedRowsChange],
);
+ const showEmptyStatus = [
+ receiptsCurrentViewId === -1,
+ receiptsCurrentPage.length === 0,
+ ].every(condition => condition === true);
+
return (
-
-
+
+
+
+
+
+
+
+
+
+
);
}
@@ -223,11 +236,13 @@ export default compose(
receiptsLoading,
receiptsPagination,
receiptTableQuery,
+ receiptsCurrentViewId
}) => ({
receiptsCurrentPage,
receiptsLoading,
receiptsPagination,
receiptTableQuery,
+ receiptsCurrentViewId
}),
),
)(ReceiptsDataTable);
diff --git a/client/src/containers/Sales/Receipt/ReceiptsEmptyStatus.js b/client/src/containers/Sales/Receipt/ReceiptsEmptyStatus.js
new file mode 100644
index 000000000..2878dff45
--- /dev/null
+++ b/client/src/containers/Sales/Receipt/ReceiptsEmptyStatus.js
@@ -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 (
+
+ Here a list of your organization products and services, to be used when you create invoices or bills to your customers or vendors.
+
+ }
+ action={
+ <>
+ {
+ history.push('/receipts/new');
+ }}
+ >
+ New receipt
+
+
+
+ Learn more
+
+ >
+ }
+ />
+ );
+}
diff --git a/client/src/containers/Sales/Receipt/withReceipts.js b/client/src/containers/Sales/Receipt/withReceipts.js
index 73f5a0711..e96128ddd 100644
--- a/client/src/containers/Sales/Receipt/withReceipts.js
+++ b/client/src/containers/Sales/Receipt/withReceipts.js
@@ -4,12 +4,14 @@ import {
getReceiptCurrentPageFactory,
getReceiptsTableQueryFactory,
getReceiptsPaginationMetaFactory,
+ getReceiptsCurrentViewIdFactory
} from 'store/receipt/receipt.selector';
export default (mapState) => {
const getReceiptsItems = getReceiptCurrentPageFactory();
const getReceiptPaginationMeta = getReceiptsPaginationMetaFactory();
const getReceiptsTableQuery = getReceiptsTableQueryFactory();
+ const getReceiptsCurrentViewId = getReceiptsCurrentViewIdFactory();
const mapStateToProps = (state, props) => {
const tableQuery = getReceiptsTableQuery(state, props);
@@ -23,6 +25,8 @@ export default (mapState) => {
receiptsLoading: state.salesReceipts.loading,
receiptNumberChanged: state.salesReceipts.journalNumberChanged,
+
+ receiptsCurrentViewId: getReceiptsCurrentViewId(state, props),
};
return mapState ? mapState(mapped, state, props) : mapped;
diff --git a/client/src/store/Bills/bills.selectors.js b/client/src/store/Bills/bills.selectors.js
index 91f2302b9..5d7a25c49 100644
--- a/client/src/store/Bills/bills.selectors.js
+++ b/client/src/store/Bills/bills.selectors.js
@@ -31,6 +31,8 @@ const billPaginationSelector = (state, props) => {
return state.bills.views?.[viewId];
};
+const getBillsCurrentViewIdSelector = (state) => state.bills.currentViewId;
+
export const getBillTableQueryFactory = () =>
createSelector(
paginationLocationQuery,
@@ -108,3 +110,12 @@ export const getVendorPayableBillsEntriesFactory = () =>
}));
},
);
+
+// Retreive the current bills view id.
+export const getBillsCurrentViewIdFactory = () =>
+ createSelector(
+ getBillsCurrentViewIdSelector,
+ (currentViewId) => {
+ return currentViewId;
+ }
+ );
\ No newline at end of file
diff --git a/client/src/store/Estimate/estimates.selectors.js b/client/src/store/Estimate/estimates.selectors.js
index 9cc8b6f36..107f60628 100644
--- a/client/src/store/Estimate/estimates.selectors.js
+++ b/client/src/store/Estimate/estimates.selectors.js
@@ -19,6 +19,10 @@ const estimatesPageSelector = (state, props, query) => {
return state.salesEstimates.views?.[viewId]?.pages?.[currentPageId];
};
+const getEstimatesCurrentViewIdSelector = (state, props) => {
+ return state.salesEstimates.currentViewId;
+};
+
// Retrieve estimates table query.
export const getEstimatesTableQueryFactory = () =>
createSelector(
@@ -58,3 +62,12 @@ export const getEstimatesPaginationMetaFactory = () =>
...(estimateView?.paginationMeta || {}),
};
});
+
+
+// Retrieve estimates current view id.
+export const getEstimatesCurrentViewIdFactory = () =>
+ createSelector(
+ getEstimatesCurrentViewIdSelector,
+ (currentViewId) => {
+ return currentViewId;
+ });
\ No newline at end of file
diff --git a/client/src/store/Invoice/invoices.selector.js b/client/src/store/Invoice/invoices.selector.js
index 5688e2911..277b6f831 100644
--- a/client/src/store/Invoice/invoices.selector.js
+++ b/client/src/store/Invoice/invoices.selector.js
@@ -27,6 +27,8 @@ const invoicesItemsSelector = (state) => state.salesInvoices.items;
const invoicesReceiableCustomerSelector = (state, props) =>
state.salesInvoices.receivable.byCustomerId[props.customerId];
+const getInvoicesCurrentViewIdSelector = (state) => state.salesInvoices.currentViewId;
+
export const getInvoiceTableQueryFactory = () =>
createSelector(
paginationLocationQuery,
@@ -51,6 +53,8 @@ export const getInvoiceCurrentPageFactory = () =>
},
);
+
+
// Retrieve specific invoice by the passed invoice id.
export const getInvoiecsByIdFactory = () =>
createSelector(invoicesByIdSelector, (invoice) => {
@@ -83,3 +87,12 @@ export const getCustomerReceivableInvoicesEntriesFactory = () =>
}));
},
);
+
+// Retrieve sale invoices current view id.
+export const getInvoicesCurrentViewIdFactory = () =>
+ createSelector(
+ getInvoicesCurrentViewIdSelector,
+ (currentViewId) => {
+ return currentViewId;
+ }
+ );
\ No newline at end of file
diff --git a/client/src/store/PaymentMades/paymentMade.selector.js b/client/src/store/PaymentMades/paymentMade.selector.js
index f058d72ec..57e38f70d 100644
--- a/client/src/store/PaymentMades/paymentMade.selector.js
+++ b/client/src/store/PaymentMades/paymentMade.selector.js
@@ -27,12 +27,17 @@ const paymentMadeById = (state, props) =>
state.paymentMades.items[props.paymentMadeId];
const paymentMadeEntries = (state, props) => props.paymentMadeEntries;
+
const billsItemsSelector = (state, props) => state.bills.items;
+
const billsPayableByPaymentMadeSelector = (state, props) =>
state.bills.payable.byBillPayamentId[props.paymentMadeId];
+
const paymentMadeBillsSelector = (state, props) =>
state.bills.byBillPayamentId[props.paymentMadeId];
+const paymentMadesCurrentViewIdSelector = (state) => state.paymentMades.currentViewId;
+
export const getPaymentMadeCurrentPageFactory = () =>
createSelector(
paymentMadesPageSelector,
@@ -113,3 +118,12 @@ export const getPaymentMadeEntriesFactory = () =>
});
},
);
+
+// Retrieve payment mades current view id.
+export const getPaymentMadesCurrentViewIdFactory = () =>
+ createSelector(
+ paymentMadesCurrentViewIdSelector,
+ (currentViewId) => {
+ return currentViewId;
+ }
+ );
\ No newline at end of file
diff --git a/client/src/store/PaymentReceive/paymentReceive.selector.js b/client/src/store/PaymentReceive/paymentReceive.selector.js
index ef25af5fa..0764377b1 100644
--- a/client/src/store/PaymentReceive/paymentReceive.selector.js
+++ b/client/src/store/PaymentReceive/paymentReceive.selector.js
@@ -35,6 +35,9 @@ const paymentReceiveInvoicesSelector = (state, props) =>
const paymentReceiveByIdSelector = (state, props) =>
state.paymentReceives.items[props.paymentReceiveId];
+const paymentReceivesCurrentViewIdSelector = (state) =>
+ state.paymentReceives.currentViewId;
+
// Retrieve payment receive current page results.
export const getPaymentReceiveCurrentPageFactory = () =>
createSelector(
@@ -124,3 +127,10 @@ export const getPaymentReceiveEntriesFactory = () =>
});
},
);
+
+// Retrieve payment receives current view id.
+export const getPaymentReceivesCurrentViewIdFactory = () =>
+ createSelector(
+ paymentReceivesCurrentViewIdSelector,
+ (currentViewId) => currentViewId,
+ );
diff --git a/client/src/store/customers/customers.selectors.js b/client/src/store/customers/customers.selectors.js
index 9c4ffb1bf..10c4d98f3 100644
--- a/client/src/store/customers/customers.selectors.js
+++ b/client/src/store/customers/customers.selectors.js
@@ -26,6 +26,8 @@ const customerPageSelector = (state, props) => {
const customersItemsSelector = (state) => state.customers.items;
+const customersCurrentViewIdSelector = (state) => state.customers.currentViewId;
+
export const getCustomerTableQueryFactory = () =>
createSelector(
paginationLocationQuery,
@@ -61,3 +63,8 @@ export const getCustomerPaginationMetaFactory = () =>
...(customerPage?.paginationMeta || {}),
};
});
+
+export const getCustomersCurrentViewIdFactory = () =>
+ createSelector(customersCurrentViewIdSelector, (currentViewId) => {
+ return currentViewId;
+ });
diff --git a/client/src/store/expenses/expenses.selectors.js b/client/src/store/expenses/expenses.selectors.js
index f5cf9eea0..200e273f8 100644
--- a/client/src/store/expenses/expenses.selectors.js
+++ b/client/src/store/expenses/expenses.selectors.js
@@ -8,6 +8,8 @@ const getPageExpensesQuery = (state, props) => {
return currentPageId || 0;
};
+const getExpensesCurrentViewIdSelector = (state) => state.expenses.currentViewId;
+
const expensesPageSelector = (state, props, query) => {
const viewId = state.expenses.currentViewId;
const currentPageId = getPageExpensesQuery(state, { viewId });
@@ -60,4 +62,12 @@ export const getExpensesPaginationMetaFactory = () => createSelector(
(expensesPage) => {
return expensesPage?.paginationMeta || {};
},
+);
+
+// Retrieve expenses current view id.
+export const getExpensesCurrentViewIdFactory = () => createSelector(
+ getExpensesCurrentViewIdSelector,
+ (currentViewId) => {
+ return currentViewId;
+ },
);
\ No newline at end of file
diff --git a/client/src/store/manualJournals/manualJournals.selectors.js b/client/src/store/manualJournals/manualJournals.selectors.js
index 5931ce6fd..30eb44a7c 100644
--- a/client/src/store/manualJournals/manualJournals.selectors.js
+++ b/client/src/store/manualJournals/manualJournals.selectors.js
@@ -1,6 +1,8 @@
import { createSelector } from 'reselect';
import { pickItemsFromIds, paginationLocationQuery, defaultPaginationMeta } from 'store/selectors';
+const manualJournalsCurrentViewIdSelector = (state) => state.manualJournals.currentViewId;
+
const manualJournalsPageSelector = (state) => {
const viewId = state.manualJournals.currentViewId;
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;
+ },
+ );
\ No newline at end of file
diff --git a/client/src/store/receipt/receipt.selector.js b/client/src/store/receipt/receipt.selector.js
index 05ee4066c..f39d4c9da 100644
--- a/client/src/store/receipt/receipt.selector.js
+++ b/client/src/store/receipt/receipt.selector.js
@@ -20,6 +20,8 @@ const receiptTableQuery = (state) => state.salesReceipts.tableQuery;
const receiptByIdSelector = (state, props) => state.salesReceipts.items[props.receiptId];
+const receiptsCurrentViewIdSelector = (state) => state.salesReceipts.currentViewId;
+
// Retrieve current page sale receipts results.
export const getReceiptCurrentPageFactory = () =>
createSelector(
@@ -56,3 +58,9 @@ export const getReceiptsPaginationMetaFactory = () =>
createSelector(receiptsPaginationSelector, (receiptPage) => {
return receiptPage?.paginationMeta || {};
});
+
+// Retrieve receipts current view id.
+export const getReceiptsCurrentViewIdFactory = () =>
+ createSelector(
+ receiptsCurrentViewIdSelector,
+ (currentViewId) => currentViewId);
\ No newline at end of file
diff --git a/client/src/style/App.scss b/client/src/style/App.scss
index 0cf0b6322..4394f01d3 100644
--- a/client/src/style/App.scss
+++ b/client/src/style/App.scss
@@ -462,4 +462,41 @@ body.authentication {
min-width: 70px;
}
}
+}
+
+
+.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;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/client/src/style/objects/buttons.scss b/client/src/style/objects/buttons.scss
index 296a758f1..9447ff1f8 100644
--- a/client/src/style/objects/buttons.scss
+++ b/client/src/style/objects/buttons.scss
@@ -23,9 +23,14 @@
}
}
-.bp3-button:not([class*="bp3-intent-"]):not(.bp3-minimal){
+.bp3-button{
min-width: 32px;
min-height: 32px;
+ padding-left: 12px;
+ padding-right: 12px;
+}
+
+.bp3-button:not([class*="bp3-intent-"]):not(.bp3-minimal){
background-color: #E6EFFB;
color: #555555;
box-shadow: 0 0 0 transparent;
diff --git a/client/src/style/pages/dashboard.scss b/client/src/style/pages/dashboard.scss
index 4967ccaf1..c91891d47 100644
--- a/client/src/style/pages/dashboard.scss
+++ b/client/src/style/pages/dashboard.scss
@@ -239,6 +239,7 @@
}
&__insider{
margin-bottom: 40px;
+ flex: 1 0 0;
}
&__offline-badge{
@@ -276,16 +277,19 @@
}
&__insider{
+ display: flex;
+ flex-direction: column;
- &--loading{
- display: flex;
- align-items: center;
- justify-content: center;
- height: 100%;
+ > .dashboard__loading-indicator{
+ margin-top: auto;
+ margin-bottom: auto;
}
}
&__page-content{
+ display: flex;
+ flex-direction: column;
+ flex: 1 0 0;
.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{
border-bottom: 1px solid #E5E5E5;
// height: 70px;