fix: dashboard sidebar expanding.

This commit is contained in:
a.bouhuolia
2021-04-19 18:34:02 +02:00
parent c6aca4ecfa
commit f29c1b6cec
27 changed files with 178 additions and 230 deletions

View File

@@ -22,7 +22,8 @@ export default function DashboardContentRoute() {
pageTitle={route.pageTitle} pageTitle={route.pageTitle}
backLink={route.backLink} backLink={route.backLink}
hint={route.hint} hint={route.hint}
sidebarShrink={route.sidebarShrink} sidebarExpand={route.sidebarExpand}
pageType={route.pageType}
/> />
</Route> </Route>
))} ))}

View File

@@ -1,7 +1,10 @@
import React, { useEffect, Suspense } from 'react'; import React, { useEffect, Suspense } from 'react';
import { isUndefined } from 'lodash';
import { CLASSES } from 'common/classes'; import { CLASSES } from 'common/classes';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import { compose } from 'utils'; import { compose } from 'utils';
import { Spinner } from '@blueprintjs/core';
/** /**
* Dashboard pages wrapper. * Dashboard pages wrapper.
*/ */
@@ -9,7 +12,7 @@ function DashboardPage({
// #ownProps // #ownProps
pageTitle, pageTitle,
backLink, backLink,
sidebarShrink, sidebarExpand = true,
Component, Component,
name, name,
hint, hint,
@@ -17,10 +20,10 @@ function DashboardPage({
// #withDashboardActions // #withDashboardActions
changePageTitle, changePageTitle,
setDashboardBackLink, setDashboardBackLink,
setSidebarShrink,
resetSidebarPreviousExpand,
changePageHint, changePageHint,
toggleSidebarExpand
}) { }) {
// Hydrate the given page title.
useEffect(() => { useEffect(() => {
pageTitle && changePageTitle(pageTitle); pageTitle && changePageTitle(pageTitle);
@@ -29,6 +32,7 @@ function DashboardPage({
}; };
}); });
// Hydrate the given page hint.
useEffect(() => { useEffect(() => {
hint && changePageHint(hint); hint && changePageHint(hint);
@@ -37,6 +41,7 @@ function DashboardPage({
} }
}, [hint, changePageHint]); }, [hint, changePageHint]);
// Hydrate the dashboard back link status.
useEffect(() => { useEffect(() => {
backLink && setDashboardBackLink(backLink); backLink && setDashboardBackLink(backLink);
@@ -45,16 +50,6 @@ function DashboardPage({
}; };
}, [backLink, setDashboardBackLink]); }, [backLink, setDashboardBackLink]);
// Handle sidebar shrink in mount and reset to the pervious state
// once the page unmount.
useEffect(() => {
sidebarShrink && setSidebarShrink();
return () => {
sidebarShrink && resetSidebarPreviousExpand();
};
}, [resetSidebarPreviousExpand, sidebarShrink, setSidebarShrink]);
useEffect(() => { useEffect(() => {
const className = `page-${name}`; const className = `page-${name}`;
name && document.body.classList.add(className); name && document.body.classList.add(className);
@@ -64,13 +59,23 @@ function DashboardPage({
}; };
}, [name]); }, [name]);
useEffect(() => {
toggleSidebarExpand(sidebarExpand);
}, [toggleSidebarExpand, sidebarExpand])
return ( return (
<div className={CLASSES.DASHBOARD_PAGE}> <div className={CLASSES.DASHBOARD_PAGE}>
<Suspense fallback={''}> <Suspense fallback={
<div class="dashboard__fallback-loading">
<Spinner size={40} value={null} />
</div>
}>
<Component /> <Component />
</Suspense> </Suspense>
</div> </div>
); );
} }
export default compose(withDashboardActions)(DashboardPage); export default compose(
withDashboardActions,
)(DashboardPage);

View File

@@ -34,8 +34,7 @@ function DashboardTopbar({
pageHint, pageHint,
// #withDashboardActions // #withDashboardActions
toggleSidebarExpend, toggleSidebarExpand,
recordSidebarPreviousExpand,
// #withDashboard // #withDashboard
sidebarExpended, sidebarExpended,
@@ -53,8 +52,7 @@ function DashboardTopbar({
}; };
const handleSidebarToggleBtn = () => { const handleSidebarToggleBtn = () => {
toggleSidebarExpend(); toggleSidebarExpand();
recordSidebarPreviousExpand();
}; };
return ( return (

View File

@@ -1,4 +1,5 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import classNames from 'classnames';
import TableContext from './TableContext'; import TableContext from './TableContext';
/** /**
@@ -20,10 +21,12 @@ export default function TableFooter() {
{group.headers.map((column) => ( {group.headers.map((column) => (
<div <div
{...column.getFooterProps({ {...column.getFooterProps({
className: 'td', className: classNames(column.className || '', 'td'),
})} })}
> >
{column.render('Footer')} <div className={'cell-inner'}>
{column.render('Footer')}
</div>
</div> </div>
))} ))}
</div> </div>

View File

@@ -72,20 +72,6 @@ export function ActionsMenu({
); );
} }
/**
* Actions cell.
*/
export function ActionsCell(props) {
return (
<Popover
position={Position.RIGHT_BOTTOM}
content={<ActionsMenu {...props} />}
>
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
</Popover>
);
}
/** /**
* Normal cell. * Normal cell.
*/ */

View File

@@ -1,8 +1,8 @@
import React from 'react'; import React from 'react';
import { Intent } from '@blueprintjs/core'; import { Intent, Tag } from '@blueprintjs/core';
import { If, AppToaster } from 'components'; import { If, AppToaster } from 'components';
import { formatMessage } from 'services/intl'; import { formatMessage } from 'services/intl';
import { NormalCell, BalanceCell, ActionsCell } from './components'; import { NormalCell, BalanceCell } from './components';
/** /**
* Account name accessor. * Account name accessor.
@@ -40,6 +40,13 @@ export const handleDeleteErrors = (errors) => {
} }
}; };
export const AccountCodeAccessor = (row) => (
<Tag minimal={true} round={true} intent={Intent.NONE}>
{ row.code }
</Tag>
);
/** /**
* Accounts table columns. * Accounts table columns.
*/ */
@@ -56,7 +63,7 @@ export const useAccountsTableColumns = () => {
{ {
id: 'code', id: 'code',
Header: formatMessage({ id: 'code' }), Header: formatMessage({ id: 'code' }),
accessor: 'code', accessor: AccountCodeAccessor,
className: 'code', className: 'code',
width: 80, width: 80,
}, },
@@ -88,14 +95,6 @@ export const useAccountsTableColumns = () => {
Cell: BalanceCell, Cell: BalanceCell,
width: 150, width: 150,
}, },
{
id: 'actions',
Header: '',
Cell: ActionsCell,
className: 'actions',
width: 50,
skeletonWidthMin: 100,
},
], ],
[], [],
) )

View File

@@ -49,20 +49,6 @@ export function ActionsMenu({
); );
} }
/**
* Actions cell.
*/
export function ActionsCell(props) {
return (
<Popover
content={<ActionsMenu {...props} />}
position={Position.RIGHT_BOTTOM}
>
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
</Popover>
);
}
/** /**
* Avatar cell. * Avatar cell.
*/ */
@@ -129,14 +115,6 @@ export function useCustomersTableColumns() {
className: 'receivable_balance', className: 'receivable_balance',
width: 100, width: 100,
}, },
{
id: 'actions',
Cell: ActionsCell,
className: 'actions',
width: 70,
disableResizing: true,
disableSortBy: true,
},
], ],
[formatMessage], [formatMessage],
); );

View File

@@ -1,5 +1,8 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import t from 'store/types'; import t from 'store/types';
import {
toggleExpendSidebar,
} from 'store/dashboard/dashboard.actions';
const mapActionsToProps = (dispatch) => ({ const mapActionsToProps = (dispatch) => ({
changePageTitle: (pageTitle) => changePageTitle: (pageTitle) =>
@@ -17,7 +20,7 @@ const mapActionsToProps = (dispatch) => ({
changePageHint: (pageHint) => changePageHint: (pageHint) =>
dispatch({ dispatch({
type: t.CHANGE_DASHBOARD_PAGE_HINT, type: t.CHANGE_DASHBOARD_PAGE_HINT,
payload: { pageHint } payload: { pageHint },
}), }),
setTopbarEditView: (id) => setTopbarEditView: (id) =>
@@ -36,32 +39,22 @@ const mapActionsToProps = (dispatch) => ({
type: t.SET_DASHBOARD_REQUEST_COMPLETED, type: t.SET_DASHBOARD_REQUEST_COMPLETED,
}), }),
toggleSidebarExpend: () => /**
* Toggles the sidebar expend.
*/
toggleSidebarExpand: (toggle) => dispatch(toggleExpendSidebar(toggle)),
changePreferencesPageTitle: (pageTitle) =>
dispatch({ dispatch({
type: t.SIDEBAR_EXPEND_TOGGLE, type: 'CHANGE_PREFERENCES_PAGE_TITLE',
pageTitle,
}), }),
changePreferencesPageTitle: (pageTitle) => dispatch({ setDashboardBackLink: (backLink) =>
type: 'CHANGE_PREFERENCES_PAGE_TITLE', dispatch({
pageTitle, type: t.SET_DASHBOARD_BACK_LINK,
}), payload: { backLink },
setSidebarShrink: () => dispatch({ }),
type: t.SIDEBAR_SHRINK,
}),
setSidebarExpand: () => dispatch({
type: t.SIDEBAR_SHRINK,
}),
resetSidebarPreviousExpand: () => dispatch({
type: t.RESET_SIDEBAR_PREVIOUS_EXPAND,
}),
recordSidebarPreviousExpand: () => dispatch({
type: t.RECORD_SIDEBAR_PREVIOUS_EXPAND,
}),
setDashboardBackLink: (backLink) => dispatch({
type: t.SET_DASHBOARD_BACK_LINK,
payload: { backLink }
})
}); });
export default connect(null, mapActionsToProps); export default connect(null, mapActionsToProps);

View File

@@ -1,13 +1,9 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import classNames from 'classnames';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { compose } from 'utils'; import { compose } from 'utils';
import { useExpensesListContext } from './ExpensesListProvider'; import { useExpensesListContext } from './ExpensesListProvider';
import { Choose } from 'components';
import { CLASSES } from 'common/classes';
import DataTable from 'components/DataTable'; import DataTable from 'components/DataTable';
import ExpensesEmptyStatus from './ExpensesEmptyStatus'; import ExpensesEmptyStatus from './ExpensesEmptyStatus';
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows'; import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';

View File

@@ -175,14 +175,6 @@ export function useExpensesTableColumns() {
className: 'description', className: 'description',
disableSortBy: true, disableSortBy: true,
}, },
{
id: 'actions',
Header: '',
Cell: ActionsCell,
className: 'actions',
width: 50,
disableResizing: true,
},
], ],
[], [],
); );

View File

@@ -1,5 +1,7 @@
import React from 'react'; import React from 'react';
import 'style/pages/InventoryAdjustments/List.scss';
import { DashboardContentTable, DashboardPageContent } from 'components'; import { DashboardContentTable, DashboardPageContent } from 'components';
import InventoryAdjustmentsAlerts from './InventoryAdjustmentsAlerts'; import InventoryAdjustmentsAlerts from './InventoryAdjustmentsAlerts';

View File

@@ -179,14 +179,6 @@ export const useInventoryAdjustmentsColumns = () => {
width: 125, width: 125,
className: 'created_at', className: 'created_at',
}, },
{
id: 'actions',
Header: '',
Cell: ActionsCell,
className: 'actions',
width: 50,
disableResizing: true,
},
], ],
[formatMessage], [formatMessage],
); );

View File

@@ -1,11 +1,9 @@
import React, { useEffect, createContext } from 'react'; import React, { createContext } from 'react';
import { useIntl } from 'react-intl';
import { transformTableQueryToParams, isTableEmptyStatus } from 'utils'; import { transformTableQueryToParams, isTableEmptyStatus } from 'utils';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { useResourceViews, useResourceFields, useItems } from 'hooks/query'; import { useResourceViews, useResourceFields, useItems } from 'hooks/query';
import { useDashboardPageTitle } from 'hooks/state';
const ItemsContext = createContext(); const ItemsContext = createContext();
@@ -40,17 +38,6 @@ function ItemsListProvider({
data: items, pagination, filterMeta, data: items, pagination, filterMeta,
}) && !isItemsFetching; }) && !isItemsFetching;
// Format message intl.
const { formatMessage } = useIntl();
// Change page title dispatcher.
const changePageTitle = useDashboardPageTitle();
// Changeas the page title once the page mount.
useEffect(() => {
changePageTitle(formatMessage({ id: 'items_list' }));
}, [changePageTitle, formatMessage]);
const state = { const state = {
itemsViews, itemsViews,
itemsFields, itemsFields,

View File

@@ -181,7 +181,6 @@ export const useItemsTableColumns = () => {
{ {
id: 'sell_price', id: 'sell_price',
Header: formatMessage({ id: 'sell_price' }), Header: formatMessage({ id: 'sell_price' }),
// Cell: SellPriceCell,
accessor: 'sell_price_formatted', accessor: 'sell_price_formatted',
className: 'sell-price', className: 'sell-price',
width: 150, width: 150,
@@ -189,7 +188,6 @@ export const useItemsTableColumns = () => {
{ {
id: 'cost_price', id: 'cost_price',
Header: formatMessage({ id: 'cost_price' }), Header: formatMessage({ id: 'cost_price' }),
// Cell: CostPriceCell,
accessor: 'cost_price_formatted', accessor: 'cost_price_formatted',
className: 'cost-price', className: 'cost-price',
width: 150, width: 150,
@@ -201,12 +199,6 @@ export const useItemsTableColumns = () => {
Cell: QuantityOnHandCell, Cell: QuantityOnHandCell,
width: 140, width: 140,
}, },
{
id: 'actions',
Cell: ItemsActionsTableCell,
width: 60,
skeletonWidthMin: 100,
},
], ],
[formatMessage], [formatMessage],
); );

View File

@@ -1,4 +1,6 @@
import React from 'react'; import React from 'react';
import 'style/pages/ItemsCategories/List.scss';
import { DashboardContentTable, DashboardPageContent } from 'components'; import { DashboardContentTable, DashboardPageContent } from 'components';
import ItemsCategoriesAlerts from './ItemsCategoriesAlerts'; import ItemsCategoriesAlerts from './ItemsCategoriesAlerts';
@@ -11,7 +13,7 @@ import ItemCategoriesTable from './ItemCategoriesTable';
*/ */
export default function ItemCategoryList() { export default function ItemCategoryList() {
return ( return (
<ItemsCategoriesProvider query={{}}> <ItemsCategoriesProvider>
<ItemsCategoryActionsBar /> <ItemsCategoryActionsBar />
<DashboardPageContent> <DashboardPageContent>

View File

@@ -25,7 +25,7 @@ function ItemsCategoriesProvider({ query, ...props }) {
}; };
return ( return (
<DashboardInsider name={'item-category-list'}> <DashboardInsider name={'items-categories-list'}>
<ItemsCategoriesContext.Provider value={state} {...props} /> <ItemsCategoriesContext.Provider value={state} {...props} />
</DashboardInsider> </DashboardInsider>
); );

View File

@@ -81,14 +81,7 @@ export function useItemsCategoriesTableColumns() {
accessor: 'description', accessor: 'description',
className: 'description', className: 'description',
width: 220, width: 220,
}, }
{
id: 'actions',
Header: '',
Cell: TableActionsCell,
className: 'actions',
width: 50,
},
], ],
[formatMessage], [formatMessage],
); );

View File

@@ -7,8 +7,29 @@ import { useQueryTenant } from '../useQueryRequest';
export function useContact(id, props) { export function useContact(id, props) {
const apiRequest = useApiRequest(); const apiRequest = useApiRequest();
return useQueryTenant(['CONTACT', id], () => apiRequest.get(`contacts/${id}`), { return useQueryTenant(
select: (res) => res.data.customer, ['CONTACT', id],
...props, () => apiRequest.get(`contacts/${id}`),
}); {
select: (res) => res.data.customer,
...props,
},
);
}
/**
* Retrieve the auto-complete contacts.
*/
export function useAutoCompleteContacts(props) {
const apiRequest = useApiRequest();
return useQueryTenant(
['CONTACTS', 'AUTO-COMPLETE'],
() => apiRequest.get('contacts/auto-complete'),
{
select: (res) => res.data.contacts,
defaultData: [],
...props,
},
);
} }

View File

@@ -96,8 +96,17 @@ const ORGANIZATIONS = {
const SUBSCRIPTIONS = { const SUBSCRIPTIONS = {
SUBSCRIPTIONS: 'SUBSCRIPTIONS', SUBSCRIPTIONS: 'SUBSCRIPTIONS',
} };
const EXPENSES = {
EXPENSES: 'EXPENSES',
EXPENSE: 'EXPENSE',
};
const MANUAL_JOURNALS = {
MANUAL_JOURNALS: 'MANUAL_JOURNALS',
MANUAL_JOURNAL: 'MANUAL_JOURNAL',
};
export default { export default {
...ACCOUNTS, ...ACCOUNTS,
...BILLS, ...BILLS,
@@ -115,5 +124,7 @@ export default {
...USERS, ...USERS,
...SETTING, ...SETTING,
...ORGANIZATIONS, ...ORGANIZATIONS,
...SUBSCRIPTIONS ...SUBSCRIPTIONS,
...EXPENSES,
...MANUAL_JOURNALS
}; };

View File

@@ -858,7 +858,7 @@ export default {
the_item_categories_has_been_deleted_successfully: the_item_categories_has_been_deleted_successfully:
'The item categories has been deleted successfully .', 'The item categories has been deleted successfully .',
receivable_accounts_should_assign_with_customers: receivable_accounts_should_assign_with_customers:
'receivable accounts should assign with customers', 'Receivable accounts should assign with customers.',
delivered: 'Delivered', delivered: 'Delivered',
save_and_deliver: 'Save & Deliver', save_and_deliver: 'Save & Deliver',
deliver_and_new: 'Deliver and new', deliver_and_new: 'Deliver and new',
@@ -1049,4 +1049,5 @@ export default {
asset_value: 'Asset value', asset_value: 'Asset value',
average: 'Average', average: 'Average',
inventory_valuation: 'Inventory valuation', inventory_valuation: 'Inventory valuation',
payable_accounts_should_assign_with_vendors: 'Payable accounts should assign with vendors.'
}; };

View File

@@ -32,7 +32,7 @@ export default [
breadcrumb: 'Make Journal Entry', breadcrumb: 'Make Journal Entry',
hotkey: 'ctrl+shift+m', hotkey: 'ctrl+shift+m',
pageTitle: formatMessage({ id: 'new_journal' }), pageTitle: formatMessage({ id: 'new_journal' }),
sidebarShrink: true, sidebarExpand: false,
backLink: true, backLink: true,
}, },
{ {
@@ -42,7 +42,7 @@ export default [
), ),
breadcrumb: 'Edit', breadcrumb: 'Edit',
pageTitle: formatMessage({ id: 'edit_journal' }), pageTitle: formatMessage({ id: 'edit_journal' }),
sidebarShrink: true, sidebarExpand: false,
backLink: true, backLink: true,
}, },
{ {
@@ -92,6 +92,7 @@ export default [
component: lazy(() => import('containers/Items/ItemsList')), component: lazy(() => import('containers/Items/ItemsList')),
breadcrumb: 'Items', breadcrumb: 'Items',
hotkey: 'shift+w', hotkey: 'shift+w',
pageTitle: formatMessage({ id: 'items_list' }),
}, },
// Inventory adjustments. // Inventory adjustments.
@@ -115,7 +116,7 @@ export default [
hotkey: 'shift+4', hotkey: 'shift+4',
pageTitle: formatMessage({ id: 'general_ledger' }), pageTitle: formatMessage({ id: 'general_ledger' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/financial-reports/balance-sheet`, path: `/financial-reports/balance-sheet`,
@@ -127,7 +128,7 @@ export default [
hotkey: 'shift+1', hotkey: 'shift+1',
pageTitle: formatMessage({ id: 'balance_sheet' }), pageTitle: formatMessage({ id: 'balance_sheet' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/financial-reports/trial-balance-sheet`, path: `/financial-reports/trial-balance-sheet`,
@@ -141,7 +142,7 @@ export default [
hotkey: 'shift+5', hotkey: 'shift+5',
pageTitle: formatMessage({ id: 'trial_balance_sheet' }), pageTitle: formatMessage({ id: 'trial_balance_sheet' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/financial-reports/profit-loss-sheet`, path: `/financial-reports/profit-loss-sheet`,
@@ -153,7 +154,7 @@ export default [
hotkey: 'shift+2', hotkey: 'shift+2',
pageTitle: formatMessage({ id: 'profit_loss_sheet' }), pageTitle: formatMessage({ id: 'profit_loss_sheet' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: '/financial-reports/receivable-aging-summary', path: '/financial-reports/receivable-aging-summary',
@@ -164,7 +165,7 @@ export default [
hint: "Summarize total unpaid balances of customers invoices with number of days the unpaid invoice is overdue.", hint: "Summarize total unpaid balances of customers invoices with number of days the unpaid invoice is overdue.",
pageTitle: formatMessage({ id: 'receivable_aging_summary' }), pageTitle: formatMessage({ id: 'receivable_aging_summary' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: '/financial-reports/payable-aging-summary', path: '/financial-reports/payable-aging-summary',
@@ -175,7 +176,7 @@ export default [
hint: "Summarize total unpaid balances of vendors purchase invoices with the number of days the unpaid invoice is overdue.", hint: "Summarize total unpaid balances of vendors purchase invoices with the number of days the unpaid invoice is overdue.",
pageTitle: formatMessage({ id: 'payable_aging_summary' }), pageTitle: formatMessage({ id: 'payable_aging_summary' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/financial-reports/journal-sheet`, path: `/financial-reports/journal-sheet`,
@@ -186,7 +187,7 @@ export default [
hint: "The debit and credit entries of system transactions, sorted by date.", hint: "The debit and credit entries of system transactions, sorted by date.",
hotkey: 'shift+3', hotkey: 'shift+3',
pageTitle: formatMessage({ id: 'journal_sheet' }), pageTitle: formatMessage({ id: 'journal_sheet' }),
sidebarShrink: true, sidebarExpand: false,
backLink: true, backLink: true,
}, },
{ {
@@ -200,7 +201,7 @@ export default [
// hotkey: '', // hotkey: '',
pageTitle: formatMessage({ id: 'purchases_by_items' }), pageTitle: formatMessage({ id: 'purchases_by_items' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/financial-reports/sales-by-items`, path: `/financial-reports/sales-by-items`,
@@ -211,7 +212,7 @@ export default [
pageTitle: formatMessage({ id: 'sales_by_items' }), pageTitle: formatMessage({ id: 'sales_by_items' }),
hint: 'Summarize the businesss sold items quantity, income and average income rate of each item during a specific point in time.', hint: 'Summarize the businesss sold items quantity, income and average income rate of each item during a specific point in time.',
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/financial-reports/inventory-valuation`, path: `/financial-reports/inventory-valuation`,
@@ -224,7 +225,7 @@ export default [
hint: 'Summerize your transactions for each inventory item and how they affect quantity, valuation and weighted average.', hint: 'Summerize your transactions for each inventory item and how they affect quantity, valuation and weighted average.',
pageTitle: formatMessage({ id: 'inventory_valuation' }), pageTitle: formatMessage({ id: 'inventory_valuation' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: '/financial-reports', path: '/financial-reports',
@@ -250,7 +251,7 @@ export default [
breadcrumb: 'Expenses', breadcrumb: 'Expenses',
hotkey: 'ctrl+shift+x', hotkey: 'ctrl+shift+x',
pageTitle: formatMessage({ id: 'new_expense' }), pageTitle: formatMessage({ id: 'new_expense' }),
sidebarShrink: true, sidebarExpand: false,
backLink: true, backLink: true,
}, },
{ {
@@ -260,7 +261,7 @@ export default [
), ),
breadcrumb: 'Edit', breadcrumb: 'Edit',
pageTitle: formatMessage({ id: 'edit_expense' }), pageTitle: formatMessage({ id: 'edit_expense' }),
sidebarShrink: true, sidebarExpand: false,
backLink: true, backLink: true,
}, },
{ {
@@ -367,7 +368,7 @@ export default [
breadcrumb: 'Edit', breadcrumb: 'Edit',
pageTitle: formatMessage({ id: 'edit_estimate' }), pageTitle: formatMessage({ id: 'edit_estimate' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/invoices/new?from_estimate_id=/:id`, path: `/invoices/new?from_estimate_id=/:id`,
@@ -378,7 +379,7 @@ export default [
breadcrumb: 'New Estimate', breadcrumb: 'New Estimate',
pageTitle: formatMessage({ id: 'new_estimate' }), pageTitle: formatMessage({ id: 'new_estimate' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/estimates/new`, path: `/estimates/new`,
@@ -390,7 +391,7 @@ export default [
hotkey: 'ctrl+shift+e', hotkey: 'ctrl+shift+e',
pageTitle: formatMessage({ id: 'new_estimate' }), pageTitle: formatMessage({ id: 'new_estimate' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/estimates`, path: `/estimates`,
@@ -412,7 +413,7 @@ export default [
name: 'invoice-edit', name: 'invoice-edit',
breadcrumb: 'Edit', breadcrumb: 'Edit',
pageTitle: formatMessage({ id: 'edit_invoice' }), pageTitle: formatMessage({ id: 'edit_invoice' }),
sidebarShrink: true, sidebarExpand: false,
backLink: true, backLink: true,
}, },
{ {
@@ -424,7 +425,7 @@ export default [
breadcrumb: 'New Invoice', breadcrumb: 'New Invoice',
hotkey: 'ctrl+shift+i', hotkey: 'ctrl+shift+i',
pageTitle: formatMessage({ id: 'new_invoice' }), pageTitle: formatMessage({ id: 'new_invoice' }),
sidebarShrink: true, sidebarExpand: false,
backLink: true, backLink: true,
}, },
{ {
@@ -447,7 +448,7 @@ export default [
breadcrumb: 'Edit', breadcrumb: 'Edit',
pageTitle: formatMessage({ id: 'edit_receipt' }), pageTitle: formatMessage({ id: 'edit_receipt' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/receipts/new`, path: `/receipts/new`,
@@ -459,7 +460,7 @@ export default [
hotkey: 'ctrl+shift+r', hotkey: 'ctrl+shift+r',
pageTitle: formatMessage({ id: 'new_receipt' }), pageTitle: formatMessage({ id: 'new_receipt' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/receipts`, path: `/receipts`,
@@ -483,7 +484,7 @@ export default [
breadcrumb: 'Edit', breadcrumb: 'Edit',
pageTitle: formatMessage({ id: 'edit_payment_receive' }), pageTitle: formatMessage({ id: 'edit_payment_receive' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/payment-receives/new`, path: `/payment-receives/new`,
@@ -496,7 +497,7 @@ export default [
breadcrumb: 'New Payment Receive', breadcrumb: 'New Payment Receive',
pageTitle: formatMessage({ id: 'new_payment_receive' }), pageTitle: formatMessage({ id: 'new_payment_receive' }),
backLink: true, backLink: true,
sidebarShrink: true, sidebarExpand: false,
}, },
{ {
path: `/payment-receives`, path: `/payment-receives`,
@@ -518,7 +519,7 @@ export default [
name: 'bill-edit', name: 'bill-edit',
breadcrumb: 'Edit', breadcrumb: 'Edit',
pageTitle: formatMessage({ id: 'edit_bill' }), pageTitle: formatMessage({ id: 'edit_bill' }),
sidebarShrink: true, sidebarExpand: false,
backLink: true, backLink: true,
}, },
{ {
@@ -530,7 +531,7 @@ export default [
breadcrumb: 'New Bill', breadcrumb: 'New Bill',
hotkey: 'ctrl+shift+b', hotkey: 'ctrl+shift+b',
pageTitle: formatMessage({ id: 'new_bill' }), pageTitle: formatMessage({ id: 'new_bill' }),
sidebarShrink: true, sidebarExpand: false,
backLink: true, backLink: true,
}, },
{ {
@@ -560,7 +561,7 @@ export default [
name: 'payment-made-edit', name: 'payment-made-edit',
breadcrumb: 'Edit', breadcrumb: 'Edit',
pageTitle: formatMessage({ id: 'edit_payment_made' }), pageTitle: formatMessage({ id: 'edit_payment_made' }),
sidebarShrink: true, sidebarExpand: false,
backLink: true, backLink: true,
}, },
{ {
@@ -573,7 +574,7 @@ export default [
name: 'payment-made-new', name: 'payment-made-new',
breadcrumb: 'New Payment Made', breadcrumb: 'New Payment Made',
pageTitle: formatMessage({ id: 'new_payment_made' }), pageTitle: formatMessage({ id: 'new_payment_made' }),
sidebarShrink: true, sidebarExpand: false,
backLink: true, backLink: true,
}, },
{ {

View File

@@ -60,3 +60,13 @@ export function closeDrawer(name, payload) {
payload, payload,
}; };
} }
/**
* Toggles the sidebar expend.
*/
export function toggleExpendSidebar(toggle) {
return {
type: t.SIDEBAR_EXPEND_TOGGLE,
payload: { toggle }
};
}

View File

@@ -1,5 +1,6 @@
import t from 'store/types';
import { createReducer } from '@reduxjs/toolkit'; import { createReducer } from '@reduxjs/toolkit';
import { isUndefined } from 'lodash';
import t from 'store/types';
import { persistReducer, purgeStoredState } from 'redux-persist'; import { persistReducer, purgeStoredState } from 'redux-persist';
import storage from 'redux-persist/lib/storage'; import storage from 'redux-persist/lib/storage';
@@ -9,7 +10,6 @@ const initialState = {
pageHint: '', pageHint: '',
preferencesPageTitle: '', preferencesPageTitle: '',
sidebarExpended: true, sidebarExpended: true,
previousSidebarExpended: null,
dialogs: {}, dialogs: {},
alerts: {}, alerts: {},
drawers: {}, drawers: {},
@@ -22,7 +22,7 @@ const STORAGE_KEY = 'bigcapital:dashboard';
const CONFIG = { const CONFIG = {
key: STORAGE_KEY, key: STORAGE_KEY,
whitelist: ['sidebarExpended', 'previousSidebarExpended'], whitelist: [],
storage, storage,
}; };
@@ -88,33 +88,11 @@ const reducerInstance = createReducer(initialState, {
state.topbarEditViewId = action.id; state.topbarEditViewId = action.id;
}, },
[t.SET_DASHBOARD_REQUEST_LOADING]: (state, action) => { [t.SIDEBAR_EXPEND_TOGGLE]: (state, action) => {
state.requestsLoading = state.requestsLoading + 1; const { toggle } = action.payload;
}, state.sidebarExpended = isUndefined(toggle)
? !state.sidebarExpended
[t.SET_DASHBOARD_REQUEST_COMPLETED]: (state, action) => { : !!toggle;
const requestsLoading = state.requestsLoading - 1;
state.requestsLoading = Math.max(requestsLoading, 0);
},
[t.RECORD_SIDEBAR_PREVIOUS_EXPAND]: (state) => {
state.previousSidebarExpended = state.sidebarExpended;
},
[t.SIDEBAR_EXPEND_TOGGLE]: (state) => {
state.sidebarExpended = !state.sidebarExpended;
},
[t.SIDEBAR_EXPAND]: (state) => {
state.sidebarExpended = true;
},
[t.SIDEBAR_SHRINK]: (state) => {
state.sidebarExpended = false;
},
[t.RESET_SIDEBAR_PREVIOUS_EXPAND]: (state) => {
state.sidebarExpended = state.previousSidebarExpended;
}, },
[t.SET_DASHBOARD_BACK_LINK]: (state, action) => { [t.SET_DASHBOARD_BACK_LINK]: (state, action) => {

View File

@@ -12,12 +12,6 @@ export default {
CHANGE_PREFERENCES_PAGE_TITLE: 'CHANGE_PREFERENCES_PAGE_TITLE', CHANGE_PREFERENCES_PAGE_TITLE: 'CHANGE_PREFERENCES_PAGE_TITLE',
ALTER_DASHBOARD_PAGE_SUBTITLE: 'ALTER_DASHBOARD_PAGE_SUBTITLE', ALTER_DASHBOARD_PAGE_SUBTITLE: 'ALTER_DASHBOARD_PAGE_SUBTITLE',
SET_TOPBAR_EDIT_VIEW: 'SET_TOPBAR_EDIT_VIEW', SET_TOPBAR_EDIT_VIEW: 'SET_TOPBAR_EDIT_VIEW',
SET_DASHBOARD_REQUEST_LOADING: 'SET_DASHBOARD_REQUEST_LOADING',
SET_DASHBOARD_REQUEST_COMPLETED: 'SET_DASHBOARD_REQUEST_COMPLETED',
SIDEBAR_EXPEND_TOGGLE: 'SIDEBAR_EXPEND_TOGGLE', SIDEBAR_EXPEND_TOGGLE: 'SIDEBAR_EXPEND_TOGGLE',
SIDEBAR_EXPAND: 'SIDEBAR_EXPAND',
SIDEBAR_SHRINK: 'SIDEBAR_SHRINK',
RESET_SIDEBAR_PREVIOUS_EXPAND: 'RESET_SIDEBAR_PREVIOUS_EXPAND',
RECORD_SIDEBAR_PREVIOUS_EXPAND: 'RECORD_SIDEBAR_PREVIOUS_EXPAND',
SET_DASHBOARD_BACK_LINK: 'SET_DASHBOARD_BACK_LINK', SET_DASHBOARD_BACK_LINK: 'SET_DASHBOARD_BACK_LINK',
}; };

View File

@@ -307,6 +307,17 @@ $dashboard-views-bar-height: 45px;
flex: 1 0 0; flex: 1 0 0;
} }
&__fallback-loading{
display: flex;
flex-direction: column;
height: 100%;
background-color: #fbfbfb;
.bp3-spinner{
margin: auto;
}
}
&__page-content { &__page-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@@ -223,13 +223,14 @@ export default class UsersController extends BaseController{
* @param {NextFunction} next * @param {NextFunction} next
*/ */
catchServiceErrors(error: Error, req: Request, res: Response, next: NextFunction) { catchServiceErrors(error: Error, req: Request, res: Response, next: NextFunction) {
if (error instanceof ServiceErrors) { if (error instanceof ServiceErrors) {
const errorReasons = []; const errorReasons = [];
if (error.errorType === 'EMAIL_ALREADY_EXISTS') { if (error.hasType('EMAIL_ALREADY_EXISTS')) {
errorReasons.push({ type: 'EMAIL_ALREADY_EXIST', code: 100 }); errorReasons.push({ type: 'EMAIL_ALREADY_EXIST', code: 100 });
} }
if (error.errorType === 'PHONE_NUMBER_ALREADY_EXIST') { if (error.hasType('PHONE_NUMBER_ALREADY_EXIST')) {
errorReasons.push({ type: 'PHONE_NUMBER_ALREADY_EXIST', code: 200 }); errorReasons.push({ type: 'PHONE_NUMBER_ALREADY_EXIST', code: 200 });
} }
if (errorReasons.length > 0) { if (errorReasons.length > 0) {

View File

@@ -2,6 +2,7 @@ import TenancyService from 'services/Tenancy/TenancyService';
import { Inject, Service } from 'typedi'; import { Inject, Service } from 'typedi';
import { ServiceError, ServiceErrors } from 'exceptions'; import { ServiceError, ServiceErrors } from 'exceptions';
import { ISystemUser, ISystemUserDTO } from 'interfaces'; import { ISystemUser, ISystemUserDTO } from 'interfaces';
import { SystemUser } from 'system/models';
const ERRORS = { const ERRORS = {
CANNOT_DELETE_LAST_USER: 'CANNOT_DELETE_LAST_USER', CANNOT_DELETE_LAST_USER: 'CANNOT_DELETE_LAST_USER',
@@ -38,20 +39,20 @@ export default class UsersService {
): Promise<ISystemUser> { ): Promise<ISystemUser> {
const { systemUserRepository } = this.repositories; const { systemUserRepository } = this.repositories;
const userByEmail = await systemUserRepository.findOne({ const userByEmail = await SystemUser.query()
email: userDTO.email, .where('email', userDTO.email)
id: userId, .whereNot('id', userId);
});
const userByPhoneNumber = await systemUserRepository.findOne({ const userByPhoneNumber = await SystemUser.query()
phoneNumber: userDTO.phoneNumber, .where('phone_number', userDTO.phoneNumber)
id: userId, .whereNot('id', userId);
});
const serviceErrors: ServiceError[] = []; const serviceErrors: ServiceError[] = [];
if (userByEmail) { if (userByEmail.length > 0) {
serviceErrors.push(new ServiceError(ERRORS.EMAIL_ALREADY_EXISTS)); serviceErrors.push(new ServiceError(ERRORS.EMAIL_ALREADY_EXISTS));
} }
if (userByPhoneNumber) { if (userByPhoneNumber.length > 0) {
serviceErrors.push(new ServiceError(ERRORS.PHONE_NUMBER_ALREADY_EXIST)); serviceErrors.push(new ServiceError(ERRORS.PHONE_NUMBER_ALREADY_EXIST));
} }
if (serviceErrors.length > 0) { if (serviceErrors.length > 0) {