re-structure to monorepo.

This commit is contained in:
a.bouhuolia
2023-02-03 01:02:31 +02:00
parent 8242ec64ba
commit 7a0a13f9d5
10400 changed files with 46966 additions and 17223 deletions

View File

@@ -0,0 +1,167 @@
// @ts-nocheck
import React from 'react';
import {
Button,
NavbarGroup,
Classes,
NavbarDivider,
Intent,
Alignment,
} from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import {
Icon,
AdvancedFilterPopover,
DashboardFilterButton,
DashboardRowsHeightButton,
FormattedMessage as T,
Can,
If,
DashboardActionViewsList,
DashboardActionsBar
} from '@/components';
import { useRefreshJournals } from '@/hooks/query/manualJournals';
import { useManualJournalsContext } from './ManualJournalsListProvider';
import { ManualJournalAction, AbilitySubject } from '@/constants/abilityOption';
import withManualJournals from './withManualJournals';
import withManualJournalsActions from './withManualJournalsActions';
import withSettings from '@/containers/Settings/withSettings';
import withSettingsActions from '@/containers/Settings/withSettingsActions';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import { compose } from '@/utils';
/**
* Manual journal actions bar.
*/
function ManualJournalActionsBar({
// #withManualJournalsActions
setManualJournalsTableState,
// #withManualJournals
manualJournalsFilterConditions,
// #withSettings
manualJournalsTableSize,
// #withSettingsActions
addSetting,
}) {
// History context.
const history = useHistory();
// Manual journals context.
const { journalsViews, fields } = useManualJournalsContext();
// Manual journals refresh action.
const { refresh } = useRefreshJournals();
// Handle click a new manual journal.
const onClickNewManualJournal = () => {
history.push('/make-journal-entry');
};
// Handle delete button click.
const handleBulkDelete = () => {};
// Handle tab change.
const handleTabChange = (view) => {
setManualJournalsTableState({ viewSlug: view ? view.slig : null });
};
// Handle click a refresh Journals
const handleRefreshBtnClick = () => {
refresh();
};
// Handle table row size change.
const handleTableRowSizeChange = (size) => {
addSetting('manualJournals', 'tableSize', size);
};
return (
<DashboardActionsBar>
<NavbarGroup>
<DashboardActionViewsList
resourceName={'manual-journals'}
allMenuItem={true}
views={journalsViews}
onChange={handleTabChange}
/>
<NavbarDivider />
<Can I={ManualJournalAction.Create} a={AbilitySubject.ManualJournal}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="plus" />}
text={<T id={'journal_entry'} />}
onClick={onClickNewManualJournal}
/>
</Can>
<AdvancedFilterPopover
advancedFilterProps={{
conditions: manualJournalsFilterConditions,
defaultFieldKey: 'journal_number',
fields,
onFilterChange: (filterConditions) => {
setManualJournalsTableState({ filterRoles: filterConditions });
},
}}
>
<DashboardFilterButton
conditionsCount={manualJournalsFilterConditions.length}
/>
</AdvancedFilterPopover>
<If condition={false}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="trash-16" iconSize={16} />}
text={<T id={'delete'} />}
intent={Intent.DANGER}
onClick={handleBulkDelete}
/>
</If>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="print-16" iconSize={16} />}
text={<T id={'print'} />}
/>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="file-import-16" iconSize={16} />}
text={<T id={'import'} />}
/>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="file-export-16" iconSize={16} />}
text={<T id={'export'} />}
/>
<NavbarDivider />
<DashboardRowsHeightButton
initialValue={manualJournalsTableSize}
onChange={handleTableRowSizeChange}
/>
<NavbarDivider />
</NavbarGroup>
<NavbarGroup align={Alignment.RIGHT}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="refresh-16" iconSize={14} />}
onClick={handleRefreshBtnClick}
/>
</NavbarGroup>
</DashboardActionsBar>
);
}
export default compose(
withDialogActions,
withManualJournalsActions,
withSettingsActions,
withManualJournals(({ manualJournalsTableState }) => ({
manualJournalsFilterConditions: manualJournalsTableState.filterRoles,
})),
withSettings(({ manualJournalsSettings }) => ({
manualJournalsTableSize: manualJournalsSettings?.tableSize,
})),
)(ManualJournalActionsBar);

View File

@@ -0,0 +1,18 @@
// @ts-nocheck
import React from 'react';
const JournalDeleteAlert = React.lazy(
() => import('@/containers/Alerts/ManualJournals/JournalDeleteAlert'),
);
const JournalPublishAlert = React.lazy(
() => import('@/containers/Alerts/ManualJournals/JournalPublishAlert'),
);
/**
* Manual journals alerts.
*/
export default [
{ name: 'journal-delete', component: JournalDeleteAlert },
{ name: 'journal-publish', component: JournalPublishAlert },
];

View File

@@ -0,0 +1,158 @@
// @ts-nocheck
import React from 'react';
import { useHistory } from 'react-router-dom';
import {
DataTable,
DashboardContentTable,
TableSkeletonRows,
TableSkeletonHeader,
} from '@/components';
import { TABLES } from '@/constants/tables';
import ManualJournalsEmptyStatus from './ManualJournalsEmptyStatus';
import { ActionsMenu } from './components';
import withManualJournals from './withManualJournals';
import withManualJournalsActions from './withManualJournalsActions';
import withAlertsActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import withSettings from '@/containers/Settings/withSettings';
import { useManualJournalsContext } from './ManualJournalsListProvider';
import { useMemorizedColumnsWidths } from '@/hooks';
import { useManualJournalsColumns } from './utils';
import { compose } from '@/utils';
/**
* Manual journals data-table.
*/
function ManualJournalsDataTable({
// #withManualJournalsActions
setManualJournalsTableState,
// #withAlertsActions
openAlert,
// #withDrawerActions
openDrawer,
// #withManualJournals
manualJournalsTableState,
// #ownProps
onSelectedRowsChange,
// #withSettings
manualJournalsTableSize,
}) {
// Manual journals context.
const {
manualJournals,
pagination,
isManualJournalsLoading,
isManualJournalsFetching,
isEmptyStatus,
} = useManualJournalsContext();
const history = useHistory();
// Manual journals columns.
const columns = useManualJournalsColumns();
// Handles the journal publish action.
const handlePublishJournal = ({ id }) => {
openAlert('journal-publish', { manualJournalId: id });
};
// Handle the journal edit action.
const handleEditJournal = ({ id }) => {
history.push(`/manual-journals/${id}/edit`);
};
// Handle the journal delete action.
const handleDeleteJournal = ({ id }) => {
openAlert('journal-delete', { manualJournalId: id });
};
// Handle view detail journal.
const handleViewDetailJournal = ({ id }) => {
openDrawer('journal-drawer', {
manualJournalId: id,
});
};
// Handle cell click.
const handleCellClick = (cell, event) => {
openDrawer('journal-drawer', { manualJournalId: cell.row.original.id });
};
// Local storage memorizing columns widths.
const [initialColumnsWidths, , handleColumnResizing] =
useMemorizedColumnsWidths(TABLES.MANUAL_JOURNALS);
// Handle fetch data once the page index, size or sort by of the table change.
const handleFetchData = React.useCallback(
({ pageSize, pageIndex, sortBy }) => {
setManualJournalsTableState({
pageIndex,
pageSize,
sortBy,
});
},
[setManualJournalsTableState],
);
// Display manual journal empty status instead of the table.
if (isEmptyStatus) {
return <ManualJournalsEmptyStatus />;
}
return (
<DashboardContentTable>
<DataTable
noInitialFetch={true}
columns={columns}
data={manualJournals}
manualSortBy={true}
selectionColumn={true}
sticky={true}
loading={isManualJournalsLoading}
headerLoading={isManualJournalsLoading}
progressBarLoading={isManualJournalsFetching}
pagesCount={pagination.pagesCount}
pagination={true}
autoResetSortBy={false}
autoResetPage={false}
TableLoadingRenderer={TableSkeletonRows}
TableHeaderSkeletonRenderer={TableSkeletonHeader}
ContextMenu={ActionsMenu}
onFetchData={handleFetchData}
onCellClick={handleCellClick}
initialColumnsWidths={initialColumnsWidths}
onColumnResizing={handleColumnResizing}
size={manualJournalsTableSize}
payload={{
onDelete: handleDeleteJournal,
onPublish: handlePublishJournal,
onEdit: handleEditJournal,
onViewDetails: handleViewDetailJournal,
}}
/>
</DashboardContentTable>
);
}
export default compose(
withManualJournalsActions,
withManualJournals(({ manualJournalsTableState }) => ({
manualJournalsTableState,
})),
withAlertsActions,
withDrawerActions,
withSettings(({ manualJournalsSettings }) => ({
manualJournalsTableSize: manualJournalsSettings?.tableSize,
})),
)(ManualJournalsDataTable);

View File

@@ -0,0 +1,43 @@
// @ts-nocheck
import React from 'react';
import { Button, Intent } from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { Can, FormattedMessage as T, EmptyStatus } from '@/components';
import {
AbilitySubject,
ManualJournalAction,
} from '@/constants/abilityOption';
export default function ManualJournalsEmptyStatus() {
const history = useHistory();
return (
<EmptyStatus
title={<T id={'manual_journals.empty_status.title'} />}
description={
<p>
<T id={'manual_journals.empty_status.description'} />
</p>
}
action={
<>
<Can I={ManualJournalAction.Create} a={AbilitySubject.ManualJournal}>
<Button
intent={Intent.PRIMARY}
large={true}
onClick={() => {
history.push('/make-journal-entry');
}}
>
<T id={'make_journal'} />
</Button>
<Button intent={Intent.NONE} large={true}>
<T id={'learn_more'} />
</Button>
</Can>
</>
}
/>
);
}

View File

@@ -0,0 +1,46 @@
// @ts-nocheck
import React from 'react';
import '@/style/pages/ManualJournal/List.scss';
import { DashboardPageContent } from '@/components';
import { transformTableStateToQuery, compose } from '@/utils';
import { ManualJournalsListProvider } from './ManualJournalsListProvider';
import ManualJournalsViewTabs from './ManualJournalsViewTabs';
import ManualJournalsDataTable from './ManualJournalsDataTable';
import ManualJournalsActionsBar from './ManualJournalActionsBar';
import withManualJournals from './withManualJournals';
/**
* Manual journals table.
*/
function ManualJournalsTable({
// #withManualJournals
journalsTableState,
journalsTableStateChanged,
}) {
return (
<ManualJournalsListProvider
query={transformTableStateToQuery(journalsTableState)}
tableStateChanged={journalsTableStateChanged}
>
<ManualJournalsActionsBar />
<DashboardPageContent>
<ManualJournalsViewTabs />
<ManualJournalsDataTable />
</DashboardPageContent>
</ManualJournalsListProvider>
);
}
export default compose(
withManualJournals(
({ manualJournalsTableState, manualJournalTableStateChanged }) => ({
journalsTableState: manualJournalsTableState,
journalsTableStateChanged: manualJournalTableStateChanged,
}),
),
)(ManualJournalsTable);

View File

@@ -0,0 +1,61 @@
// @ts-nocheck
import React, { createContext } from 'react';
import { isEmpty } from 'lodash';
import { DashboardInsider } from '@/components';
import { useResourceViews, useResourceMeta, useJournals } from '@/hooks/query';
import { getFieldsFromResourceMeta } from '@/utils';
const ManualJournalsContext = createContext();
function ManualJournalsListProvider({ query, tableStateChanged, ...props }) {
// Fetches accounts resource views and fields.
const { data: journalsViews, isLoading: isViewsLoading } =
useResourceViews('manual_journals');
// Fetches the manual journals transactions with pagination meta.
const {
data: { manualJournals, pagination, filterMeta },
isLoading: isManualJournalsLoading,
isFetching: isManualJournalsFetching,
} = useJournals(query, { keepPreviousData: true });
// Fetch the accounts resource fields.
const {
data: resourceMeta,
isLoading: isResourceMetaLoading,
isFetching: isResourceMetaFetching,
} = useResourceMeta('manual_journals');
// Detarmines the datatable empty status.
const isEmptyStatus =
isEmpty(manualJournals) && !tableStateChanged && !isManualJournalsLoading;
// Global state.
const state = {
manualJournals,
pagination,
journalsViews,
resourceMeta,
fields: getFieldsFromResourceMeta(resourceMeta.fields),
isManualJournalsLoading,
isManualJournalsFetching,
isViewsLoading,
isEmptyStatus,
};
const isPageLoading = isViewsLoading || isResourceMetaLoading;
return (
<DashboardInsider loading={isPageLoading} name={'manual-journals'}>
<ManualJournalsContext.Provider value={state} {...props} />
</DashboardInsider>
);
}
const useManualJournalsContext = () => React.useContext(ManualJournalsContext);
export { ManualJournalsListProvider, useManualJournalsContext };

View File

@@ -0,0 +1,61 @@
// @ts-nocheck
import React from 'react';
import { Alignment, Navbar, NavbarGroup } from '@blueprintjs/core';
import { pick } from 'lodash';
import { DashboardViewsTabs } from '@/components';
import { useManualJournalsContext } from './ManualJournalsListProvider';
import withManualJournals from './withManualJournals';
import withManualJournalsActions from './withManualJournalsActions';
import withDashboardActions from '@/containers/Dashboard/withDashboardActions';
import { compose } from '@/utils';
/**
* Manual journal views tabs.
*/
function ManualJournalsViewTabs({
// #withManualJournalsActions
setManualJournalsTableState,
// #withManualJournals
journalsTableState
}) {
// Manual journals context.
const { journalsViews } = useManualJournalsContext();
const tabs = journalsViews.map((view) => ({
...pick(view, ['name', 'id']),
}));
const handleClickNewView = () => {};
// Handles the tab change.
const handleTabChange = (viewId) => {
setManualJournalsTableState({
customViewId: viewId || null,
});
};
return (
<Navbar className="navbar--dashboard-views">
<NavbarGroup align={Alignment.LEFT}>
<DashboardViewsTabs
resourceName={'manual-journals'}
currentViewId={journalsTableState.customViewId}
tabs={tabs}
onChange={handleTabChange}
onNewViewTabClick={handleClickNewView}
/>
</NavbarGroup>
</Navbar>
);
}
export default compose(
withManualJournalsActions,
withDashboardActions,
withManualJournals(({ manualJournalsTableState }) => ({
journalsTableState: manualJournalsTableState,
})),
)(ManualJournalsViewTabs);

View File

@@ -0,0 +1,193 @@
// @ts-nocheck
import React from 'react';
import {
Intent,
Classes,
Tooltip,
Position,
Tag,
Button,
MenuItem,
Menu,
MenuDivider,
Popover,
} from '@blueprintjs/core';
import intl from 'react-intl-universal';
import {
Can,
FormattedMessage as T,
Choose,
Money,
If,
Icon,
} from '@/components';
import {
ManualJournalAction,
AbilitySubject,
} from "@/constants/abilityOption";
import { safeCallback } from '@/utils';
/**
* Amount accessor.
*/
export const AmountAccessor = (r) => (
<Tooltip
content={
<AmountPopoverContent
journalEntries={r.entries}
currencyCode={r.currency_code}
/>
}
position={Position.RIGHT_TOP}
boundary={'viewport'}
>
{r.amount_formatted}
</Tooltip>
);
/**
* Amount popover content line.
*/
export const AmountPopoverContentLine = ({ journalEntry, currencyCode }) => {
const isCredit = !!journalEntry.credit;
const isDebit = !!journalEntry.debit;
const { account } = journalEntry;
return (
<Choose>
<Choose.When condition={isDebit}>
<div>
C. <Money amount={journalEntry.debit} currency={currencyCode} /> -{' '}
{account.name} <If condition={account.code}>({account.code})</If>
</div>
</Choose.When>
<Choose.When condition={isCredit}>
<div>
D. <Money amount={journalEntry.credit} currency={currencyCode} /> -{' '}
{account.name} <If condition={account.code}>({account.code})</If>
</div>
</Choose.When>
</Choose>
);
};
/**
* Amount popover content.
*/
export function AmountPopoverContent({ journalEntries, currencyCode }) {
const journalLinesProps = journalEntries.map((journalEntry) => ({
journalEntry,
accountId: journalEntry.account_id,
}));
return (
<div>
{journalLinesProps.map(({ journalEntry, accountId }) => (
<AmountPopoverContentLine
journalEntry={journalEntry}
accountId={accountId}
currencyCode={currencyCode}
/>
))}
</div>
);
}
/**
* Publish column accessor.
*/
export const StatusAccessor = (row) => {
return (
<Choose>
<Choose.When condition={!!row.is_published}>
<Tag minimal={true} round={true}>
<T id={'published'} />
</Tag>
</Choose.When>
<Choose.Otherwise>
<Tag minimal={true} intent={Intent.WARNING} round={true}>
<T id={'draft'} />
</Tag>
</Choose.Otherwise>
</Choose>
);
};
/**
* Note column accessor.
*/
export function NoteAccessor(row) {
return (
<If condition={row.description}>
<Tooltip
className={Classes.TOOLTIP_INDICATOR}
content={row.description}
position={Position.LEFT_TOP}
hoverOpenDelay={50}
>
<Icon icon={'file-alt'} iconSize={16} />
</Tooltip>
</If>
);
}
/**
* Table actions cell.
*/
export const ActionsCell = (props) => {
return (
<Popover
content={<ActionsMenu {...props} />}
position={Position.RIGHT_BOTTOM}
>
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
</Popover>
);
};
/**
* Actions menu of the table.
*/
export const ActionsMenu = ({
payload: { onPublish, onEdit, onDelete, onViewDetails },
row: { original },
}) => {
return (
<Menu>
<MenuItem
icon={<Icon icon="reader-18" />}
text={intl.get('view_details')}
onClick={safeCallback(onViewDetails, original)}
/>
<Can I={ManualJournalAction.Edit} a={AbilitySubject.ManualJournal}>
<MenuDivider />
<If condition={!original.is_published}>
<MenuItem
icon={<Icon icon="arrow-to-top" />}
text={intl.get('publish_journal')}
onClick={safeCallback(onPublish, original)}
/>
</If>
</Can>
<Can I={ManualJournalAction.Edit} a={AbilitySubject.ManualJournal}>
<MenuItem
icon={<Icon icon="pen-18" />}
text={intl.get('edit_journal')}
onClick={safeCallback(onEdit, original)}
/>
</Can>
<Can I={ManualJournalAction.Delete} a={AbilitySubject.ManualJournal}>
<MenuDivider />
<MenuItem
text={intl.get('delete_journal')}
icon={<Icon icon="trash-16" iconSize={16} />}
intent={Intent.DANGER}
onClick={safeCallback(onDelete, original)}
/>
</Can>
</Menu>
);
};

View File

@@ -0,0 +1,77 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import clsx from 'classnames';
import { CLASSES } from '@/constants/classes';
import { FormatDateCell } from '@/components';
import { NoteAccessor, StatusAccessor } from './components';
/**
* Retrieve the manual journals columns.
*/
export const useManualJournalsColumns = () => {
return React.useMemo(
() => [
{
id: 'date',
Header: intl.get('date'),
accessor: 'date',
Cell: FormatDateCell,
width: 115,
className: 'date',
clickable: true,
},
{
id: 'amount',
Header: intl.get('amount'),
accessor: 'formatted_amount',
width: 115,
clickable: true,
align: 'right',
className: clsx(CLASSES.FONT_BOLD),
},
{
id: 'journal_number',
Header: intl.get('journal_no'),
accessor: (row) => `${row.journal_number}`,
className: 'journal_number',
width: 100,
clickable: true,
textOverview: true,
},
{
id: 'journal_type',
Header: intl.get('journal_type'),
accessor: 'journal_type',
width: 110,
clickable: true,
textOverview: true,
},
{
id: 'status',
Header: intl.get('publish'),
accessor: (row) => StatusAccessor(row),
width: 95,
clickable: true,
},
{
id: 'note',
Header: intl.get('note'),
accessor: NoteAccessor,
disableSortBy: true,
width: 85,
clickable: true,
},
{
id: 'created_at',
Header: intl.get('created_at'),
accessor: 'created_at',
Cell: FormatDateCell,
width: 125,
clickable: true,
},
],
[],
);
};

View File

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

View File

@@ -0,0 +1,12 @@
// @ts-nocheck
import { connect } from 'react-redux';
import {
setManualJournalsTableState,
} from '@/store/manualJournals/manualJournals.actions';
const mapActionsToProps = (dispatch) => ({
setManualJournalsTableState: (queries) =>
dispatch(setManualJournalsTableState(queries)),
});
export default connect(null, mapActionsToProps);