feat: style read-only drawers.

fix: empty state in resources tables.
This commit is contained in:
a.bouhuolia
2021-08-24 14:57:19 +02:00
parent f5fd2aa324
commit af34986aac
143 changed files with 1530 additions and 915 deletions

View File

@@ -0,0 +1,12 @@
export const DRAWERS = {
ESTIMATE_DRAWER: 'estimate-drawer',
MANUAL_JOURNAL_DRAWER: 'journal-drawer',
INVOICE_DRAWER: 'invoice-drawer',
RECEIPT_DRAWER: 'receipt-drawer',
PAYMENT_RECEIVE_DRAWER: 'payment-receive-drawer',
ACCOUNT_DRAWER: 'account-drawer',
JOURNAL_DRAWER: 'journal-drawer',
EXPENSE_DRAWER: 'expense-drawer'
};

View File

@@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames';
export default function Card({ children }) { export default function Card({ className, children }) {
return <div class="card">{children}</div>; return <div className={classNames('card', className)}>{children}</div>;
} }

View File

@@ -9,7 +9,7 @@ function DashboardSplitPane({
sidebarExpended, sidebarExpended,
children children
}) { }) {
const initialSize = 190; const initialSize = 180;
const [defaultSize, setDefaultSize] = useState( const [defaultSize, setDefaultSize] = useState(
parseInt(localStorage.getItem('dashboard-size'), 10) || initialSize, parseInt(localStorage.getItem('dashboard-size'), 10) || initialSize,
@@ -27,7 +27,7 @@ function DashboardSplitPane({
<SplitPane <SplitPane
allowResize={sidebarExpended} allowResize={sidebarExpended}
split="vertical" split="vertical"
minSize={190} minSize={180}
maxSize={300} maxSize={300}
defaultSize={sidebarExpended ? defaultSize : 50} defaultSize={sidebarExpended ? defaultSize : 50}
size={sidebarExpended ? defaultSize : 50} size={sidebarExpended ? defaultSize : 50}

View File

@@ -9,7 +9,6 @@ import { saveInvoke } from 'utils';
/** /**
* Dashboard views tabs. * Dashboard views tabs.
*
*/ */
export default function DashboardViewsTabs({ export default function DashboardViewsTabs({
initialViewSlug = 0, initialViewSlug = 0,
@@ -42,8 +41,9 @@ export default function DashboardViewsTabs({
// Trigger `onChange` and `onThrottledChange` events. // Trigger `onChange` and `onThrottledChange` events.
const triggerOnChange = (viewSlug) => { const triggerOnChange = (viewSlug) => {
saveInvoke(onChange, viewSlug); const value = viewSlug === 0 ? null : viewSlug;
throttledOnChange.current(viewSlug); saveInvoke(onChange, value);
throttledOnChange.current(value);
}; };
// Handles click a new view. // Handles click a new view.

View File

@@ -1,17 +1,22 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Col, Row } from 'components';
import 'style/components/Details.scss'; import 'style/components/Details.scss';
const DIRECTION = {
VERTICAL: 'vertical',
HORIZANTAL: 'horizantal',
};
/** /**
* Details menu. * Details menu.
*/ */
export function DetailsMenu({ children, vertical = false }) { export function DetailsMenu({ children, direction = DIRECTION.VERTICAL }) {
return ( return (
<div <div
className={classNames('details-menu', { className={classNames('details-menu', {
'is-vertical': vertical, 'details-menu--vertical': direction === DIRECTION.VERTICAL,
'details-menu--horizantal': direction === DIRECTION.HORIZANTAL,
})} })}
> >
{children} {children}
@@ -20,27 +25,15 @@ export function DetailsMenu({ children, vertical = false }) {
} }
/** /**
* Detail item vertical . * Detail item.
*/ */
export function DetailItemVER({ label, children }) { export function DetailItem({ label, children, name }) {
return ( return (
<div class="detail-item"> <div className={classNames('detail-item', {
[`detail-item--${name}`]: name,
})}>
<div class="detail-item__label">{label}</div> <div class="detail-item__label">{label}</div>
<div class="detail-item__content">{children}</div> <div class="detail-item__content">{children}</div>
</div> </div>
); );
} }
/**
* Detail item horizontal .
*/
export function DetailItemHOR({ label, children }) {
return (
<Row>
<Col className="label" xs={3}>
{label}
</Col>
<Col xs={3}>{children}</Col>
</Row>
);
}

View File

@@ -5,15 +5,10 @@ import classNames from 'classnames';
export default function DialogContent(props) { export default function DialogContent(props) {
const { isLoading, children } = props; const { isLoading, children } = props;
const loadingContent = <Spinner size={30} />; const loadingContent = (
<div className={classNames(Classes.DIALOG_BODY, 'is-loading')}>
return ( <Spinner size={30} />
<div
className={classNames(Classes.DIALOG_BODY, {
'is-loading': isLoading,
})}
>
{isLoading ? loadingContent : children}
</div> </div>
); );
return isLoading ? loadingContent : children;
} }

View File

@@ -24,6 +24,7 @@ function DrawerComponent(props) {
canEscapeKeyClose={true} canEscapeKeyClose={true}
position={Position.RIGHT} position={Position.RIGHT}
onClose={handleClose} onClose={handleClose}
portalClassName={'drawer-portal'}
{...props} {...props}
> >
{children} {children}

View File

@@ -13,16 +13,21 @@ import PaymentReceiveDetailDrawer from 'containers/Drawers/PaymentReceiveDetailD
import PaymentMadeDetailDrawer from 'containers/Drawers/PaymentMadeDetailDrawer'; import PaymentMadeDetailDrawer from 'containers/Drawers/PaymentMadeDetailDrawer';
import EstimateDetailDrawer from '../containers/Drawers/EstimateDetailDrawer'; import EstimateDetailDrawer from '../containers/Drawers/EstimateDetailDrawer';
import { DRAWERS } from 'common/drawers';
/**
* Drawers container of the dashboard.
*/
export default function DrawersContainer() { export default function DrawersContainer() {
return ( return (
<div> <div>
<EstimateDrawer name={'estimate-drawer'} /> <EstimateDrawer name={DRAWERS.EstimateDrawer} />
<InvoiceDrawer name={'invoice-drawer'} /> <InvoiceDrawer name={'invoice-drawer'} />
<ReceiptDrawer name={'receipt-drawer'} /> <ReceiptDrawer name={'receipt-drawer'} />
<PaymentReceiveDrawer name={'payment-receive-drawer'} /> <PaymentReceiveDrawer name={'payment-receive-drawer'} />
<AccountDrawer name={'account-drawer'} /> <AccountDrawer name={DRAWERS.ACCOUNT_DRAWER} />
<ManualJournalDrawer name={'journal-drawer'} /> <ManualJournalDrawer name={DRAWERS.JOURNAL_DRAWER} />
<ExpenseDrawer name={'expense-drawer'} /> <ExpenseDrawer name={DRAWERS.EXPENSE_DRAWER} />
<BillDrawer name={'bill-drawer'} /> <BillDrawer name={'bill-drawer'} />
<InvoiceDetailDrawer name={'invoice-detail-drawer'} /> <InvoiceDetailDrawer name={'invoice-detail-drawer'} />
<EstimateDetailDrawer name={'estimate-detail-drawer'} /> <EstimateDetailDrawer name={'estimate-detail-drawer'} />

View File

@@ -1,13 +1,24 @@
import React from 'react'; import React from 'react';
import { Spinner } from '@blueprintjs/core'; import { Spinner, Classes } from '@blueprintjs/core';
import classNames from 'classnames';
/** /**
* Previews the pdf document of the given object url. * Previews the pdf document of the given object url.
*/ */
export function PdfDocumentPreview({ url, height, width, isLoading }) { export function PdfDocumentPreview({ url, height, width, isLoading }) {
return isLoading ? ( const content = isLoading ? (
<Spinner size={30} /> <Spinner size={30} />
) : ( ) : (
<embed src={url} height={height} width={width} /> <embed src={url} height={height} width={width} />
); );
return (
<div
className={classNames(Classes.DIALOG_BODY, {
loading: isLoading,
})}
>
{content}
</div>
);
} }

View File

@@ -68,6 +68,7 @@ export * from './Dashboard/DashboardFilterButton';
export * from './Dashboard/DashboardRowsHeightButton'; export * from './Dashboard/DashboardRowsHeightButton';
export * from './UniversalSearch/UniversalSearch'; export * from './UniversalSearch/UniversalSearch';
export * from './PdfPreview'; export * from './PdfPreview';
export * from './Details';
const Hint = FieldHint; const Hint = FieldHint;

View File

@@ -19,10 +19,12 @@ import { transformTableStateToQuery, compose } from 'utils';
function ManualJournalsTable({ function ManualJournalsTable({
// #withManualJournals // #withManualJournals
journalsTableState, journalsTableState,
journalsTableStateChanged,
}) { }) {
return ( return (
<ManualJournalsListProvider <ManualJournalsListProvider
query={transformTableStateToQuery(journalsTableState)} query={transformTableStateToQuery(journalsTableState)}
tableStateChanged={journalsTableStateChanged}
> >
<ManualJournalsActionsBar /> <ManualJournalsActionsBar />
@@ -40,7 +42,8 @@ function ManualJournalsTable({
} }
export default compose( export default compose(
withManualJournals(({ manualJournalsTableState }) => ({ withManualJournals(({ manualJournalsTableState, manualJournalTableStateChanged }) => ({
journalsTableState: manualJournalsTableState, journalsTableState: manualJournalsTableState,
journalsTableStateChanged: manualJournalTableStateChanged,
})), })),
)(ManualJournalsTable); )(ManualJournalsTable);

View File

@@ -1,11 +1,13 @@
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { isEmpty } from 'lodash';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { useResourceViews, useResourceMeta, useJournals } from 'hooks/query'; import { useResourceViews, useResourceMeta, useJournals } from 'hooks/query';
import { isTableEmptyStatus, getFieldsFromResourceMeta } from 'utils'; import { getFieldsFromResourceMeta } from 'utils';
const ManualJournalsContext = createContext(); const ManualJournalsContext = createContext();
function ManualJournalsListProvider({ query, ...props }) { function ManualJournalsListProvider({ query, tableStateChanged, ...props }) {
// Fetches accounts resource views and fields. // Fetches accounts resource views and fields.
const { data: journalsViews, isLoading: isViewsLoading } = const { data: journalsViews, isLoading: isViewsLoading } =
useResourceViews('manual_journals'); useResourceViews('manual_journals');
@@ -26,11 +28,7 @@ function ManualJournalsListProvider({ query, ...props }) {
// Detarmines the datatable empty status. // Detarmines the datatable empty status.
const isEmptyStatus = const isEmptyStatus =
isTableEmptyStatus({ isEmpty(manualJournals) && !tableStateChanged && !isManualJournalsLoading;
data: manualJournals,
pagination,
filterMeta,
}) && !isManualJournalsFetching;
// Global state. // Global state.
const state = { const state = {

View File

@@ -24,7 +24,7 @@ export const useManualJournalsColumns = () => {
{ {
id: 'amount', id: 'amount',
Header: intl.get('amount'), Header: intl.get('amount'),
accessor: AmountAccessor, accessor: 'formatted_amount',
className: 'amount', className: 'amount',
width: 115, width: 115,
}, },

View File

@@ -1,14 +1,21 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
getManualJournalsTableStateFactory getManualJournalsTableStateFactory,
manualJournalTableStateChangedFactory,
} from 'store/manualJournals/manualJournals.selectors'; } from 'store/manualJournals/manualJournals.selectors';
export default (mapState) => { export default (mapState) => {
const getJournalsTableQuery = getManualJournalsTableStateFactory(); const getJournalsTableQuery = getManualJournalsTableStateFactory();
const manualJournalTableStateChanged =
manualJournalTableStateChangedFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const mapped = { const mapped = {
manualJournalsTableState: getJournalsTableQuery(state, props), manualJournalsTableState: getJournalsTableQuery(state, props),
manualJournalTableStateChanged: manualJournalTableStateChanged(
state,
props,
),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -9,12 +9,14 @@ function JournalUniversalSearchSelectComponent({
// #ownProps // #ownProps
resourceType, resourceType,
resourceId, resourceId,
onAction,
// #withDrawerActions // #withDrawerActions
openDrawer, openDrawer,
}) { }) {
if (resourceType === RESOURCES_TYPES.MANUAL_JOURNAL) { if (resourceType === RESOURCES_TYPES.MANUAL_JOURNAL) {
openDrawer('journal-drawer', { manualJournalId: resourceId }); openDrawer('journal-drawer', { manualJournalId: resourceId });
onAction && onAction();
} }
return null; return null;
} }
@@ -27,6 +29,7 @@ export const JournalUniversalSearchSelectAction = withDrawerActions(
* Mappes the manual journal item to search item. * Mappes the manual journal item to search item.
*/ */
const manualJournalsToSearch = (manualJournal) => ({ const manualJournalsToSearch = (manualJournal) => ({
id: manualJournal.id,
text: manualJournal.journal_number, text: manualJournal.journal_number,
subText: manualJournal.formatted_date, subText: manualJournal.formatted_date,
label: manualJournal.formatted_amount, label: manualJournal.formatted_amount,

View File

@@ -6,12 +6,14 @@ function AccountUniversalSearchItemSelectComponent({
// #ownProps // #ownProps
resourceType, resourceType,
resourceId, resourceId,
onAction,
// #withDrawerActions // #withDrawerActions
openDrawer, openDrawer,
}) { }) {
if (resourceType === RESOURCES_TYPES.ACCOUNT) { if (resourceType === RESOURCES_TYPES.ACCOUNT) {
openDrawer('account-drawer', { accountId: resourceId }); openDrawer('account-drawer', { accountId: resourceId });
onAction && onAction();
} }
return null; return null;
} }
@@ -26,6 +28,7 @@ export const AccountUniversalSearchItemSelect = withDrawerActions(
* @returns * @returns
*/ */
const accountToSearch = (account) => ({ const accountToSearch = (account) => ({
id: account.id,
text: `${account.name} - ${account.code}`, text: `${account.name} - ${account.code}`,
label: account.formatted_amount, label: account.formatted_amount,
reference: account, reference: account,

View File

@@ -22,6 +22,7 @@ import withAccountsTableActions from './withAccountsTableActions';
function AccountsChart({ function AccountsChart({
// #withAccounts // #withAccounts
accountsTableState, accountsTableState,
accountsTableStateChanged,
// #withAccountsActions // #withAccountsActions
setAccountsTableState, setAccountsTableState,
@@ -41,6 +42,7 @@ function AccountsChart({
return ( return (
<AccountsChartProvider <AccountsChartProvider
query={transformAccountsStateToQuery(accountsTableState)} query={transformAccountsStateToQuery(accountsTableState)}
tableStateChanged={accountsTableStateChanged}
> >
<AccountsActionsBar /> <AccountsActionsBar />
@@ -58,6 +60,9 @@ function AccountsChart({
} }
export default compose( export default compose(
withAccounts(({ accountsTableState }) => ({ accountsTableState })), withAccounts(({ accountsTableState, accountsTableStateChanged }) => ({
accountsTableState,
accountsTableStateChanged,
})),
withAccountsTableActions, withAccountsTableActions,
)(AccountsChart); )(AccountsChart);

View File

@@ -8,7 +8,7 @@ const AccountsChartContext = createContext();
/** /**
* Accounts chart data provider. * Accounts chart data provider.
*/ */
function AccountsChartProvider({ query, ...props }) { function AccountsChartProvider({ query, tableStateChanged,...props }) {
// Fetch accounts resource views and fields. // Fetch accounts resource views and fields.
const { data: resourceViews, isLoading: isViewsLoading } = const { data: resourceViews, isLoading: isViewsLoading } =
useResourceViews('accounts'); useResourceViews('accounts');

View File

@@ -1,15 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
getAccountsTableStateFactory, getAccountsTableStateFactory,
accountsTableStateChangedFactory,
} from 'store/accounts/accounts.selectors'; } from 'store/accounts/accounts.selectors';
export default (mapState) => { export default (mapState) => {
const getAccountsTableState = getAccountsTableStateFactory(); const getAccountsTableState = getAccountsTableStateFactory();
const accountsTableStateChanged = accountsTableStateChangedFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const mapped = { const mapped = {
accountsTableState: getAccountsTableState(state, props), accountsTableState: getAccountsTableState(state, props),
accountsSelectedRows: null, accountsTableStateChanged: accountsTableStateChanged(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -21,9 +21,10 @@ import { compose } from 'utils';
function CustomersList({ function CustomersList({
// #withCustomers // #withCustomers
customersTableState, customersTableState,
customersTableStateChanged,
// #withCustomersActions // #withCustomersActions
setCustomersTableState setCustomersTableState,
}) { }) {
// Resets the accounts table state once the page unmount. // Resets the accounts table state once the page unmount.
useEffect( useEffect(
@@ -38,7 +39,10 @@ function CustomersList({
); );
return ( return (
<CustomersListProvider tableState={customersTableState}> <CustomersListProvider
tableState={customersTableState}
tableStateChanged={customersTableStateChanged}
>
<CustomersActionsBar /> <CustomersActionsBar />
<DashboardPageContent> <DashboardPageContent>
@@ -54,6 +58,9 @@ function CustomersList({
} }
export default compose( export default compose(
withCustomers(({ customersTableState }) => ({ customersTableState })), withCustomers(({ customersTableState, customersTableStateChanged }) => ({
withCustomersActions customersTableState,
customersTableStateChanged,
})),
withCustomersActions,
)(CustomersList); )(CustomersList);

View File

@@ -1,13 +1,14 @@
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { isEmpty } from 'lodash';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { useResourceMeta, useResourceViews, useCustomers } from 'hooks/query'; import { useResourceMeta, useResourceViews, useCustomers } from 'hooks/query';
import { isTableEmptyStatus, getFieldsFromResourceMeta } from 'utils'; import { getFieldsFromResourceMeta } from 'utils';
import { transformCustomersStateToQuery } from './utils'; import { transformCustomersStateToQuery } from './utils';
const CustomersListContext = createContext(); const CustomersListContext = createContext();
function CustomersListProvider({ tableState, ...props }) { function CustomersListProvider({ tableState, tableStateChanged, ...props }) {
// Transformes the table state to fetch query. // Transformes the table state to fetch query.
const tableQuery = transformCustomersStateToQuery(tableState); const tableQuery = transformCustomersStateToQuery(tableState);
@@ -31,13 +32,7 @@ function CustomersListProvider({ tableState, ...props }) {
// Detarmines the datatable empty status. // Detarmines the datatable empty status.
const isEmptyStatus = const isEmptyStatus =
isTableEmptyStatus({ isEmpty(customers) && !isCustomersLoading && !tableStateChanged;
data: customers,
pagination,
filterMeta,
}) &&
!isCustomersFetching &&
!tableState.inactiveMode;
const state = { const state = {
customersViews, customersViews,

View File

@@ -1,12 +1,18 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { getCustomersTableStateFactory } from 'store/customers/customers.selectors'; import {
getCustomersTableStateFactory,
customersTableStateChangedFactory,
} from 'store/customers/customers.selectors';
export default (mapState) => { export default (mapState) => {
const getCustomersTableState = getCustomersTableStateFactory(); const getCustomersTableState = getCustomersTableStateFactory();
const customersTableStateChanged = customersTableStateChangedFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const mapped = { const mapped = {
customersTableState: getCustomersTableState(state, props), customersTableState: getCustomersTableState(state, props),
customersTableStateChanged: customersTableStateChanged(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -1,6 +1,12 @@
import React from 'react'; import React from 'react';
import Icon from 'components/Icon'; import Icon from 'components/Icon';
import { Button, Classes, NavbarGroup, Intent } from '@blueprintjs/core'; import {
Button,
Classes,
NavbarGroup,
Intent,
NavbarDivider,
} from '@blueprintjs/core';
import { FormattedMessage as T } from 'components'; import { FormattedMessage as T } from 'components';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar'; import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
@@ -11,6 +17,7 @@ import withDrawerActions from 'containers/Drawer/withDrawerActions';
import { safeCallback } from 'utils'; import { safeCallback } from 'utils';
import { compose } from 'utils'; import { compose } from 'utils';
import { useAccountDrawerContext } from './AccountDrawerProvider';
/** /**
* Account drawer action bar. * Account drawer action bar.
@@ -24,10 +31,10 @@ function AccountDrawerActionBar({
// #withDrawerActions // #withDrawerActions
closeDrawer, closeDrawer,
// #ownProps
account,
}) { }) {
// Account drawer context.
const { account } = useAccountDrawerContext();
// Handle new child button click. // Handle new child button click.
const onNewChildAccount = () => { const onNewChildAccount = () => {
openDialog('account-form', { openDialog('account-form', {
@@ -44,10 +51,8 @@ function AccountDrawerActionBar({
// Handle delete action account. // Handle delete action account.
const onDeleteAccount = () => { const onDeleteAccount = () => {
if (account) {
openAlert('account-delete', { accountId: account.id }); openAlert('account-delete', { accountId: account.id });
closeDrawer('account-drawer'); closeDrawer('account-drawer');
}
}; };
return ( return (
@@ -65,9 +70,10 @@ function AccountDrawerActionBar({
text={<T id={'new_child_account'} />} text={<T id={'new_child_account'} />}
onClick={safeCallback(onNewChildAccount)} onClick={safeCallback(onNewChildAccount)}
/> />
<NavbarDivider />
<Button <Button
className={Classes.MINIMAL} className={Classes.MINIMAL}
icon={<Icon icon="trash-18" iconSize={18} />} icon={<Icon icon={'trash-16'} iconSize={16} />}
text={<T id={'delete'} />} text={<T id={'delete'} />}
intent={Intent.DANGER} intent={Intent.DANGER}
onClick={safeCallback(onDeleteAccount)} onClick={safeCallback(onDeleteAccount)}

View File

@@ -1,20 +1,21 @@
import React from 'react'; import React from 'react';
import { Card } from 'components';
import AccountDrawerActionBar from './AccountDrawerActionBar'; import AccountDrawerActionBar from './AccountDrawerActionBar';
import AccountDrawerHeader from './AccountDrawerHeader'; import AccountDrawerHeader from './AccountDrawerHeader';
import AccountDrawerTable from './AccountDrawerTable'; import AccountDrawerTable from './AccountDrawerTable';
import { useAccountDrawerContext } from './AccountDrawerProvider';
/** /**
* Account view details. * Account view details.
*/ */
export default function AccountDrawerDetails() { export default function AccountDrawerDetails() {
const { account, accounts } = useAccountDrawerContext();
return ( return (
<div className={'account-drawer'}> <div className={'account-drawer'}>
<AccountDrawerActionBar account={account} /> <AccountDrawerActionBar />
<AccountDrawerHeader account={account} /> <Card className={'card-header'}>
<AccountDrawerHeader />
</Card>
<AccountDrawerTable /> <AccountDrawerTable />
</div> </div>
); );

View File

@@ -1,68 +1,56 @@
import React from 'react'; import React from 'react';
import { defaultTo } from 'lodash';
import { FormattedMessage as T } from 'components'; import { FormattedMessage as T } from 'components';
import { Icon, Money } from 'components'; import { Icon, Money, DetailsMenu, DetailItem } from 'components';
import { useAccountDrawerContext } from './AccountDrawerProvider';
/** /**
* Account drawer header. * Account drawer header.
*/ */
export default function AccountDrawerHeader({ export default function AccountDrawerHeader() {
account: { const { account } = useAccountDrawerContext();
account_normal,
account_type_label,
code,
amount,
currency_code,
description,
},
}) {
return ( return (
<div className={'account-drawer__content'}> <div className={'account-drawer__content-header'}>
<div> <DetailsMenu>
<span> <DetailItem
<T id={'closing_balance'} /> name={'closing-balance'}
</span> label={<T id={'closing_balance'} />}
<p className={'balance'}> >
{<Money amount={amount} currency={currency_code} />} <h3 class={'big-number'}>
</p> <Money amount={account.amount} currency={account.currency_code} />
</div> </h3>
<div class={'account-type'}> </DetailItem>
<span>
<T id={'account_type'} /> <DetailItem name={'account-type'} label={<T id={'account_type'} />}>
</span> {account.account_type_label}
<p>{account_type_label}</p> </DetailItem>
</div>
<div class={'account-normal'}> <DetailItem name={'account-normal'} label={<T id={'account_normal'} />}>
<span> {account.account_normal}
<T id={'account_normal'} />
</span>
<p>
{' '}
{account_normal}{' '}
<Icon <Icon
iconSize={14} iconSize={14}
icon={`arrow-${account_normal === 'credit' ? 'down' : 'up'}`} icon={`arrow-${
account.account_normal === 'credit' ? 'down' : 'up'
}`}
/> />
</p> </DetailItem>
</div>
<div>
<span>
<T id={'code'} />
</span>
<p>{code}</p>
</div>
<div>
<span>
<T id={'currency'} />
</span>
<p>{currency_code}</p>
</div>
<p className={'account-drawer__content--desc'}> <DetailItem name={'code'} label={<T id={'code'} />}>
<b> {account.code}
<T id={'description'} /> </DetailItem>
</b>
: {description ? description : '--'} <DetailItem name={'currency'} label={<T id={'currency'} />}>
</p> {account.currency_code}
</DetailItem>
</DetailsMenu>
<DetailsMenu direction={'horizantal'}>
<DetailItem name={'description'} label={<T id={'description'} />}>
{defaultTo(account.description, '--')}
</DetailItem>
</DetailsMenu>
</div> </div>
); );
} }

View File

@@ -14,12 +14,12 @@ function AccountDrawerProvider({ accountId, name, ...props }) {
}); });
// Load the specific account transactions. // Load the specific account transactions.
const { const { data: accounts, isLoading: isAccountsLoading } =
data: accounts, useAccountTransactions(accountId, {
isLoading: isAccountsLoading,
} = useAccountTransactions(accountId, {
enabled: !!accountId, enabled: !!accountId,
}); });
// Drawer title.
const drawerTitle = `${account.name} ${account.code}`; const drawerTitle = `${account.name} ${account.code}`;
// provider. // provider.

View File

@@ -1,61 +1,29 @@
import React from 'react'; import React from 'react';
import moment from 'moment';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import intl from 'react-intl-universal';
import { useAccountDrawerContext } from './AccountDrawerProvider'; import { useAccountDrawerContext } from './AccountDrawerProvider';
import intl from 'react-intl-universal'; import { DataTable, If } from 'components';
import { DataTable, Money } from 'components';
import { isBlank, compose } from 'utils'; import { compose } from 'utils';
import { useAccountReadEntriesColumns } from './utils';
import withDrawerActions from 'containers/Drawer/withDrawerActions'; import withDrawerActions from 'containers/Drawer/withDrawerActions';
/** /**
* account drawer table. * account drawer table.
*/ */
function AccountDrawerTable({ closeDrawer }) { function AccountDrawerTable({ closeDrawer }) {
const { const {
account: { currency_code }, account,
accounts, accounts,
drawerName, drawerName,
} = useAccountDrawerContext(); } = useAccountDrawerContext();
const columns = React.useMemo( // Account read-only entries table columns.
() => [ const columns = useAccountReadEntriesColumns();
{
Header: intl.get('transaction_date'),
accessor: ({ date }) => moment(date).format('YYYY MMM DD'),
width: 110,
},
{
Header: intl.get('transaction_type'),
accessor: 'reference_type_formatted',
width: 100,
},
{
Header: intl.get('credit'),
accessor: ({ credit }) =>
!isBlank(credit) && credit !== 0 ? (
<Money amount={credit} currency={currency_code} />
) : null,
width: 80,
},
{
Header: intl.get('debit'),
accessor: ({ debit }) =>
!isBlank(debit) && debit !== 0 ? (
<Money amount={debit} currency={currency_code} />
) : null,
width: 80,
},
{
Header: intl.get('running_balance'),
accessor: ({ running_balance }) => (
<Money amount={running_balance} currency={currency_code} />
),
width: 110,
},
],
[],
);
// Handle view more link click. // Handle view more link click.
const handleLinkClick = () => { const handleLinkClick = () => {
@@ -64,8 +32,9 @@ function AccountDrawerTable({ closeDrawer }) {
return ( return (
<div className={'account-drawer__table'}> <div className={'account-drawer__table'}>
<DataTable columns={columns} data={accounts} /> <DataTable columns={columns} data={accounts} payload={{ account }}/>
<If condition={accounts.length > 0}>
<div class="account-drawer__table-footer"> <div class="account-drawer__table-footer">
<Link <Link
to={`/financial-reports/general-ledger`} to={`/financial-reports/general-ledger`}
@@ -74,6 +43,7 @@ function AccountDrawerTable({ closeDrawer }) {
{intl.get('view_more_transactions')} {intl.get('view_more_transactions')}
</Link> </Link>
</div> </div>
</If>
</div> </div>
); );
} }

View File

@@ -15,9 +15,16 @@ function AccountDrawer({
isOpen, isOpen,
payload: { accountId }, payload: { accountId },
}) { }) {
return ( return (
<Drawer isOpen={isOpen} name={name} size={'900px'}> <Drawer
isOpen={isOpen}
name={name}
style={{
minWidth: '700px',
maxWidth: '900px',
}}
size={'65%'}
>
<DrawerSuspense> <DrawerSuspense>
<AccountDrawerContent name={name} accountId={accountId} /> <AccountDrawerContent name={name} accountId={accountId} />
</DrawerSuspense> </DrawerSuspense>

View File

@@ -0,0 +1,62 @@
import intl from 'react-intl-universal';
import React from 'react';
import moment from 'moment';
import { Money } from 'components';
import { isBlank } from 'utils';
/**
* Debit/credit table cell.
*/
function DebitCreditTableCell({ value, payload: { account } }) {
return !isBlank(value) && value !== 0 ? (
<Money amount={value} currency={account.currency_code} />
) : null;
}
/**
* Running balance table cell.
*/
function RunningBalanceTableCell({ value, payload: { account } }) {
return (
<Money amount={value} currency={account.currency_code} />
);
}
/**
* Retrieve entries columns of read-only account view.
*/
export const useAccountReadEntriesColumns = () =>
React.useMemo(
() => [
{
Header: intl.get('transaction_date'),
accessor: ({ date }) => moment(date).format('YYYY MMM DD'),
width: 110,
},
{
Header: intl.get('transaction_type'),
accessor: 'reference_type_formatted',
width: 100,
},
{
Header: intl.get('credit'),
accessor: 'credit',
Cell: DebitCreditTableCell,
width: 80,
},
{
Header: intl.get('debit'),
accessor: 'debit',
Cell: DebitCreditTableCell,
width: 80,
},
{
Header: intl.get('running_balance'),
Cell: RunningBalanceTableCell,
accessor: 'running_balance',
width: 110,
},
],
[],
);

View File

@@ -1,23 +1,26 @@
import React from 'react'; import React from 'react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import Icon from 'components/Icon'; import Icon from 'components/Icon';
import { Button, Classes, NavbarGroup, Intent } from '@blueprintjs/core'; import {
Button,
Classes,
NavbarGroup,
Intent,
NavbarDivider,
} from '@blueprintjs/core';
import { FormattedMessage as T } from 'components'; import { FormattedMessage as T } from 'components';
import { safeCallback } from 'utils';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar'; import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import withAlertsActions from 'containers/Alert/withAlertActions'; import withAlertsActions from 'containers/Alert/withAlertActions';
import withDrawerActions from 'containers/Drawer/withDrawerActions'; import withDrawerActions from 'containers/Drawer/withDrawerActions';
import { compose } from 'utils'; import { compose } from 'utils';
import { useExpenseDrawerContext } from './ExpenseDrawerProvider';
/** /**
* Expense drawer action bar. * Expense drawer action bar.
*/ */
function ExpenseDrawerActionBar({ function ExpenseDrawerActionBar({
// #ownProps
expense,
// #withAlertsDialog // #withAlertsDialog
openAlert, openAlert,
@@ -25,21 +28,18 @@ function ExpenseDrawerActionBar({
closeDrawer, closeDrawer,
}) { }) {
const history = useHistory(); const history = useHistory();
const { expense } = useExpenseDrawerContext();
// Handle the expense edit action. // Handle the expense edit action.
const onEditExpense = () => { const handleEditExpense = () => {
if (expense) {
history.push(`/expenses/${expense.id}/edit`); history.push(`/expenses/${expense.id}/edit`);
closeDrawer('expense-drawer'); closeDrawer('expense-drawer');
}
}; };
// Handle the expense delete action. // Handle the expense delete action.
const onDeleteExpense = () => { const handleDeleteExpense = () => {
if (expense) {
openAlert('expense-delete', { expenseId: expense.id }); openAlert('expense-delete', { expenseId: expense.id });
closeDrawer('expense-drawer'); closeDrawer('expense-drawer');
}
}; };
return ( return (
@@ -49,15 +49,15 @@ function ExpenseDrawerActionBar({
className={Classes.MINIMAL} className={Classes.MINIMAL}
icon={<Icon icon="pen-18" />} icon={<Icon icon="pen-18" />}
text={<T id={'edit_expense'} />} text={<T id={'edit_expense'} />}
onClick={safeCallback(onEditExpense)} onClick={handleEditExpense}
/> />
<NavbarDivider />
<Button <Button
className={Classes.MINIMAL} className={Classes.MINIMAL}
icon={<Icon style={{ color: 'red' }} icon="trash-18" iconSize={18} />} icon={<Icon icon="trash-16" iconSize={16} />}
text={<T id={'delete'} />} text={<T id={'delete'} />}
// intent={Intent.DANGER} intent={Intent.DANGER}
onClick={safeCallback(onDeleteExpense)} onClick={handleDeleteExpense}
/> />
</NavbarGroup> </NavbarGroup>
</DashboardActionsBar> </DashboardActionsBar>

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import 'style/components/Drawers/ViewDetails.scss'; import 'style/components/Drawers/ExpenseDrawer.scss';
import { ExpenseDrawerProvider } from './ExpenseDrawerProvider'; import { ExpenseDrawerProvider } from './ExpenseDrawerProvider';
import ExpenseDrawerDetails from './ExpenseDrawerDetails'; import ExpenseDrawerDetails from './ExpenseDrawerDetails';

View File

@@ -1,22 +1,26 @@
import React from 'react'; import React from 'react';
import { Card } from 'components';
import ExpenseDrawerActionBar from './ExpenseDrawerActionBar'; import ExpenseDrawerActionBar from './ExpenseDrawerActionBar';
import ExpenseDrawerHeader from './ExpenseDrawerHeader'; import ExpenseDrawerHeader from './ExpenseDrawerHeader';
import ExpenseDrawerTable from './ExpenseDrawerTable'; import ExpenseDrawerTable from './ExpenseDrawerTable';
import ExpenseDrawerFooter from './ExpenseDrawerFooter'; import ExpenseDrawerFooter from './ExpenseDrawerFooter';
import { useExpenseDrawerContext } from './ExpenseDrawerProvider';
/** /**
* Expense view details. * Expense view details.
*/ */
export default function ExpenseDrawerDetails() { export default function ExpenseDrawerDetails() {
const { expense } = useExpenseDrawerContext();
return ( return (
<div className={'expense-drawer'}> <div className={'expense-drawer'}>
<ExpenseDrawerActionBar expense={expense} /> <ExpenseDrawerActionBar />
<div className="expense-drawer__content"> <div className="expense-drawer__content">
<ExpenseDrawerHeader expense={expense} /> <Card>
<ExpenseDrawerTable expense={expense} /> <ExpenseDrawerHeader />
<ExpenseDrawerFooter expense={expense} /> <ExpenseDrawerTable />
<ExpenseDrawerFooter />
</Card>
</div> </div>
</div> </div>
); );

View File

@@ -1,20 +1,19 @@
import React from 'react'; import React from 'react';
import { If, Money } from 'components'; import { useExpenseDrawerContext } from './ExpenseDrawerProvider';
import { FormattedMessage as T } from 'components';
export default function ExpenseDrawerFooter() {
const { expense: { total_amount } } = useExpenseDrawerContext();
export default function ExpenseDrawerFooter({
expense: { total_amount, currency_code },
}) {
return ( return (
<div className="expense-drawer__content--footer"> <div className="expense-drawer__content-footer">
<div className="wrapper"> <div class="total-lines">
<div> <div class="total-lines__line total-lines__line--subtotal">
<span><T id={'sub_total'}/></span> <div class="title">Subtotal</div>
<p>{<Money amount={total_amount} currency={currency_code} />}</p> <div class="amount">{total_amount}</div>
</div> </div>
<div> <div class="total-lines__line total-lines__line--total">
<span><T id={'total'}/></span> <div class="title">TOTAL</div>
<p>{<Money amount={total_amount} currency={currency_code} />}</p> <div class="amount">{total_amount}</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,68 +1,58 @@
import React from 'react'; import React from 'react';
import moment from 'moment'; import moment from 'moment';
import { If, Money } from 'components'; import { defaultTo } from 'lodash';
import { DetailItem, DetailsMenu, Money } from 'components';
import { FormattedMessage as T } from 'components'; import { FormattedMessage as T } from 'components';
import { useExpenseDrawerContext } from './ExpenseDrawerProvider';
/** /**
* Expense drawer content. * Expense drawer content.
*/ */
export default function ExpenseDrawerHeader({ export default function ExpenseDrawerHeader() {
const {
expense: { expense: {
total_amount, total_amount,
payment_account: { name },
payment_date, payment_date,
currency_code, currency_code,
reference_no, reference_no,
description, description,
published_at, published_at,
}, },
}) { } = useExpenseDrawerContext();
return ( return (
<div className={'expense-drawer__content--header'}> <div className={'expense-drawer__content-header'}>
<div className={'info'}> <DetailsMenu>
<span> <DetailItem name={'amount'} label={<T id={'full_amount'} />}>
<T id={'full_amount'} /> <h3 class="big-number">
</span> <Money amount={total_amount} currency={currency_code} />
<p className="balance"> </h3>
{<Money amount={total_amount} currency={currency_code} />} </DetailItem>
</p>
</div> <DetailItem name={'date'} label={<T id={'date'} />}>
<div className={'info'}> {moment(payment_date).format('YYYY MMM DD')}
<span> </DetailItem>
<T id={'date'} />
</span> <DetailItem name={'currency'} label={<T id={'currency'} />}>
<p>{moment(payment_date).format('YYYY MMM DD')}</p> {currency_code}
</div> </DetailItem>
<div className={'info'}>
<span> <DetailItem name={'reference'} label={<T id={'reference_no'} />}>
<T id={'payment_account_'} /> {defaultTo(reference_no, '-')}
</span> </DetailItem>
<p>{name}</p>
</div> <DetailItem label={<T id={'published_at'} />}>
<div className={'info'}> {moment(published_at).format('YYYY MMM DD')}
<span> </DetailItem>
<T id={'currency'} /> </DetailsMenu>
</span>
<p>{currency_code}</p> <DetailsMenu direction={'horizantal'}>
</div> <DetailItem label={<T id={'description'} />}>
<div className={'info'}> {defaultTo(description, '—')}
<span> </DetailItem>
<T id={'reference_no'} /> <DetailItem label={<T id={'created_at'} />}>2021 Aug 24</DetailItem>
</span> </DetailsMenu>
<p>{reference_no}</p>
</div>
<div className={'info'}>
<span>
<T id={'published_at'} />
</span>
<p>{moment(published_at).format('YYYY MMM DD')}</p>
</div>
<div className={'info'}>
<span>
<T id={'description'} />
</span>
<p>{description}</p>
</div>
</div> </div>
); );
} }

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { useExpense } from 'hooks/query'; import { useExpense } from 'hooks/query';
import { DrawerHeaderContent, DashboardInsider } from 'components'; import { DashboardInsider } from 'components';
const ExpenseDrawerDrawerContext = React.createContext(); const ExpenseDrawerDrawerContext = React.createContext();
@@ -8,16 +8,22 @@ const ExpenseDrawerDrawerContext = React.createContext();
* Expense drawer provider. * Expense drawer provider.
*/ */
function ExpenseDrawerProvider({ expenseId, ...props }) { function ExpenseDrawerProvider({ expenseId, ...props }) {
// Fetch the expense details. // Fetch the expense details.
const { data: expense, isLoading: isExpenseLoading } = useExpense(expenseId, { const {
data: expense,
isLoading: isExpenseLoading,
isFetching: isExpenseFetching,
} = useExpense(expenseId, {
enabled: !!expenseId, enabled: !!expenseId,
}); });
// provider. // Provider.
const provider = { const provider = {
expenseId, expenseId,
expense, expense,
isExpenseFetching,
isExpenseLoading,
}; };
return ( return (
<DashboardInsider loading={isExpenseLoading}> <DashboardInsider loading={isExpenseLoading}>

View File

@@ -1,40 +1,18 @@
import React from 'react'; import React from 'react';
import { DataTable } from 'components';
import intl from 'react-intl-universal'; import { useExpenseReadEntriesColumns } from './utils';
import { DataTable, Money } from 'components'; import { useExpenseDrawerContext } from './ExpenseDrawerProvider';
/** /**
* Expense details table. * Expense details table.
*/ */
export default function ExpenseDrawerTable({ export default function ExpenseDrawerTable() {
expense: { currency_code, categories }, const columns = useExpenseReadEntriesColumns();
}) { const { expense } = useExpenseDrawerContext();
const columns = React.useMemo(
() => [
{
Header: intl.get('expense_account'),
accessor: 'expense_account.name',
width: 110,
},
{
Header: intl.get('amount'),
accessor: ({ amount }) => (
<Money amount={amount} currency={currency_code} />
),
width: 100,
},
{
Header: intl.get('description'),
accessor: 'description',
width: 110,
},
],
[],
);
return ( return (
<div className="expense-drawer__content--table"> <div className="expense-drawer__content--table">
<DataTable columns={columns} data={categories} /> <DataTable columns={columns} data={expense.categories} />
</div> </div>
); );
} }

View File

@@ -15,10 +15,19 @@ function ExpenseDrawer({
//#withDrawer //#withDrawer
isOpen, isOpen,
payload: { expenseId, title }, payload: { expenseId },
}) { }) {
return ( return (
<Drawer isOpen={isOpen} name={name} title={intl.get('expense')}> <Drawer
isOpen={isOpen}
name={name}
title={intl.get('expense')}
size={'65%'}
style={{
minWidth: '700px',
maxWidth: '900px',
}}
>
<DrawerSuspense> <DrawerSuspense>
<ExpenseDrawerContent expenseId={expenseId} /> <ExpenseDrawerContent expenseId={expenseId} />
</DrawerSuspense> </DrawerSuspense>

View File

@@ -0,0 +1,27 @@
import React from 'react';
import intl from 'react-intl-universal';
export const useExpenseReadEntriesColumns = () =>
React.useMemo(
() => [
{
Header: intl.get('expense_account'),
accessor: 'expense_account.name',
width: 110,
disableSortBy: true,
},
{
Header: intl.get('description'),
accessor: 'description',
width: 110,
disableSortBy: true,
},
{
Header: intl.get('amount'),
accessor: 'amount',
width: 100,
disableSortBy: true,
},
],
[],
);

View File

@@ -1,23 +1,26 @@
import React from 'react'; import React from 'react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import Icon from 'components/Icon'; import Icon from 'components/Icon';
import { Button, Classes, NavbarGroup, Intent } from '@blueprintjs/core'; import {
Button,
Classes,
NavbarGroup,
Intent,
NavbarDivider,
} from '@blueprintjs/core';
import { FormattedMessage as T } from 'components'; import { FormattedMessage as T } from 'components';
import { safeCallback } from 'utils';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar'; import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import withAlertsActions from 'containers/Alert/withAlertActions'; import withAlertsActions from 'containers/Alert/withAlertActions';
import withDrawerActions from 'containers/Drawer/withDrawerActions'; import withDrawerActions from 'containers/Drawer/withDrawerActions';
import { compose } from 'utils'; import { compose } from 'utils';
import { useManualJournalDrawerContext } from './ManualJournalDrawerProvider';
/** /**
* Manual journal action bar. * Manual journal action bar.
*/ */
function ManualJournalDrawerActionBar({ function ManualJournalDrawerActionBar({
// #ownProps
manualJournal,
// #withAlertsDialog // #withAlertsDialog
openAlert, openAlert,
@@ -25,21 +28,17 @@ function ManualJournalDrawerActionBar({
closeDrawer, closeDrawer,
}) { }) {
const history = useHistory(); const history = useHistory();
const { manualJournalId } = useManualJournalDrawerContext();
// Handle edit manual journal action. // Handle edit manual journal action.
const onEditManualJournal = () => { const handleEditManualJournal = () => {
if (manualJournal) { history.push(`/manual-journals/${manualJournalId}/edit`);
history.push(`/manual-journals/${manualJournal.id}/edit`);
closeDrawer('journal-drawer'); closeDrawer('journal-drawer');
}
}; };
// Handle manual journal delete action. // Handle manual journal delete action.
const onDeleteManualJournal = () => { const handleDeleteManualJournal = () => {
if (manualJournal) { openAlert('journal-delete', { manualJournalId });
openAlert('journal-delete', { manualJournalId: manualJournal.id });
closeDrawer('journal-drawer');
}
}; };
return ( return (
@@ -49,14 +48,15 @@ function ManualJournalDrawerActionBar({
className={Classes.MINIMAL} className={Classes.MINIMAL}
icon={<Icon icon="pen-18" />} icon={<Icon icon="pen-18" />}
text={<T id={'edit_journal'} />} text={<T id={'edit_journal'} />}
onClick={safeCallback(onEditManualJournal)} onClick={handleEditManualJournal}
/> />
<NavbarDivider />
<Button <Button
className={Classes.MINIMAL} className={Classes.MINIMAL}
icon={<Icon style={{ color: 'red' }} icon="trash-18" iconSize={18} />} icon={<Icon icon="trash-16" iconSize={16} />}
text={<T id={'delete'} />} text={<T id={'delete'} />}
onClick={safeCallback(onDeleteManualJournal)} intent={Intent.DANGER}
onClick={handleDeleteManualJournal}
/> />
</NavbarGroup> </NavbarGroup>
</DashboardActionsBar> </DashboardActionsBar>

View File

@@ -1,4 +1,7 @@
import React from 'react'; import React from 'react';
import { Card } from 'components';
import ManualJournalDrawerActionBar from './ManualJournalDrawerActionBar'; import ManualJournalDrawerActionBar from './ManualJournalDrawerActionBar';
import ManualJournalDrawerHeader from './ManualJournalDrawerHeader'; import ManualJournalDrawerHeader from './ManualJournalDrawerHeader';
import ManualJournalDrawerTable from './ManualJournalDrawerTable'; import ManualJournalDrawerTable from './ManualJournalDrawerTable';
@@ -15,10 +18,13 @@ export default function ManualJournalDrawerDetails() {
return ( return (
<div className={'journal-drawer'}> <div className={'journal-drawer'}>
<ManualJournalDrawerActionBar manualJournal={manualJournal} /> <ManualJournalDrawerActionBar manualJournal={manualJournal} />
<div className="journal-drawer__content"> <div className="journal-drawer__content">
<ManualJournalDrawerHeader manualJournal={manualJournal} /> <Card>
<ManualJournalDrawerTable manualJournal={manualJournal} /> <ManualJournalDrawerHeader />
<ManualJournalDrawerFooter manualJournal={manualJournal} /> <ManualJournalDrawerTable />
<ManualJournalDrawerFooter />
</Card>
</div> </div>
</div> </div>
); );

View File

@@ -1,25 +1,27 @@
import React from 'react'; import React from 'react';
import { FormattedMessage as T } from 'components'; import { useManualJournalDrawerContext } from './ManualJournalDrawerProvider';
export default function ManualJournalDrawerFooter({}) {
const {
manualJournal: { amount },
} = useManualJournalDrawerContext();
export default function ManualJournalDrawerFooter({
manualJournal: { amount_formatted },
}) {
return ( return (
<div className="journal-drawer__content--footer"> <div className="journal-drawer__content-footer">
<div className="wrapper"> <div class="total-lines">
<div> <div class="total-lines__line total-lines__line--subtotal">
<span> <div class="title">Subtotal</div>
<T id={'sub_total'} /> <div class="debit">{amount}</div>
</span> <div class="credit">{amount} </div>
<p>{amount_formatted}</p>
</div> </div>
<div> <div class="total-lines__line total-lines__line--total">
<span> <div class="title">TOTAL</div>
<T id={'total'} /> <div class="debit">{amount}</div>
</span> <div class="credit">{amount}</div>
<p>{amount_formatted}</p>
</div> </div>
</div> </div>
</div> </div>
); );
} }

View File

@@ -1,47 +1,49 @@
import React from 'react'; import React from 'react';
import { FormattedMessage as T } from 'components'; import { defaultTo } from 'lodash';
import { DetailsMenu, DetailItem, FormattedMessage as T } from 'components';
import { useManualJournalDrawerContext } from './ManualJournalDrawerProvider';
/** /**
* Manual journal details header. * Manual journal details header.
*/ */
export default function ManualJournalDrawerHeader({ export default function ManualJournalDrawerHeader() {
const {
manualJournal: { manualJournal: {
amount_formatted, formatted_amount,
journal_type, journal_type,
journal_number, journal_number,
reference, reference,
currency_code, currency_code,
description,
}, },
}) { } = useManualJournalDrawerContext();
return ( return (
<div className={'journal-drawer__content--header'}> <div className={'journal-drawer__content-header'}>
<div> <DetailsMenu>
<T id={'total'} /> <DetailItem name={'total'} label={<T id={'total'} />}>
<p className="balance">{amount_formatted}</p> <h3 class="amount">{formatted_amount}</h3>
</div> </DetailItem>
<div>
<span> <DetailItem name={'journal-type'} label={<T id={'journal_type'} />}>
<T id={'journal_type'} /> {journal_type}
</span> </DetailItem>
<p>{journal_type}</p>
</div> <DetailItem name={'journal-number'} label={<T id={'journal_no'} />}>
<div> {journal_number}
<span> </DetailItem>
<T id={'journal_no'} />
</span> <DetailItem name={'reference-no'} label={<T id={'reference_no'} />}>
<p>{journal_number}</p> {defaultTo(reference, '-')}
</div> </DetailItem>
<div>
<span> <DetailItem name={'currency'} label={<T id={'currency'} />}>
<T id={'reference_no'} /> {currency_code}
</span> </DetailItem>
<p>{reference}</p> </DetailsMenu>
</div>
<div> <div class="journal-drawer__content-description">
<span> <b class="title">Description</b>: {defaultTo(description, '')}
<T id={'currency'} />
</span>
<p>{currency_code}</p>
</div> </div>
</div> </div>
); );

View File

@@ -9,17 +9,22 @@ const ManualJournalDrawerContext = React.createContext();
* Manual journal drawer provider. * Manual journal drawer provider.
*/ */
function ManualJournalDrawerProvider({ manualJournalId, ...props }) { function ManualJournalDrawerProvider({ manualJournalId, ...props }) {
// fetch the specific manual journal details. // Fetch the specific manual journal details.
const { data: manualJournal, isLoading: isJournalLoading } = useJournal( const {
manualJournalId, data: manualJournal,
{ isLoading: isJournalLoading,
isFetching: isJournalFetching,
} = useJournal(manualJournalId, {
enabled: !!manualJournalId, enabled: !!manualJournalId,
}, });
);
// provider. // Provider.
const provider = { const provider = {
manualJournalId, manualJournalId,
manualJournal, manualJournal,
isJournalFetching,
isJournalLoading,
}; };
return ( return (

View File

@@ -1,73 +1,20 @@
import React from 'react'; import React from 'react';
import { Classes, Tooltip, Position } from '@blueprintjs/core';
import intl from 'react-intl-universal'; import { DataTable, If } from 'components';
import { DataTable, Money, If, Icon } from 'components'; import { useManualJournalEntriesColumns } from './utils';
import { isBlank } from 'utils'; import { useManualJournalDrawerContext } from './ManualJournalDrawerProvider';
/**
* Note column accessor.
*/
export function NoteAccessor(row) {
return (
<If condition={row.note}>
<Tooltip
className={Classes.TOOLTIP_INDICATOR}
content={row.note}
position={Position.LEFT_TOP}
hoverOpenDelay={50}
>
<Icon icon={'file-alt'} iconSize={16} />
</Tooltip>
</If>
);
}
/** /**
* Manual journal drawer table. * Manual journal drawer table.
*/ */
export default function ManualJournalDrawerTable({ export default function ManualJournalDrawerTable() {
manualJournal: { entries, description, currency_code }, const columns = useManualJournalEntriesColumns();
}) { const {
const columns = React.useMemo( manualJournal: { entries, description },
() => [ } = useManualJournalDrawerContext();
{
Header: intl.get('account_name'),
accessor: 'account.name',
width: 130,
},
{
Header: intl.get('contact'),
accessor: 'contact.display_name',
width: 130,
},
{
Header: intl.get('credit'),
accessor: ({ credit }) =>
!isBlank(credit) && credit !== 0 ? (
<Money amount={credit} currency={currency_code} />
) : null,
width: 80,
},
{
Header: intl.get('debit'),
accessor: ({ debit }) =>
!isBlank(debit) && debit !== 0 ? (
<Money amount={debit} currency={currency_code} />
) : null,
width: 80,
},
{
Header: intl.get('note'),
accessor: NoteAccessor,
width: 80,
},
],
[],
);
return ( return (
<div className="journal-drawer__content--table"> <div className="journal-drawer__content-table">
<DataTable columns={columns} data={entries} /> <DataTable columns={columns} data={entries} />
<If condition={description}> <If condition={description}>

View File

@@ -19,7 +19,15 @@ function ManualJournalDrawer({
payload: { manualJournalId }, payload: { manualJournalId },
}) { }) {
return ( return (
<Drawer isOpen={isOpen} name={name} size={'900px'}> <Drawer
isOpen={isOpen}
name={name}
size={'65%'}
style={{
minWidth: '700px',
maxWidth: '900px',
}}
>
<DrawerSuspense> <DrawerSuspense>
<ManualJournalDrawerContent manualJournalId={manualJournalId} /> <ManualJournalDrawerContent manualJournalId={manualJournalId} />
</DrawerSuspense> </DrawerSuspense>

View File

@@ -0,0 +1,65 @@
import intl from 'react-intl-universal';
import React from 'react';
import { Classes, Tooltip, Position } from '@blueprintjs/core';
import { If, Icon } from 'components';
/**
* Note column accessor.
*/
export function NoteAccessor(row) {
return (
<If condition={row.note}>
<Tooltip
className={Classes.TOOLTIP_INDICATOR}
content={row.note}
position={Position.LEFT_TOP}
hoverOpenDelay={50}
>
<Icon icon={'file-alt'} iconSize={16} />
</Tooltip>
</If>
);
}
/**
* Retrieve read-only manual journal entries columns.
*/
export const useManualJournalEntriesColumns = () =>
React.useMemo(
() => [
{
Header: intl.get('account_name'),
accessor: 'account.name',
width: 130,
disableSortBy: true,
},
{
Header: intl.get('contact'),
accessor: 'contact.display_name',
width: 130,
disableSortBy: true,
},
{
Header: intl.get('note'),
accessor: NoteAccessor,
width: 80,
disableSortBy: true,
},
{
Header: intl.get('credit'),
accessor: 'credit',
width: 100,
disableResizable: true,
disableSortBy: true,
},
{
Header: intl.get('debit'),
accessor: 'debit',
width: 100,
disableResizable: true,
disableSortBy: true,
},
],
[],
);

View File

@@ -21,6 +21,7 @@ import { ExpensesListProvider } from './ExpensesListProvider';
function ExpensesList({ function ExpensesList({
// #withExpenses // #withExpenses
expensesTableState, expensesTableState,
expensesTableStateChanged,
// #withExpensesActions // #withExpensesActions
setExpensesTableState, setExpensesTableState,
@@ -40,6 +41,7 @@ function ExpensesList({
return ( return (
<ExpensesListProvider <ExpensesListProvider
query={transformTableStateToQuery(expensesTableState)} query={transformTableStateToQuery(expensesTableState)}
tableStateChanged={expensesTableStateChanged}
> >
<ExpenseActionsBar /> <ExpenseActionsBar />
@@ -57,6 +59,9 @@ function ExpensesList({
} }
export default compose( export default compose(
withExpenses(({ expensesTableState }) => ({ expensesTableState })), withExpenses(({ expensesTableState, expensesTableStateChanged }) => ({
expensesTableState,
expensesTableStateChanged,
})),
withExpensesActions, withExpensesActions,
)(ExpensesList); )(ExpensesList);

View File

@@ -1,14 +1,16 @@
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { isEmpty } from 'lodash';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { useExpenses, useResourceMeta, useResourceViews } from 'hooks/query'; import { useExpenses, useResourceMeta, useResourceViews } from 'hooks/query';
import { isTableEmptyStatus, getFieldsFromResourceMeta } from 'utils'; import { getFieldsFromResourceMeta } from 'utils';
const ExpensesListContext = createContext(); const ExpensesListContext = createContext();
/** /**
* Accounts chart data provider. * Accounts chart data provider.
*/ */
function ExpensesListProvider({ query, ...props }) { function ExpensesListProvider({ query, tableStateChanged, ...props }) {
// Fetch accounts resource views and fields. // Fetch accounts resource views and fields.
const { data: expensesViews, isLoading: isViewsLoading } = const { data: expensesViews, isLoading: isViewsLoading } =
useResourceViews('expenses'); useResourceViews('expenses');
@@ -29,11 +31,7 @@ function ExpensesListProvider({ query, ...props }) {
// Detarmines the datatable empty status. // Detarmines the datatable empty status.
const isEmptyStatus = const isEmptyStatus =
isTableEmptyStatus({ isEmpty(expenses) && !isExpensesLoading && !tableStateChanged;
data: expenses,
pagination,
filterMeta,
}) && !isExpensesFetching;
// Provider payload. // Provider payload.
const provider = { const provider = {

View File

@@ -1,12 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { getExpensesTableStateFactory } from 'store/expenses/expenses.selectors'; import {
expensesTableStateChangedFactory,
getExpensesTableStateFactory,
} from 'store/expenses/expenses.selectors';
export default (mapState) => { export default (mapState) => {
const getExpensesTableState = getExpensesTableStateFactory(); const getExpensesTableState = getExpensesTableStateFactory();
const expensesTableStateChanged = expensesTableStateChangedFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const mapped = { const mapped = {
expensesTableState: getExpensesTableState(state, props), expensesTableState: getExpensesTableState(state, props),
expensesTableStateChanged: expensesTableStateChanged(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -1,8 +1,12 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { setExpensesTableState } from 'store/expenses/expenses.actions'; import {
setExpensesTableState,
resetExpensesTableState,
} from 'store/expenses/expenses.actions';
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setExpensesTableState: (state) => dispatch(setExpensesTableState(state)), setExpensesTableState: (state) => dispatch(setExpensesTableState(state)),
resetExpensesTableState: (state) => dispatch(resetExpensesTableState(state)),
}); });
export default connect(null, mapDispatchToProps); export default connect(null, mapDispatchToProps);

View File

@@ -11,7 +11,9 @@ import ItemsViewsTabs from './ItemsViewsTabs';
import ItemsDataTable from './ItemsDataTable'; import ItemsDataTable from './ItemsDataTable';
import { ItemsListProvider } from './ItemsListProvider'; import { ItemsListProvider } from './ItemsListProvider';
import withItems from './withItems'; import withItems from './withItems';
import withItemsActions from './withItemsActions';
/** /**
* Items list. * Items list.
@@ -19,9 +21,24 @@ import withItems from './withItems';
function ItemsList({ function ItemsList({
// #withItems // #withItems
itemsTableState, itemsTableState,
itemsTableStateChanged,
// #withItemsActions
resetItemsTableState,
}) { }) {
// Resets items table query state once the page unmount.
React.useEffect(
() => () => {
resetItemsTableState();
},
[resetItemsTableState],
);
return ( return (
<ItemsListProvider tableState={itemsTableState}> <ItemsListProvider
tableState={itemsTableState}
tableStateChanged={itemsTableStateChanged}
>
<ItemsActionsBar /> <ItemsActionsBar />
<DashboardPageContent> <DashboardPageContent>
@@ -38,5 +55,9 @@ function ItemsList({
} }
export default compose( export default compose(
withItems(({ itemsTableState }) => ({ itemsTableState })), withItemsActions,
withItems(({ itemsTableState, itemsTableStateChanged }) => ({
itemsTableState,
itemsTableStateChanged,
})),
)(ItemsList); )(ItemsList);

View File

@@ -1,5 +1,5 @@
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { isEmpty } from 'lodash';
import { import {
getFieldsFromResourceMeta, getFieldsFromResourceMeta,
transformTableQueryToParams, transformTableQueryToParams,
@@ -15,7 +15,7 @@ const ItemsContext = createContext();
/** /**
* Items list provider. * Items list provider.
*/ */
function ItemsListProvider({ tableState, ...props }) { function ItemsListProvider({ tableState, tableStateChanged, ...props }) {
const tableQuery = transformItemsTableState(tableState); const tableQuery = transformItemsTableState(tableState);
// Fetch accounts resource views and fields. // Fetch accounts resource views and fields.
@@ -43,13 +43,7 @@ function ItemsListProvider({ tableState, ...props }) {
// Detarmines the datatable empty status. // Detarmines the datatable empty status.
const isEmptyStatus = const isEmptyStatus =
isTableEmptyStatus({ !tableStateChanged && !isItemsLoading && isEmpty(items);
data: items,
pagination,
filterMeta,
}) &&
!isItemsFetching &&
!tableState.inactiveMode;
const state = { const state = {
itemsViews, itemsViews,
@@ -68,7 +62,10 @@ function ItemsListProvider({ tableState, ...props }) {
}; };
return ( return (
<DashboardInsider loading={isItemsLoading || isResourceLoading} name={'items-list'}> <DashboardInsider
loading={isItemsLoading || isResourceLoading}
name={'items-list'}
>
<ItemsContext.Provider value={state} {...props} /> <ItemsContext.Provider value={state} {...props} />
</DashboardInsider> </DashboardInsider>
); );

View File

@@ -22,7 +22,7 @@ function ItemsViewsTabs({
const { itemsViews } = useItemsListContext(); const { itemsViews } = useItemsListContext();
// Mapped items views. // Mapped items views.
const tabs = transfromViewsToTabs(itemsViews) const tabs = transfromViewsToTabs(itemsViews);
// Handles the active tab change. // Handles the active tab change.
const handleTabChange = (viewSlug) => { const handleTabChange = (viewSlug) => {
@@ -46,7 +46,7 @@ function ItemsViewsTabs({
export default compose( export default compose(
withRouter, withRouter,
withItems(({ itemsTableState }) => ({ withItems(({ itemsTableState }) => ({
itemsCurrentView: itemsTableState?.viewSlug itemsCurrentView: itemsTableState?.viewSlug,
})), })),
withItemsActions, withItemsActions,
)(ItemsViewsTabs); )(ItemsViewsTabs);

View File

@@ -1,15 +1,18 @@
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import { import {
getItemsTableStateFactory, getItemsTableStateFactory,
isItemsTableStateChangedFactory,
} from 'store/items/items.selectors'; } from 'store/items/items.selectors';
export default (mapState) => { export default (mapState) => {
const getItemsTableState = getItemsTableStateFactory(); const getItemsTableState = getItemsTableStateFactory();
const isItemsTableStateChanged = isItemsTableStateChangedFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const mapped = { const mapped = {
itemsSelectedRows: state.items.selectedRows, itemsSelectedRows: state.items.selectedRows,
itemsTableState: getItemsTableState(state, props), itemsTableState: getItemsTableState(state, props),
itemsTableStateChanged: isItemsTableStateChanged(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -1,8 +1,12 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { setItemsTableState }from 'store/items/items.actions'; import {
setItemsTableState,
resetItemsTableState,
} from 'store/items/items.actions';
export const mapDispatchToProps = (dispatch) => ({ export const mapDispatchToProps = (dispatch) => ({
setItemsTableState: (queries) => dispatch(setItemsTableState(queries)), setItemsTableState: (queries) => dispatch(setItemsTableState(queries)),
resetItemsTableState: () => dispatch(resetItemsTableState()),
}); });
export default connect(null, mapDispatchToProps); export default connect(null, mapDispatchToProps);

View File

@@ -21,9 +21,10 @@ import { transformTableStateToQuery, compose } from 'utils';
function BillsList({ function BillsList({
// #withBills // #withBills
billsTableState, billsTableState,
billsTableStateChanged,
// #withBillsActions // #withBillsActions
setBillsTableState setBillsTableState,
}) { }) {
// Resets the accounts table state once the page unmount. // Resets the accounts table state once the page unmount.
useEffect( useEffect(
@@ -38,7 +39,10 @@ function BillsList({
); );
return ( return (
<BillsListProvider query={transformTableStateToQuery(billsTableState)}> <BillsListProvider
query={transformTableStateToQuery(billsTableState)}
tableStateChanged={billsTableStateChanged}
>
<BillsActionsBar /> <BillsActionsBar />
<DashboardPageContent> <DashboardPageContent>
@@ -55,6 +59,9 @@ function BillsList({
} }
export default compose( export default compose(
withBills(({ billsTableState }) => ({ billsTableState })), withBills(({ billsTableState, billsTableStateChanged }) => ({
withBillsActions billsTableState,
billsTableStateChanged,
})),
withBillsActions,
)(BillsList); )(BillsList);

View File

@@ -1,14 +1,17 @@
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { isEmpty } from 'lodash';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { useResourceViews, useResourceMeta, useBills } from 'hooks/query'; import { useResourceViews, useResourceMeta, useBills } from 'hooks/query';
import { getFieldsFromResourceMeta, isTableEmptyStatus } from 'utils';
import { getFieldsFromResourceMeta } from 'utils';
const BillsListContext = createContext(); const BillsListContext = createContext();
/** /**
* Accounts chart data provider. * Accounts chart data provider.
*/ */
function BillsListProvider({ query, ...props }) { function BillsListProvider({ query, tableStateChanged, ...props }) {
// Fetch accounts resource views and fields. // Fetch accounts resource views and fields.
const { data: billsViews, isLoading: isViewsLoading } = const { data: billsViews, isLoading: isViewsLoading } =
useResourceViews('bills'); useResourceViews('bills');
@@ -29,11 +32,7 @@ function BillsListProvider({ query, ...props }) {
// Detarmines the datatable empty status. // Detarmines the datatable empty status.
const isEmptyStatus = const isEmptyStatus =
isTableEmptyStatus({ isEmpty(bills) && !isBillsLoading && !tableStateChanged;
data: bills,
pagination,
filterMeta,
}) && !isBillsFetching;
// Provider payload. // Provider payload.
const provider = { const provider = {

View File

@@ -1,12 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { getBillsTableStateFactory } from 'store/Bills/bills.selectors'; import {
getBillsTableStateFactory,
billsTableStateChangedFactory,
} from 'store/Bills/bills.selectors';
export default (mapState) => { export default (mapState) => {
const getBillsTableState = getBillsTableStateFactory(); const getBillsTableState = getBillsTableStateFactory();
const billsTableStateChanged = billsTableStateChangedFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const mapped = { const mapped = {
billsTableState: getBillsTableState(state, props), billsTableState: getBillsTableState(state, props),
billsTableStateChanged: billsTableStateChanged(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -1,8 +1,12 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { setBillsTableState } from 'store/Bills/bills.actions'; import {
setBillsTableState,
resetBillsTableState,
} from 'store/Bills/bills.actions';
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setBillsTableState: (queries) => dispatch(setBillsTableState(queries)), setBillsTableState: (queries) => dispatch(setBillsTableState(queries)),
resetBillsTableState: () => dispatch(resetBillsTableState()),
}); });
export default connect(null, mapDispatchToProps); export default connect(null, mapDispatchToProps);

View File

@@ -43,17 +43,17 @@ function PaymentMadeActionsBar({
// Payment receives list context. // Payment receives list context.
const { paymentMadesViews, fields } = usePaymentMadesListContext(); const { paymentMadesViews, fields } = usePaymentMadesListContext();
// Payment receive refresh action.
const { refresh } = useRefreshPaymentMades();
// Handle new payment made button click. // Handle new payment made button click.
const handleClickNewPaymentMade = () => { const handleClickNewPaymentMade = () => {
history.push('/payment-mades/new'); history.push('/payment-mades/new');
}; };
// Payment receive refresh action.
const { refresh } = useRefreshPaymentMades();
// Handle tab changing. // Handle tab changing.
const handleTabChange = (customView) => { const handleTabChange = (viewSlug) => {
setPaymentMadesTableState({ customViewId: customView.id || null }); setPaymentMadesTableState({ viewSlug });
}; };
// Handle click a refresh payment receives. // Handle click a refresh payment receives.

View File

@@ -20,25 +20,23 @@ import { compose, transformTableStateToQuery } from 'utils';
function PaymentMadeList({ function PaymentMadeList({
// #withPaymentMades // #withPaymentMades
paymentMadesTableState, paymentMadesTableState,
paymentsTableStateChanged,
// #withPaymentMadeActions // #withPaymentMadeActions
setPaymentMadesTableState resetPaymentMadesTableState,
}) { }) {
// Resets the invoices table state once the page unmount. // Resets the invoices table state once the page unmount.
React.useEffect( React.useEffect(
() => () => { () => () => {
setPaymentMadesTableState({ resetPaymentMadesTableState();
filterRoles: [],
viewSlug: '',
pageIndex: 0,
});
}, },
[setPaymentMadesTableState], [resetPaymentMadesTableState],
); );
return ( return (
<PaymentMadesListProvider <PaymentMadesListProvider
query={transformTableStateToQuery(paymentMadesTableState)} query={transformTableStateToQuery(paymentMadesTableState)}
tableStateChanged={paymentsTableStateChanged}
> >
<PaymentMadeActionsBar /> <PaymentMadeActionsBar />
@@ -56,8 +54,9 @@ function PaymentMadeList({
} }
export default compose( export default compose(
withPaymentMades(({ paymentMadesTableState }) => ({ withPaymentMades(({ paymentMadesTableState, paymentsTableStateChanged }) => ({
paymentMadesTableState, paymentMadesTableState,
paymentsTableStateChanged,
})), })),
withPaymentMadeActions withPaymentMadeActions,
)(PaymentMadeList); )(PaymentMadeList);

View File

@@ -2,7 +2,6 @@ import React from 'react';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import { FormattedMessage as T } from 'components'; import { FormattedMessage as T } from 'components';
import { Alignment, Navbar, NavbarGroup } from '@blueprintjs/core'; import { Alignment, Navbar, NavbarGroup } from '@blueprintjs/core';
import { pick } from 'lodash';
import { DashboardViewsTabs } from 'components'; import { DashboardViewsTabs } from 'components';
@@ -10,6 +9,8 @@ import { usePaymentMadesListContext } from './PaymentMadesListProvider';
import withPaymentMadeActions from './withPaymentMadeActions'; import withPaymentMadeActions from './withPaymentMadeActions';
import { compose } from 'utils'; import { compose } from 'utils';
import { transformPaymentViewsToTabs } from './utils';
import withPaymentMade from './withPaymentMade'; import withPaymentMade from './withPaymentMade';
/** /**
@@ -28,15 +29,14 @@ function PaymentMadeViewTabs({
const { paymentMadesViews } = usePaymentMadesListContext(); const { paymentMadesViews } = usePaymentMadesListContext();
// Handle the active tab changning. // Handle the active tab changning.
const handleTabsChange = (customView) => { const handleTabsChange = (viewSlug) => {
setPaymentMadesTableState({ setPaymentMadesTableState({ viewSlug });
customViewId: customView.id || null,
});
}; };
// Transformes payment views to tabs.
const tabs = paymentMadesViews.map((view) => ({ const tabs = React.useMemo(
...pick(view, ['name', 'id']), () => transformPaymentViewsToTabs(paymentMadesViews),
})); [paymentMadesViews],
);
const handleClickNewView = () => { const handleClickNewView = () => {
history.push('/custom_views/payment-mades/new'); history.push('/custom_views/payment-mades/new');
@@ -59,5 +59,5 @@ function PaymentMadeViewTabs({
export default compose( export default compose(
withPaymentMadeActions, withPaymentMadeActions,
withPaymentMade(({ paymentMadesTableState }) => ({ paymentMadesTableState })) withPaymentMade(({ paymentMadesTableState }) => ({ paymentMadesTableState })),
)(PaymentMadeViewTabs); )(PaymentMadeViewTabs);

View File

@@ -1,23 +1,23 @@
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { isEmpty } from 'lodash';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { import {
useResourceViews, useResourceViews,
usePaymentMades, usePaymentMades,
useResourceMeta useResourceMeta,
} from 'hooks/query'; } from 'hooks/query';
import { isTableEmptyStatus, getFieldsFromResourceMeta } from 'utils'; import { getFieldsFromResourceMeta } from 'utils';
const PaymentMadesListContext = createContext(); const PaymentMadesListContext = createContext();
/** /**
* Accounts chart data provider. * Accounts chart data provider.
*/ */
function PaymentMadesListProvider({ query, ...props }) { function PaymentMadesListProvider({ query, tableStateChanged, ...props }) {
// Fetch accounts resource views and fields. // Fetch accounts resource views and fields.
const { const { data: paymentMadesViews, isLoading: isViewsLoading } =
data: paymentMadesViews, useResourceViews('bill_payments');
isLoading: isViewsLoading,
} = useResourceViews('bill_payments');
// Fetch the accounts resource fields. // Fetch the accounts resource fields.
const { const {
@@ -35,11 +35,7 @@ function PaymentMadesListProvider({ query, ...props }) {
// Detarmines the datatable empty status. // Detarmines the datatable empty status.
const isEmptyStatus = const isEmptyStatus =
isTableEmptyStatus({ isEmpty(paymentMades) && !isPaymentsLoading && !tableStateChanged;
data: paymentMades,
pagination,
filterMeta,
}) && !isPaymentsLoading;
// Provider payload. // Provider payload.
const provider = { const provider = {
@@ -56,7 +52,7 @@ function PaymentMadesListProvider({ query, ...props }) {
isPaymentsLoading, isPaymentsLoading,
isPaymentsFetching, isPaymentsFetching,
isViewsLoading, isViewsLoading,
isEmptyStatus isEmptyStatus,
}; };
return ( return (

View File

@@ -0,0 +1,7 @@
import { pick } from 'lodash';
export const transformPaymentViewsToTabs = (paymentMadeViews) => {
return paymentMadeViews.map((view) => ({
...pick(view, ['name', 'id']),
}));
};

View File

@@ -1,14 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
getPaymentMadesTableStateFactory getPaymentMadesTableStateFactory,
paymentsTableStateChangedFactory,
} from 'store/PaymentMades/paymentMades.selector'; } from 'store/PaymentMades/paymentMades.selector';
export default (mapState) => { export default (mapState) => {
const getPaymentMadesTableState = getPaymentMadesTableStateFactory(); const getPaymentMadesTableState = getPaymentMadesTableStateFactory();
const paymentsTableStateChanged = paymentsTableStateChangedFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const mapped = { const mapped = {
paymentMadesTableState: getPaymentMadesTableState(state, props), paymentMadesTableState: getPaymentMadesTableState(state, props),
paymentsTableStateChanged: paymentsTableStateChanged(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -1,8 +1,13 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { setPaymentMadesTableState } from 'store/PaymentMades/paymentMades.actions'; import {
setPaymentMadesTableState,
resetPaymentMadesTableState,
} from 'store/PaymentMades/paymentMades.actions';
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setPaymentMadesTableState: (state) => setPaymentMadesTableState: (state) =>
dispatch(setPaymentMadesTableState(state)), dispatch(setPaymentMadesTableState(state)),
resetPaymentMadesTableState: () => dispatch(resetPaymentMadesTableState()),
}); });
export default connect(null, mapDispatchToProps); export default connect(null, mapDispatchToProps);

View File

@@ -46,7 +46,6 @@ function EstimateActionsBar({
const onClickNewEstimate = () => { const onClickNewEstimate = () => {
history.push('/estimates/new'); history.push('/estimates/new');
}; };
// Estimates refresh action. // Estimates refresh action.
const { refresh } = useRefreshEstimates(); const { refresh } = useRefreshEstimates();

View File

@@ -20,25 +20,23 @@ import { compose, transformTableStateToQuery } from 'utils';
function EstimatesList({ function EstimatesList({
// #withEstimate // #withEstimate
estimatesTableState, estimatesTableState,
estimatesTableStateChanged,
// #withEstimatesActions // #withEstimatesActions
setEstimatesTableState resetEstimatesTableState,
}) { }) {
// Resets the estimates table state once the page unmount. // Resets the estimates table state once the page unmount.
React.useEffect( React.useEffect(
() => () => { () => () => {
setEstimatesTableState({ resetEstimatesTableState();
filterRoles: [],
viewSlug: '',
pageIndex: 0,
});
}, },
[setEstimatesTableState], [resetEstimatesTableState],
); );
return ( return (
<EstimatesListProvider <EstimatesListProvider
query={transformTableStateToQuery(estimatesTableState)} query={transformTableStateToQuery(estimatesTableState)}
tableStateChanged={estimatesTableStateChanged}
> >
<EstimatesActionsBar /> <EstimatesActionsBar />
@@ -56,6 +54,9 @@ function EstimatesList({
} }
export default compose( export default compose(
withEstimates(({ estimatesTableState }) => ({ estimatesTableState })), withEstimates(({ estimatesTableState, estimatesTableStateChanged }) => ({
withEstimatesActions estimatesTableState,
estimatesTableStateChanged,
})),
withEstimatesActions,
)(EstimatesList); )(EstimatesList);

View File

@@ -1,16 +1,18 @@
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { isEmpty } from 'lodash';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { useResourceViews, useResourceMeta, useEstimates } from 'hooks/query'; import { useResourceViews, useResourceMeta, useEstimates } from 'hooks/query';
import { isTableEmptyStatus, getFieldsFromResourceMeta } from 'utils'; import { getFieldsFromResourceMeta } from 'utils';
// Estimates list context.
const EstimatesListContext = createContext(); const EstimatesListContext = createContext();
/** /**
* Sale estimates data provider. * Sale estimates data provider.
*/ */
function EstimatesListProvider({ query, ...props }) { function EstimatesListProvider({ query, tableStateChanged, ...props }) {
// Fetches estimates resource views and fields. // Fetches estimates resource views and fields.
const { data: estimatesViews, isLoading: isViewsLoading } = const { data: estimatesViews, isLoading: isViewsLoading } =
useResourceViews('sale_estimates'); useResourceViews('sale_estimates');
@@ -31,11 +33,7 @@ function EstimatesListProvider({ query, ...props }) {
// Detarmines the datatable empty status. // Detarmines the datatable empty status.
const isEmptyStatus = const isEmptyStatus =
isTableEmptyStatus({ !isEstimatesLoading && !tableStateChanged && isEmpty(estimates);
data: estimates,
pagination,
filterMeta,
}) && !isEstimatesFetching;
// Provider payload. // Provider payload.
const provider = { const provider = {

View File

@@ -1,14 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
getEstimatesTableStateFactory, getEstimatesTableStateFactory,
isEstimatesTableStateChangedFactory,
} from 'store/Estimate/estimates.selectors'; } from 'store/Estimate/estimates.selectors';
export default (mapState) => { export default (mapState) => {
const getEstimatesTableState = getEstimatesTableStateFactory(); const getEstimatesTableState = getEstimatesTableStateFactory();
const isEstimatesTableStateChanged = isEstimatesTableStateChangedFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const mapped = { const mapped = {
estimatesTableState: getEstimatesTableState(state, props), estimatesTableState: getEstimatesTableState(state, props),
estimatesTableStateChanged: isEstimatesTableStateChanged(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -1,10 +1,12 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
setEstimatesTableState, setEstimatesTableState,
resetEstimatesTableState,
} from 'store/Estimate/estimates.actions'; } from 'store/Estimate/estimates.actions';
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setEstimatesTableState: (state) => dispatch(setEstimatesTableState(state)), setEstimatesTableState: (state) => dispatch(setEstimatesTableState(state)),
resetEstimatesTableState: () => dispatch(resetEstimatesTableState()),
}); });
export default connect(null, mapDispatchToProps); export default connect(null, mapDispatchToProps);

View File

@@ -29,9 +29,7 @@ function InvoiceViewTabs({
// Handle tab change. // Handle tab change.
const handleTabsChange = (viewSlug) => { const handleTabsChange = (viewSlug) => {
setInvoicesTableState({ setInvoicesTableState({ viewSlug });
viewSlug: viewSlug || null,
});
}; };
// Handle click a new view tab. // Handle click a new view tab.
const handleClickNewView = () => { const handleClickNewView = () => {

View File

@@ -22,25 +22,23 @@ import { transformTableStateToQuery, compose } from 'utils';
function InvoicesList({ function InvoicesList({
// #withInvoice // #withInvoice
invoicesTableState, invoicesTableState,
invoicesTableStateChanged,
// #withInvoicesActions // #withInvoicesActions
setInvoicesTableState resetInvoicesTableState,
}) { }) {
// Resets the invoices table state once the page unmount. // Resets the invoices table state once the page unmount.
React.useEffect( React.useEffect(
() => () => { () => () => {
setInvoicesTableState({ resetInvoicesTableState();
filterRoles: [],
viewSlug: '',
pageIndex: 0,
});
}, },
[setInvoicesTableState], [resetInvoicesTableState],
); );
return ( return (
<InvoicesListProvider <InvoicesListProvider
query={transformTableStateToQuery(invoicesTableState)} query={transformTableStateToQuery(invoicesTableState)}
tableStateChanged={invoicesTableStateChanged}
> >
<InvoicesActionsBar /> <InvoicesActionsBar />
@@ -58,7 +56,10 @@ function InvoicesList({
} }
export default compose( export default compose(
withInvoices(({ invoicesTableState }) => ({ invoicesTableState })), withInvoices(({ invoicesTableState, invoicesTableStateChanged }) => ({
invoicesTableState,
invoicesTableStateChanged,
})),
withInvoiceActions, withInvoiceActions,
withAlertsActions, withAlertsActions,
)(InvoicesList); )(InvoicesList);

View File

@@ -1,14 +1,16 @@
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { isEmpty } from 'lodash';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { useResourceViews, useResourceMeta, useInvoices } from 'hooks/query'; import { useResourceViews, useResourceMeta, useInvoices } from 'hooks/query';
import { isTableEmptyStatus, getFieldsFromResourceMeta } from 'utils'; import { getFieldsFromResourceMeta } from 'utils';
const InvoicesListContext = createContext(); const InvoicesListContext = createContext();
/** /**
* Accounts chart data provider. * Accounts chart data provider.
*/ */
function InvoicesListProvider({ query, ...props }) { function InvoicesListProvider({ query, tableStateChanged, ...props }) {
// Fetch accounts resource views and fields. // Fetch accounts resource views and fields.
const { data: invoicesViews, isLoading: isViewsLoading } = const { data: invoicesViews, isLoading: isViewsLoading } =
useResourceViews('sale_invoices'); useResourceViews('sale_invoices');
@@ -29,11 +31,7 @@ function InvoicesListProvider({ query, ...props }) {
// Detarmines the datatable empty status. // Detarmines the datatable empty status.
const isEmptyStatus = const isEmptyStatus =
isTableEmptyStatus({ isEmpty(invoices) && !tableStateChanged && !isInvoicesLoading;
data: invoices,
pagination,
filterMeta,
}) && !isInvoicesLoading;
// Provider payload. // Provider payload.
const provider = { const provider = {

View File

@@ -1,10 +1,12 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
setInvoicesTableState setInvoicesTableState,
resetInvoicesTableState
} from 'store/Invoice/invoices.actions'; } from 'store/Invoice/invoices.actions';
const mapDipatchToProps = (dispatch) => ({ const mapDipatchToProps = (dispatch) => ({
setInvoicesTableState: (queries) => dispatch(setInvoicesTableState(queries)), setInvoicesTableState: (queries) => dispatch(setInvoicesTableState(queries)),
resetInvoicesTableState: () => dispatch(resetInvoicesTableState()),
}); });
export default connect(null, mapDipatchToProps); export default connect(null, mapDipatchToProps);

View File

@@ -1,14 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
getInvoicesTableStateFactory, getInvoicesTableStateFactory,
isInvoicesTableStateChangedFactory,
} from 'store/Invoice/invoices.selector'; } from 'store/Invoice/invoices.selector';
export default (mapState) => { export default (mapState) => {
const getInvoicesTableState = getInvoicesTableStateFactory(); const getInvoicesTableState = getInvoicesTableStateFactory();
const isInvoicesTableStateChanged = isInvoicesTableStateChangedFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const mapped = { const mapped = {
invoicesTableState: getInvoicesTableState(state, props), invoicesTableState: getInvoicesTableState(state, props),
invoicesTableStateChanged: isInvoicesTableStateChanged(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -20,25 +20,23 @@ import { compose, transformTableStateToQuery } from 'utils';
function PaymentReceiveList({ function PaymentReceiveList({
// #withPaymentReceives // #withPaymentReceives
paymentReceivesTableState, paymentReceivesTableState,
paymentsTableStateChanged,
// #withPaymentReceivesActions // #withPaymentReceivesActions
setPaymentReceivesTableState resetPaymentReceivesTableState,
}) { }) {
// Resets the payment receives table state once the page unmount. // Resets the payment receives table state once the page unmount.
React.useEffect( React.useEffect(
() => () => { () => () => {
setPaymentReceivesTableState({ resetPaymentReceivesTableState();
filterRoles: [],
viewSlug: '',
pageIndex: 0,
});
}, },
[setPaymentReceivesTableState], [resetPaymentReceivesTableState],
); );
return ( return (
<PaymentReceivesListProvider <PaymentReceivesListProvider
query={transformTableStateToQuery(paymentReceivesTableState)} query={transformTableStateToQuery(paymentReceivesTableState)}
tableStateChanged={paymentsTableStateChanged}
> >
<PaymentReceiveActionsBar /> <PaymentReceiveActionsBar />
@@ -56,8 +54,11 @@ function PaymentReceiveList({
} }
export default compose( export default compose(
withPaymentReceives(({ paymentReceivesTableState }) => ({ withPaymentReceives(
({ paymentReceivesTableState, paymentsTableStateChanged }) => ({
paymentReceivesTableState, paymentReceivesTableState,
})), paymentsTableStateChanged,
}),
),
withPaymentReceivesActions, withPaymentReceivesActions,
)(PaymentReceiveList); )(PaymentReceiveList);

View File

@@ -1,4 +1,6 @@
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { isEmpty } from 'lodash';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { import {
useResourceViews, useResourceViews,
@@ -12,7 +14,7 @@ const PaymentReceivesListContext = createContext();
/** /**
* Payment receives data provider. * Payment receives data provider.
*/ */
function PaymentReceivesListProvider({ query, ...props }) { function PaymentReceivesListProvider({ query, tableStateChanged, ...props }) {
// Fetch accounts resource views and fields. // Fetch accounts resource views and fields.
const { const {
data: paymentReceivesViews, data: paymentReceivesViews,
@@ -33,6 +35,10 @@ function PaymentReceivesListProvider({ query, ...props }) {
isFetching: isPaymentReceivesFetching, isFetching: isPaymentReceivesFetching,
} = usePaymentReceives(query, { keepPreviousData: true }); } = usePaymentReceives(query, { keepPreviousData: true });
// Detarmines the datatable empty status.
const isEmptyStatus =
!isPaymentReceivesLoading && !tableStateChanged && isEmpty(paymentReceives);
// Provider payload. // Provider payload.
const provider = { const provider = {
paymentReceives, paymentReceives,
@@ -42,6 +48,7 @@ function PaymentReceivesListProvider({ query, ...props }) {
fields: getFieldsFromResourceMeta(resourceMeta.fields), fields: getFieldsFromResourceMeta(resourceMeta.fields),
isEmptyStatus,
isViewsLoading, isViewsLoading,
isResourceFetching, isResourceFetching,
isResourceLoading, isResourceLoading,

View File

@@ -1,14 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
getPaymentReceiveTableStateFactory getPaymentReceiveTableStateFactory,
paymentsTableStateChangedFactory
} from 'store/PaymentReceives/paymentReceives.selector'; } from 'store/PaymentReceives/paymentReceives.selector';
export default (mapState) => { export default (mapState) => {
const getPaymentReceiveTableState = getPaymentReceiveTableStateFactory(); const getPaymentReceiveTableState = getPaymentReceiveTableStateFactory();
const paymentsTableStateChanged = paymentsTableStateChangedFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const mapped = { const mapped = {
paymentReceivesTableState: getPaymentReceiveTableState(state, props), paymentReceivesTableState: getPaymentReceiveTableState(state, props),
paymentsTableStateChanged: paymentsTableStateChanged(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -1,9 +1,15 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { setPaymentReceivesTableState } from 'store/PaymentReceives/paymentReceives.actions'; import {
setPaymentReceivesTableState,
resetPaymentReceivesTableState,
} from 'store/PaymentReceives/paymentReceives.actions';
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setPaymentReceivesTableState: (state) => setPaymentReceivesTableState: (state) =>
dispatch(setPaymentReceivesTableState(state)), dispatch(setPaymentReceivesTableState(state)),
resetPaymentReceivesTableState: () =>
dispatch(resetPaymentReceivesTableState()),
}); });
export default connect(null, mapDispatchToProps); export default connect(null, mapDispatchToProps);

View File

@@ -20,24 +20,24 @@ import { transformTableStateToQuery, compose } from 'utils';
function ReceiptsList({ function ReceiptsList({
// #withReceipts // #withReceipts
receiptTableState, receiptTableState,
receiptsTableStateChanged,
// #withReceiptsActions // #withReceiptsActions
setReceiptsTableState, resetReceiptsTableState,
}) { }) {
// Resets the receipts table state once the page unmount. // Resets the receipts table state once the page unmount.
React.useEffect( React.useEffect(
() => () => { () => () => {
setReceiptsTableState({ resetReceiptsTableState();
filterRoles: [],
viewSlug: '',
pageIndex: 0,
});
}, },
[setReceiptsTableState], [resetReceiptsTableState],
); );
return ( return (
<ReceiptsListProvider query={transformTableStateToQuery(receiptTableState)}> <ReceiptsListProvider
query={transformTableStateToQuery(receiptTableState)}
tableStateChanged={receiptsTableStateChanged}
>
<DashboardPageContent> <DashboardPageContent>
<ReceiptActionsBar /> <ReceiptActionsBar />
@@ -56,8 +56,9 @@ function ReceiptsList({
} }
export default compose( export default compose(
withReceipts(({ receiptTableState }) => ({ withReceipts(({ receiptTableState, receiptsTableStateChanged }) => ({
receiptTableState, receiptTableState,
receiptsTableStateChanged,
})), })),
withReceiptsActions, withReceiptsActions,
)(ReceiptsList); )(ReceiptsList);

View File

@@ -1,13 +1,15 @@
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { isEmpty } from 'lodash';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { useResourceMeta, useResourceViews, useReceipts } from 'hooks/query'; import { useResourceMeta, useResourceViews, useReceipts } from 'hooks/query';
import { isTableEmptyStatus, getFieldsFromResourceMeta } from 'utils'; import { getFieldsFromResourceMeta } from 'utils';
const ReceiptsListContext = createContext(); const ReceiptsListContext = createContext();
// Receipts list provider. // Receipts list provider.
function ReceiptsListProvider({ query, ...props }) { function ReceiptsListProvider({ query, tableStateChanged, ...props }) {
// Fetch receipts resource views and fields. // Fetch receipts resource views and fields.
const { data: receiptsViews, isLoading: isViewsLoading } = const { data: receiptsViews, isLoading: isViewsLoading } =
useResourceViews('sale_receipt'); useResourceViews('sale_receipt');
@@ -27,11 +29,7 @@ function ReceiptsListProvider({ query, ...props }) {
// Detarmines the datatable empty status. // Detarmines the datatable empty status.
const isEmptyStatus = const isEmptyStatus =
isTableEmptyStatus({ isEmpty(receipts) && !tableStateChanged && !isReceiptsLoading;
data: receipts,
pagination,
filterMeta,
}) && !isReceiptsLoading;
const provider = { const provider = {
receipts, receipts,

View File

@@ -1,14 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
getReceiptsTableStateFactory, getReceiptsTableStateFactory,
receiptsTableStateChangedFactory,
} from 'store/receipts/receipts.selector'; } from 'store/receipts/receipts.selector';
export default (mapState) => { export default (mapState) => {
const getReceiptsTableState = getReceiptsTableStateFactory(); const getReceiptsTableState = getReceiptsTableStateFactory();
const receiptsTableStateChanged = receiptsTableStateChangedFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const mapped = { const mapped = {
receiptTableState: getReceiptsTableState(state, props), receiptTableState: getReceiptsTableState(state, props),
receiptsTableStateChanged: receiptsTableStateChanged(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -1,8 +1,12 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { setReceiptsTableState } from 'store/receipts/receipts.actions'; import {
setReceiptsTableState,
resetReceiptsTableState,
} from 'store/receipts/receipts.actions';
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setReceiptsTableState: (queries) => dispatch(setReceiptsTableState(queries)), setReceiptsTableState: (queries) => dispatch(setReceiptsTableState(queries)),
resetReceiptsTableState: () => dispatch(resetReceiptsTableState()),
}); });
export default connect(null, mapDispatchToProps); export default connect(null, mapDispatchToProps);

View File

@@ -66,19 +66,14 @@ function DashboardUniversalSearch({
setSearchKeyword(query); setSearchKeyword(query);
}; };
// Handle search type change. // Handle search type change.
const handleSearchTypeChange = (searchType) => { const handleSearchTypeChange = (type) => {
remove(); remove();
setSearchType(searchType.key); setSearchType(type.key);
if (searchKeyword && searchType) {
refetch();
}
}; };
// Handle overlay of universal search close. // Handle overlay of universal search close.
const handleClose = () => { const handleClose = () => {
closeGlobalSearch(); closeGlobalSearch();
}; };
// Handle universal search item select. // Handle universal search item select.
const handleItemSelect = (item) => { const handleItemSelect = (item) => {
setSelectedItemUniversalSearch(searchType, item.id); setSelectedItemUniversalSearch(searchType, item.id);
@@ -92,10 +87,10 @@ function DashboardUniversalSearch({
); );
React.useEffect(() => { React.useEffect(() => {
if (searchKeyword) { if (searchKeyword && searchType) {
debounceFetch.current(); debounceFetch.current();
} }
}, [searchKeyword]); }, [searchKeyword, searchType]);
// Handles the overlay once be closed. // Handles the overlay once be closed.
const handleOverlayClosed = () => { const handleOverlayClosed = () => {

View File

@@ -4,6 +4,7 @@ import * as R from 'ramda';
import withUniversalSearch from './withUniversalSearch'; import withUniversalSearch from './withUniversalSearch';
import { getUniversalSearchItemsActions } from './utils'; import { getUniversalSearchItemsActions } from './utils';
import withUniversalSearchActions from './withUniversalSearchActions';
/** /**
* Universal search selected item action based on each resource type. * Universal search selected item action based on each resource type.
@@ -11,13 +12,22 @@ import { getUniversalSearchItemsActions } from './utils';
function DashboardUniversalSearchItemActions({ function DashboardUniversalSearchItemActions({
searchSelectedResourceType, searchSelectedResourceType,
searchSelectedResourceId, searchSelectedResourceId,
// #with
resetSelectedItemUniversalSearch,
}) { }) {
const components = getUniversalSearchItemsActions(); const components = getUniversalSearchItemsActions();
// Handle action execuation.
const handleActionExec = React.useCallback(() => {
resetSelectedItemUniversalSearch();
}, [resetSelectedItemUniversalSearch]);
return components.map((COMPONENT) => ( return components.map((COMPONENT) => (
<COMPONENT <COMPONENT
resourceId={searchSelectedResourceId} resourceId={searchSelectedResourceId}
resourceType={searchSelectedResourceType} resourceType={searchSelectedResourceType}
onAction={handleActionExec}
/> />
)); ));
} }
@@ -29,4 +39,5 @@ export default R.compose(
searchSelectedResourceId, searchSelectedResourceId,
}), }),
), ),
withUniversalSearchActions,
)(DashboardUniversalSearchItemActions); )(DashboardUniversalSearchItemActions);

View File

@@ -53,8 +53,8 @@ function VendorActionsBar({
const { refresh } = useRefreshVendors(); const { refresh } = useRefreshVendors();
// Handle the active tab change. // Handle the active tab change.
const handleTabChange = (customView) => { const handleTabChange = (viewSlug) => {
setVendorsTableState({ customViewId: customView.id || null }); setVendorsTableState({ viewSlug });
}; };
// Handle inactive switch changing. // Handle inactive switch changing.

View File

@@ -22,12 +22,12 @@ function VendorViewsTabs({
}) { }) {
const { vendorsViews } = useVendorsListContext(); const { vendorsViews } = useVendorsListContext();
// Transformes the resource views to tabs.
const tabs = transfromViewsToTabs(vendorsViews); const tabs = transfromViewsToTabs(vendorsViews);
// Handle dashboard tabs change.
const handleTabsChange = (viewSlug) => { const handleTabsChange = (viewSlug) => {
setVendorsTableState({ setVendorsTableState({ viewSlug });
viewSlug: viewSlug || null,
});
}; };
return ( return (

View File

@@ -21,9 +21,10 @@ import { compose } from 'utils';
function VendorsList({ function VendorsList({
// #withVendors // #withVendors
vendorsTableState, vendorsTableState,
vendorsTableStateChanged,
// #withVendorsActions // #withVendorsActions
setVendorsTableState setVendorsTableState,
}) { }) {
// Resets the vendors table state once the page unmount. // Resets the vendors table state once the page unmount.
useEffect( useEffect(
@@ -38,7 +39,10 @@ function VendorsList({
); );
return ( return (
<VendorsListProvider tableState={vendorsTableState}> <VendorsListProvider
tableState={vendorsTableState}
tableStateChanged={vendorsTableStateChanged}
>
<VendorActionsBar /> <VendorActionsBar />
<DashboardPageContent> <DashboardPageContent>
@@ -55,6 +59,9 @@ function VendorsList({
} }
export default compose( export default compose(
withVendors(({ vendorsTableState }) => ({ vendorsTableState })), withVendors(({ vendorsTableState, vendorsTableStateChanged }) => ({
withVendorsActions vendorsTableState,
vendorsTableStateChanged,
})),
withVendorsActions,
)(VendorsList); )(VendorsList);

View File

@@ -1,4 +1,5 @@
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { isEmpty } from 'lodash';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { useResourceMeta, useResourceViews, useVendors } from 'hooks/query'; import { useResourceMeta, useResourceViews, useVendors } from 'hooks/query';
@@ -7,7 +8,7 @@ import { transformVendorsStateToQuery } from './utils';
const VendorsListContext = createContext(); const VendorsListContext = createContext();
function VendorsListProvider({ tableState, ...props }) { function VendorsListProvider({ tableState, tableStateChanged, ...props }) {
// Transformes the vendors table state to fetch query. // Transformes the vendors table state to fetch query.
const tableQuery = transformVendorsStateToQuery(tableState); const tableQuery = transformVendorsStateToQuery(tableState);
@@ -31,13 +32,7 @@ function VendorsListProvider({ tableState, ...props }) {
// Detarmines the datatable empty status. // Detarmines the datatable empty status.
const isEmptyStatus = const isEmptyStatus =
isTableEmptyStatus({ isEmpty(vendors) && !isVendorsLoading && !tableStateChanged;
data: vendors,
pagination,
filterMeta,
}) &&
!isVendorsLoading &&
!tableState.inactiveMode;
const provider = { const provider = {
vendors, vendors,

View File

@@ -1,14 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
getVendorsTableStateFactory, getVendorsTableStateFactory,
vendorsTableStateChangedFactory,
} from 'store/vendors/vendors.selectors'; } from 'store/vendors/vendors.selectors';
export default (mapState) => { export default (mapState) => {
const getVendorsTableState = getVendorsTableStateFactory(); const getVendorsTableState = getVendorsTableStateFactory();
const vendorsTableStateChanged = vendorsTableStateChangedFactory();
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
const mapped = { const mapped = {
vendorsTableState: getVendorsTableState(state, props), vendorsTableState: getVendorsTableState(state, props),
vendorsTableStateChanged: vendorsTableStateChanged(state, props),
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -1205,23 +1205,21 @@
"the_contact_has_been_inactivated_successfully": "تم إلغاء تنشيط جهة اتصال بنجاح.", "the_contact_has_been_inactivated_successfully": "تم إلغاء تنشيط جهة اتصال بنجاح.",
"are_sure_to_inactive_this_contact": "هل أنت متأكد أنك تريد إلغاء تنشيط جهة اتصال؟ ستكون قادرًا على تنشيطه لاحقًا", "are_sure_to_inactive_this_contact": "هل أنت متأكد أنك تريد إلغاء تنشيط جهة اتصال؟ ستكون قادرًا على تنشيطه لاحقًا",
"are_sure_to_activate_this_contact": "هل أنت متأكد أنك تريد تفعيل جهة اتصال؟ ستتمكن من تعطيله لاحقًا", "are_sure_to_activate_this_contact": "هل أنت متأكد أنك تريد تفعيل جهة اتصال؟ ستتمكن من تعطيله لاحقًا",
"publish_adjustment": "Publish adjustment", "publish_adjustment": "نشر التسوية",
"inactivate_customer": "Inactivate customer", "inactivate_customer": "تعطيل الزبون",
"activate_customer": "Activate customer", "activate_customer": "تفعيل الزبون",
"filter.all_filters_must_match": "Atleast one filter must match", "filter.all_filters_must_match": "يجب ان تتطابق مع جميع الشروط",
"filter.atleast_one_filter_must_match": "Atleast one filter must match", "filter.atleast_one_filter_must_match": "يجب أن يتطابق شرط واحد على الأقل",
"filter.when": "When", "filter.when": "عندما",
"universal_search.placeholder": "Search...", "universal_search.placeholder": "بحث...",
"universal_search.enter_text": "لتحديد",
"universal_search.enter_text": "To select", "universal_search.close_text": "لإغلاق",
"universal_search.close_text": "To close", "universal_seach.navigate_text": "للاختيار",
"universal_seach.navigate_text": "To navigate", "pdf_preview.dialog.title": "معاينة PDF",
"pdf_preview.dialog.title": "PDF Preview", "pdf_preview.download.button": "تحميل",
"pdf_preview.download.button": "Download", "pdf_preview.preview.button": "معاينة",
"pdf_preview.preview.button": "Preview", "invoice_preview.dialog.title": "معاينة فاتورة PDF",
"invoice_preview.dialog.title": "Invoice PDF Preview", "estimate_preview.dialog.title": "معاينة عرض PDF",
"estimate_preview.dialog.title": "Estimate PDF Preview", "receipt_preview.dialog.title":"معاينة إيصال PDF"
"receipt_preview.dialog.title":"Receipt PDF Preview"
} }

View File

@@ -1195,7 +1195,7 @@
"publish_adjustment": "Publish adjustment", "publish_adjustment": "Publish adjustment",
"inactivate_customer": "Inactivate customer", "inactivate_customer": "Inactivate customer",
"activate_customer": "Activate customer", "activate_customer": "Activate customer",
"filter.all_filters_must_match": "Atleast one filter must match", "filter.all_filters_must_match": "All filters must match",
"filter.atleast_one_filter_must_match": "Atleast one filter must match", "filter.atleast_one_filter_must_match": "Atleast one filter must match",
"filter.when": "When", "filter.when": "When",
"universal_search.placeholder": "Search...", "universal_search.placeholder": "Search...",

View File

@@ -7,4 +7,9 @@ export const setBillsTableState = (queries) => {
}; };
}; };
export const setSelectedRowsItems = () => {}; export const resetBillsTableState = () => {
return {
type: t.BILLS_TABLE_STATE_RESET,
};
};

View File

@@ -4,12 +4,15 @@ import storage from 'redux-persist/lib/storage';
import { createTableStateReducers } from 'store/tableState.reducer'; import { createTableStateReducers } from 'store/tableState.reducer';
import t from 'store/types'; import t from 'store/types';
const initialState = { export const defaultTableQuery = {
tableState: {
pageSize: 12, pageSize: 12,
pageIndex: 0, pageIndex: 0,
filterRoles: [] filterRoles: [],
}, viewSlug: null,
};
const initialState = {
tableState: defaultTableQuery,
}; };
const STORAGE_KEY = 'bigcapital:bills'; const STORAGE_KEY = 'bigcapital:bills';
@@ -21,14 +24,11 @@ const CONFIG = {
}; };
const reducerInstance = createReducer(initialState, { const reducerInstance = createReducer(initialState, {
...createTableStateReducers('BILLS'), ...createTableStateReducers('BILLS', defaultTableQuery),
[t.RESET]: () => { [t.RESET]: () => {
purgeStoredState(CONFIG); purgeStoredState(CONFIG);
} },
}); });
export default persistReducer( export default persistReducer(CONFIG, reducerInstance);
CONFIG,
reducerInstance,
);

View File

@@ -1,5 +1,8 @@
import { isEqual } from 'lodash';
import { paginationLocationQuery } from 'store/selectors'; import { paginationLocationQuery } from 'store/selectors';
import { createDeepEqualSelector } from 'utils'; import { createDeepEqualSelector } from 'utils';
import { defaultTableQuery } from './bills.reducer';
const billsTableStateSelector = (state) => state.bills.tableState; const billsTableStateSelector = (state) => state.bills.tableState;
@@ -15,3 +18,8 @@ export const getBillsTableStateFactory = () =>
}; };
}, },
); );
export const billsTableStateChangedFactory = () =>
createDeepEqualSelector(billsTableStateSelector, (tableState) => {
return !isEqual(tableState, defaultTableQuery);
});

View File

@@ -1,4 +1,5 @@
export default { export default {
BILLS_TABLE_STATE_SET: 'BILLS/TABLE_STATE_SET', BILLS_TABLE_STATE_SET: 'BILLS/TABLE_STATE_SET',
BILLS_TABLE_STATE_RESET: 'BILLS/TABLE_STATE_RESET',
}; };

View File

@@ -7,4 +7,8 @@ export const setEstimatesTableState = (queries) => {
}; };
}; };
export const setSelectedRowsItems = () => {}; export const resetEstimatesTableState = () => {
return {
type: t.ESTIMATES_TABLE_STATE_RESET,
};
}

View File

@@ -6,12 +6,15 @@ import {
} from 'store/tableState.reducer'; } from 'store/tableState.reducer';
import t from 'store/types'; import t from 'store/types';
const initialState = { export const defaultTableQuery = {
tableState: {
pageSize: 12, pageSize: 12,
pageIndex: 0, pageIndex: 0,
filterRoles: [], filterRoles: [],
}, viewSlug: null,
};
const initialState = {
tableState: defaultTableQuery,
}; };
const STORAGE_KEY = 'bigcapital:estimates'; const STORAGE_KEY = 'bigcapital:estimates';
@@ -23,7 +26,7 @@ const CONFIG = {
}; };
const reducerInstance = createReducer(initialState, { const reducerInstance = createReducer(initialState, {
...createTableStateReducers('ESTIMATES'), ...createTableStateReducers('ESTIMATES', defaultTableQuery),
[t.RESET]: () => { [t.RESET]: () => {
purgeStoredState(CONFIG); purgeStoredState(CONFIG);

View File

@@ -1,5 +1,7 @@
import { isEqual } from 'lodash';
import { createDeepEqualSelector } from 'utils'; import { createDeepEqualSelector } from 'utils';
import { paginationLocationQuery } from 'store/selectors'; import { paginationLocationQuery } from 'store/selectors';
import { defaultTableQuery } from './estimates.reducer';
const estimatesTableState = (state) => state.salesEstimates.tableState; const estimatesTableState = (state) => state.salesEstimates.tableState;
@@ -15,3 +17,8 @@ export const getEstimatesTableStateFactory = () =>
}; };
}, },
); );
export const isEstimatesTableStateChangedFactory = () =>
createDeepEqualSelector(estimatesTableState, (tableState) => {
return !isEqual(tableState, defaultTableQuery);
});

Some files were not shown because too many files have changed in this diff Show More