feat: manual journal drawer.

This commit is contained in:
elforjani3
2021-04-27 16:06:26 +02:00
parent 5b62410afa
commit 571d9eb2fd
10 changed files with 346 additions and 1 deletions

View File

@@ -10,6 +10,7 @@ import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
import withManualJournals from './withManualJournals';
import withManualJournalsActions from './withManualJournalsActions';
import withAlertsActions from 'containers/Alert/withAlertActions';
import withDrawerActions from 'containers/Drawer/withDrawerActions';
import { useManualJournalsContext } from './ManualJournalsListProvider';
import { useManualJournalsColumns } from './utils';
@@ -27,6 +28,9 @@ function ManualJournalsDataTable({
// #withAlertsActions
openAlert,
// #withDrawerActions
openDrawer,
// #withManualJournals
manualJournalsTableState,
@@ -62,6 +66,14 @@ function ManualJournalsDataTable({
openAlert('journal-delete', { manualJournalId: id });
};
// Handle view detail journal.
const handleViewDetailJournal = ({ id, journal_number }) => {
openDrawer('journal-drawer', {
manualJournalId: id,
title: `Manual Journal ${journal_number}`,
});
};
// Handle fetch data once the page index, size or sort by of the table change.
const handleFetchData = React.useCallback(
({ pageSize, pageIndex, sortBy }) => {
@@ -104,6 +116,7 @@ function ManualJournalsDataTable({
onDelete: handleDeleteJournal,
onPublish: handlePublishJournal,
onEdit: handleEditJournal,
onViewDetails: handleViewDetailJournal,
}}
/>
);
@@ -115,4 +128,5 @@ export default compose(
manualJournalsTableState,
})),
withAlertsActions,
withDrawerActions,
)(ManualJournalsDataTable);

View File

@@ -148,7 +148,7 @@ export const ActionsCell = (props) => {
* Actions menu of the table.
*/
export const ActionsMenu = ({
payload: { onPublish, onEdit, onDelete },
payload: { onPublish, onEdit, onDelete, onViewDetails },
row: { original },
}) => {
return (
@@ -156,6 +156,7 @@ export const ActionsMenu = ({
<MenuItem
icon={<Icon icon="reader-18" />}
text={formatMessage({ id: 'view_details' })}
onClick={safeCallback(onViewDetails, original)}
/>
<MenuDivider />
<If condition={!original.is_published}>

View File

@@ -0,0 +1,69 @@
import React from 'react';
import { useHistory } from 'react-router-dom';
import Icon from 'components/Icon';
import { Button, Classes, NavbarGroup, Intent } from '@blueprintjs/core';
import { FormattedMessage as T } from 'react-intl';
import { safeCallback } from 'utils';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import withAlertsActions from 'containers/Alert/withAlertActions';
import withDrawerActions from 'containers/Drawer/withDrawerActions';
import { compose } from 'utils';
/**
* Manual journal action bar.
*/
function ManualJournalDrawerActionBar({
// #ownProps
manualJournal,
// #withAlertsDialog
openAlert,
// #withDrawerActions
closeDrawer,
}) {
const history = useHistory();
// Handle edit manual journal action.
const onEditManualJournal = () => {
if (manualJournal) {
history.push(`/manual-journals/${manualJournal.id}/edit`);
closeDrawer('journal-drawer');
}
};
// Handle manual journal delete action.
const onDeleteManualJournal = () => {
if (manualJournal) {
openAlert('journal-delete', { manualJournalId: manualJournal.id });
closeDrawer('journal-drawer');
}
};
return (
<DashboardActionsBar>
<NavbarGroup>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="pen-18" />}
text={<T id={'edit_journal'} />}
onClick={safeCallback(onEditManualJournal)}
/>
<Button
className={Classes.MINIMAL}
icon={<Icon style={{ color: 'red' }} icon="trash-18" iconSize={18} />}
text={<T id={'delete'} />}
onClick={safeCallback(onDeleteManualJournal)}
/>
</NavbarGroup>
</DashboardActionsBar>
);
}
export default compose(
withAlertsActions,
withDrawerActions,
)(ManualJournalDrawerActionBar);

View File

@@ -0,0 +1,17 @@
import React from 'react';
import { ManualJournalDrawerProvider } from './ManualJournalDrawerProvider';
import ManualJournalDrawerDetails from './ManualJournalDrawerDetails';
/**
* Manual Journal drawer content.
*/
export default function ManualJournalDrawerContent({
// #ownProp
manualJournalId,
}) {
return (
<ManualJournalDrawerProvider manualJournalId={manualJournalId}>
<ManualJournalDrawerDetails />
</ManualJournalDrawerProvider>
);
}

View File

@@ -0,0 +1,27 @@
import React from 'react';
import ManualJournalDrawerActionBar from './ManualJournalDrawerActionBar';
import ManualJournalDrawerHeader from './ManualJournalDrawerHeader';
import ManualJournalDrawerTable from './ManualJournalDrawerTable';
import ManualJournalDrawerFooter from './ManualJournalDrawerFooter';
import { useManualJournalDrawerContext } from 'containers/Drawers/ManualJournalDrawer/ManualJournalDrawerProvider';
import 'style/components/Drawer/ViewDetails.scss';
/**
* Manual journal view details.
*/
export default function ManualJournalDrawerDetails() {
const { manualJournal } = useManualJournalDrawerContext();
return (
<div className={'journal-drawer'}>
<ManualJournalDrawerActionBar manualJournal={manualJournal} />
<div className="journal-drawer__content">
<ManualJournalDrawerHeader manualJournal={manualJournal} />
<ManualJournalDrawerTable manualJournal={manualJournal} />
<ManualJournalDrawerFooter manualJournal={manualJournal} />
</div>
</div>
);
}

View File

@@ -0,0 +1,20 @@
import React from 'react';
export default function ManualJournalDrawerFooter({
manualJournal: { amount_formatted },
}) {
return (
<div className="journal-drawer__content--footer">
<div className="wrapper">
<div>
<span>Sub Total</span>
<p>{amount_formatted}</p>
</div>
<div>
<span>Total</span>
<p>{amount_formatted}</p>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,48 @@
import React from 'react';
import { FormattedMessage as T } from 'react-intl';
/**
* Manual journal details header.
*/
export default function ManualJournalDrawerHeader({
manualJournal: {
amount_formatted,
journal_type,
journal_number,
reference,
currency_code,
},
}) {
return (
<div className={'journal-drawer__content--header'}>
<div>
<T id={'total'} />
<p className="balance">{amount_formatted}</p>
</div>
<div>
<span>
<T id={'journal_type'} />
</span>
<p>{journal_type}</p>
</div>
<div>
<span>
<T id={'journal_no'} />
</span>
<p>{journal_number}</p>
</div>
<div>
<span>
<T id={'reference_no'} />
</span>
<p>{reference}</p>
</div>
<div>
<span>
<T id={'currency'} />
</span>
<p>{currency_code}</p>
</div>
</div>
);
}

View File

@@ -0,0 +1,33 @@
import React from 'react';
import { useJournal } from 'hooks/query';
import { DashboardInsider } from 'components';
const ManualJournalDrawerContext = React.createContext();
/**
* Manual journal drawer provider.
*/
function ManualJournalDrawerProvider({ manualJournalId, ...props }) {
// fetch the specific manual journal details.
const { data: manualJournal, isLoading: isJournalLoading } = useJournal(
manualJournalId,
{
enabled: !!manualJournalId,
},
);
// provider.
const provider = {
manualJournalId,
manualJournal,
};
return (
<DashboardInsider loading={isJournalLoading}>
<ManualJournalDrawerContext.Provider value={provider} {...props} />
</DashboardInsider>
);
}
const useManualJournalDrawerContext = () =>
React.useContext(ManualJournalDrawerContext);
export { ManualJournalDrawerProvider, useManualJournalDrawerContext };

View File

@@ -0,0 +1,79 @@
import React from 'react';
import { Classes, Tooltip, Position } from '@blueprintjs/core';
import { formatMessage } from 'services/intl';
import { DataTable, Money, If, Icon } from 'components';
import { isBlank } from 'utils';
/**
* 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.
*/
export default function ManualJournalDrawerTable({
manualJournal: { entries, description, currency_code },
}) {
const columns = React.useMemo(
() => [
{
Header: formatMessage({ id: 'account_name' }),
accessor: 'account.name',
width: 130,
},
{
Header: formatMessage({ id: 'contact' }),
accessor: 'contact.display_name',
width: 130,
},
{
Header: formatMessage({ id: 'credit' }),
accessor: ({ credit }) =>
!isBlank(credit) && credit !== 0 ? (
<Money amount={credit} currency={currency_code} />
) : null,
width: 80,
},
{
Header: formatMessage({ id: 'debit' }),
accessor: ({ debit }) =>
!isBlank(debit) && debit !== 0 ? (
<Money amount={debit} currency={currency_code} />
) : null,
width: 80,
},
{
Header: formatMessage({ id: 'note' }),
accessor: NoteAccessor,
width: 80,
},
],
[],
);
return (
<div className="journal-drawer__content--table">
<DataTable columns={columns} data={entries} />
<If condition={description}>
<p className={'desc'}>
<b>Description</b>: {description}
</p>
</If>
</div>
);
}

View File

@@ -0,0 +1,37 @@
import React, { lazy } from 'react';
import { Drawer, DrawerSuspense } from 'components';
import withDrawers from 'containers/Drawer/withDrawers';
import withDrawerActions from 'containers/Drawer/withDrawerActions';
import { compose } from 'utils';
const ManualJournalDrawerContent = lazy(() =>
import('./ManualJournalDrawerContent'),
);
/**
* Manual journal drawer.
*/
function ManualJournalDrawer({
name,
//#withDrawer
isOpen,
payload: { manualJournalId, title },
closeDrawer,
}) {
// Handle close drawer.
const handleDrawerClose = () => {
closeDrawer(name);
};
return (
<Drawer isOpen={isOpen} title={title} isClose={handleDrawerClose}>
<DrawerSuspense>
<ManualJournalDrawerContent manualJournalId={manualJournalId} />
</DrawerSuspense>
</Drawer>
);
}
export default compose(withDrawers(), withDrawerActions)(ManualJournalDrawer);