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={ + <> + + + + + } + /> + ); +} 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={ + <> + + + + + } + /> + ); +} 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={ + <> + + + + + } + /> + ); +} 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={ + <> + + + + + } + /> + ); +} 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={ + <> + + + + + } + /> + ); +} 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={ + <> + + + + + } + /> + ); +} 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={ + <> + + + + } + /> + ); +} 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={ + <> + + + + + } + /> + ); + } 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={ + <> + + + + + } + /> + ); +} 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={ + <> + + + + + } + /> + ); +} 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;