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,122 @@
// @ts-nocheck
import React from 'react';
import {
Button,
NavbarGroup,
Classes,
NavbarDivider,
Alignment,
Switch,
} from '@blueprintjs/core';
import {
DashboardActionsBar,
Can,
Icon,
FormattedMessage as T,
} from '@/components';
import { useRefreshCashflowAccounts } from '@/hooks/query';
import { CashflowAction, AbilitySubject } from '@/constants/abilityOption';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import withCashflowAccountsTableActions from '../AccountTransactions/withCashflowAccountsTableActions';
import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils';
import { ACCOUNT_TYPE } from '@/constants';
import { DialogsName } from '@/constants/dialogs';
import { compose } from '@/utils';
/**
* Cash Flow accounts actions bar.
*/
function CashFlowAccountsActionsBar({
// #withDialogActions
openDialog,
// #withCashflowAccountsTableActions
setCashflowAccountsTableState,
}) {
const { refresh } = useRefreshCashflowAccounts();
// Handle refresh button click.
const handleRefreshBtnClick = () => {
refresh();
};
// Handle add bank account.
const handleAddBankAccount = () => {
openDialog(DialogsName.AccountForm, {
action: AccountDialogAction.NewDefinedType,
accountType: ACCOUNT_TYPE.CASH,
});
};
// Handle add cash account.
const handleAddCashAccount = () => {
openDialog(DialogsName.AccountForm, {
action: AccountDialogAction.NewDefinedType,
accountType: ACCOUNT_TYPE.BANK,
});
};
// Handle inactive switch changing.
const handleInactiveSwitchChange = (event) => {
const checked = event.target.checked;
setCashflowAccountsTableState({ inactiveMode: checked });
};
return (
<DashboardActionsBar>
<NavbarGroup>
<Can I={CashflowAction.Create} a={AbilitySubject.Cashflow}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon={'plus-24'} iconSize={20} />}
text={<T id={'cash_flow.label.add_cash_account'} />}
onClick={handleAddBankAccount}
/>
<Button
className={Classes.MINIMAL}
icon={<Icon icon={'plus-24'} iconSize={20} />}
text={<T id={'cash_flow.label.add_bank_account'} />}
onClick={handleAddCashAccount}
/>
<NavbarDivider />
</Can>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="print-16" iconSize={16} />}
text={<T id={'print'} />}
/>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="file-export-16" iconSize={16} />}
text={<T id={'export'} />}
/>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="file-import-16" iconSize={16} />}
text={<T id={'import'} />}
/>
<NavbarDivider />
<Can I={CashflowAction.Edit} a={AbilitySubject.Cashflow}>
<Switch
labelElement={<T id={'inactive'} />}
defaultChecked={false}
onChange={handleInactiveSwitchChange}
/>
</Can>
</NavbarGroup>
<NavbarGroup align={Alignment.RIGHT}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="refresh-16" iconSize={14} />}
onClick={handleRefreshBtnClick}
/>
</NavbarGroup>
</DashboardActionsBar>
);
}
export default compose(
withDialogActions,
withCashflowAccountsTableActions,
)(CashFlowAccountsActionsBar);

View File

@@ -0,0 +1,67 @@
// @ts-nocheck
import React from 'react';
import { TABLES } from '@/constants/tables';
import {
DataTable,
TableFastCell,
TableSkeletonRows,
TableSkeletonHeader,
} from '@/components';
import withSettings from '@/containers/Settings/withSettings';
import { useMemorizedColumnsWidths } from '@/hooks';
import { useCashFlowAccountsContext } from './CashFlowAccountsProvider';
import { useCashFlowAccountsTableColumns } from './components';
import { compose } from '@/utils';
/**
* Cash flow accounts data table.
*/
function CashFlowAccountsDataTable({
// #withSettings
cashflowTableSize,
}) {
// Retrieve list context.
const {
cashflowAccounts,
isCashFlowAccountsFetching,
isCashFlowAccountsLoading,
} = useCashFlowAccountsContext();
// Retrieve table columns.
const columns = useCashFlowAccountsTableColumns();
// Local storage memorizing columns widths.
const [initialColumnsWidths, , handleColumnResizing] =
useMemorizedColumnsWidths(TABLES.CASHFLOW_ACCOUNTS);
return (
<DataTable
noInitialFetch={true}
columns={columns}
data={cashflowAccounts}
selectionColumn={false}
sticky={true}
loading={isCashFlowAccountsLoading}
headerLoading={isCashFlowAccountsLoading}
progressBarLoading={isCashFlowAccountsFetching}
expandColumnSpace={1}
expandToggleColumn={2}
selectionColumnWidth={45}
TableCellRenderer={TableFastCell}
TableLoadingRenderer={TableSkeletonRows}
TableHeaderSkeletonRenderer={TableSkeletonHeader}
initialColumnsWidths={initialColumnsWidths}
onColumnResizing={handleColumnResizing}
size={cashflowTableSize}
/>
);
}
export default compose(
withSettings(({ cashflowSettings }) => ({
cashflowTableSize: cashflowSettings?.tableSize,
})),
)(CashFlowAccountsDataTable);

View File

@@ -0,0 +1,50 @@
// @ts-nocheck
import React, { useEffect } from 'react';
import { compose } from 'lodash/fp';
import '@/style/pages/CashFlow/CashFlowAccounts/List.scss';
import { DashboardPageContent } from '@/components';
import { CashFlowAccountsProvider } from './CashFlowAccountsProvider';
import CashflowAccountsGrid from './CashflowAccountsGrid';
import CashFlowAccountsActionsBar from './CashFlowAccountsActionsBar';
import withCashflowAccounts from '@/containers/CashFlow/AccountTransactions/withCashflowAccounts';
import withCashflowAccountsTableActions from '@/containers/CashFlow/AccountTransactions/withCashflowAccountsTableActions';
/**
* Cashflow accounts list.
*/
function CashFlowAccountsList({
// #withCashflowAccounts
cashflowAccountsTableState,
// #withCashflowAccountsTableActions
resetCashflowAccountsTableState,
}) {
// Resets the cashflow accounts table state.
useEffect(
() => () => {
resetCashflowAccountsTableState();
},
[resetCashflowAccountsTableState],
);
return (
<CashFlowAccountsProvider tableState={cashflowAccountsTableState}>
<CashFlowAccountsActionsBar />
<DashboardPageContent>
<CashflowAccountsGrid />
</DashboardPageContent>
</CashFlowAccountsProvider>
);
}
export default compose(
withCashflowAccounts(({ cashflowAccountsTableState }) => ({
cashflowAccountsTableState,
})),
withCashflowAccountsTableActions,
)(CashFlowAccountsList);

View File

@@ -0,0 +1,40 @@
// @ts-nocheck
import React from 'react';
import { DashboardInsider } from '@/components/Dashboard';
import { useCashflowAccounts } from '@/hooks/query';
import { transformAccountsStateToQuery } from './utils';
const CashFlowAccountsContext = React.createContext();
/**
* Cash Flow data provider.
*/
function CashFlowAccountsProvider({ tableState, ...props }) {
const query = transformAccountsStateToQuery(tableState);
// Fetch cash flow list .
const {
data: cashflowAccounts,
isFetching: isCashFlowAccountsFetching,
isLoading: isCashFlowAccountsLoading,
} = useCashflowAccounts(query, { keepPreviousData: true });
// Provider payload.
const provider = {
cashflowAccounts,
isCashFlowAccountsFetching,
isCashFlowAccountsLoading,
};
return (
<DashboardInsider name={'cashflow-accounts'}>
<CashFlowAccountsContext.Provider value={provider} {...props} />
</DashboardInsider>
);
}
const useCashFlowAccountsContext = () =>
React.useContext(CashFlowAccountsContext);
export { CashFlowAccountsProvider, useCashFlowAccountsContext };

View File

@@ -0,0 +1,319 @@
// @ts-nocheck
import React, { useMemo } from 'react';
import intl from 'react-intl-universal';
import styled from 'styled-components';
import { isNull, isEmpty } from 'lodash';
import { compose, curry } from 'lodash/fp';
import { Link } from 'react-router-dom';
import { ContextMenu2 } from '@blueprintjs/popover2';
import { Menu, MenuItem, MenuDivider, Intent } from '@blueprintjs/core';
import {
AccountAction,
CashflowAction,
AbilitySubject,
} from '@/constants/abilityOption';
import { DialogsName } from '@/constants/dialogs';
import {
getAddMoneyInOptions,
getAddMoneyOutOptions,
} from '@/constants/cashflowOptions';
import { BankAccountsList, BankAccount, If, Icon, T, Can } from '@/components';
import { useCashFlowAccountsContext } from './CashFlowAccountsProvider';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import withAlertsActions from '@/containers/Alert/withAlertActions';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils';
import { safeCallback } from '@/utils';
const CASHFLOW_SKELETON_N = 4;
/**
* Cashflow accounts skeleton for loading state.
*/
function CashflowAccountsSkeleton() {
return [...Array(CASHFLOW_SKELETON_N)].map((e, i) => (
<BankAccount
title={'XXXXX'}
code={'XXXXX'}
balance={'XXXXXX'}
cash={'cash'}
loading={true}
/>
));
}
/**
* Cashflow bank account.
*/
function CashflowBankAccount({
// #withAlertsDialog
openAlert,
// #withDial
openDialog,
// #withDrawerActions
openDrawer,
account,
}) {
// Handle view detail account.
const handleViewClick = () => {
openDrawer('account-drawer', { accountId: account.id });
};
// Handle delete action account.
const handleDeleteClick = () => {
openAlert('account-delete', { accountId: account.id });
};
// Handle inactivate action account.
const handleInactivateClick = () => {
openAlert('account-inactivate', { accountId: account.id });
};
// Handle activate action account.
const handleActivateClick = () => {
openAlert('account-activate', { accountId: account.id });
};
// Handle edit account action.
const handleEditAccount = () => {
openDialog(DialogsName.AccountForm, {
action: AccountDialogAction.Edit,
id: account.id,
});
};
// Handle money in menu item actions.
const handleMoneyInClick = (transactionType) => {
openDialog('money-in', {
account_type: transactionType,
account_id: account.id,
});
};
// Handle money out menu item actions.
const handleMoneyOutClick = (transactionType) => {
openDialog('money-out', {
account_type: transactionType,
account_id: account.id,
});
};
return (
<ContextMenu2
content={
<CashflowAccountContextMenu
account={account}
onViewClick={handleViewClick}
onDeleteClick={handleDeleteClick}
onActivateClick={handleActivateClick}
onInactivateClick={handleInactivateClick}
onEditClick={handleEditAccount}
onMoneyInClick={handleMoneyInClick}
onMoneyOutClick={handleMoneyOutClick}
/>
}
>
<CashflowAccountAnchor
to={`/cashflow-accounts/${account.id}/transactions`}
>
<BankAccount
title={account.name}
code={account.code}
balance={!isNull(account.amount) ? account.formatted_amount : '-'}
type={account.account_type}
updatedBeforeText={getUpdatedBeforeText(account.createdAt)}
/>
</CashflowAccountAnchor>
</ContextMenu2>
);
}
const CashflowBankAccountEnhanced = compose(
withAlertsActions,
withDrawerActions,
withDialogActions,
)(CashflowBankAccount);
function getUpdatedBeforeText(createdAt) {
return '';
}
/**
* Cashflow accounts grid items.
*/
function CashflowAccountsGridItems({ accounts }) {
return accounts.map((account) => (
<CashflowBankAccountEnhanced account={account} />
));
}
/**
* Cashflow accounts empty state.
*/
function CashflowAccountsEmptyState() {
return (
<AccountsEmptyStateBase>
<AccountsEmptyStateTitle>
<T id={'cash_flow.accounts.no_results'} />
</AccountsEmptyStateTitle>
</AccountsEmptyStateBase>
);
}
/**
* Cashflow accounts grid.
*/
export default function CashflowAccountsGrid() {
// Retrieve list context.
const { cashflowAccounts, isCashFlowAccountsLoading } =
useCashFlowAccountsContext();
return (
<CashflowAccountsGridWrap>
<BankAccountsList>
{isCashFlowAccountsLoading ? (
<CashflowAccountsSkeleton />
) : isEmpty(cashflowAccounts) ? (
<CashflowAccountsEmptyState />
) : (
<CashflowAccountsGridItems accounts={cashflowAccounts} />
)}
</BankAccountsList>
</CashflowAccountsGridWrap>
);
}
/**
* Cashflow account money out context menu.
*/
function CashflowAccountMoneyInContextMenu({ onClick }) {
const handleItemClick = curry((transactionType, event) => {
onClick && onClick(transactionType, event);
});
// Retreives the add money in button options.
const addMoneyInOptions = useMemo(() => getAddMoneyInOptions(), []);
return addMoneyInOptions.map((option) => (
<MenuItem text={option.name} onClick={handleItemClick(option.value)} />
));
}
/**
* Cashflow account money in context menu.
*/
function CashflowAccountMoneyOutContextMenu({ onClick }) {
const handleItemClick = curry((transactionType, event) => {
onClick && onClick(transactionType, event);
});
// Retreives the add money out button options.
const addMoneyOutOptions = useMemo(() => getAddMoneyOutOptions(), []);
return addMoneyOutOptions.map((option) => (
<MenuItem text={option.name} onClick={handleItemClick(option.value)} />
));
}
/**
* Cashflow account context menu.
*/
function CashflowAccountContextMenu({
account,
onViewClick,
onEditClick,
onInactivateClick,
onActivateClick,
onDeleteClick,
onMoneyInClick,
onMoneyOutClick,
}) {
return (
<Menu>
<MenuItem
icon={<Icon icon="reader-18" />}
text={intl.get('view_details')}
onClick={safeCallback(onViewClick)}
/>
<Can I={CashflowAction.Create} a={AbilitySubject.Cashflow}>
<MenuDivider />
<MenuItem
text={<T id={'cash_flow_money_in'} />}
icon={<Icon icon={'arrow-downward'} iconSize={16} />}
>
<CashflowAccountMoneyInContextMenu onClick={onMoneyInClick} />
</MenuItem>
<MenuItem
text={<T id={'cash_flow_money_out'} />}
icon={<Icon icon={'arrow-upward'} iconSize={16} />}
>
<CashflowAccountMoneyOutContextMenu onClick={onMoneyOutClick} />
</MenuItem>
</Can>
<Can I={CashflowAction.Edit} a={AbilitySubject.Cashflow}>
<MenuDivider />
<MenuItem
icon={<Icon icon="pen-18" />}
text={intl.get('edit_account')}
onClick={safeCallback(onEditClick)}
/>
</Can>
<Can I={AccountAction.Edit} a={AbilitySubject.Account}>
<MenuDivider />
<If condition={account.active}>
<MenuItem
text={intl.get('inactivate_account')}
icon={<Icon icon="pause-16" iconSize={16} />}
onClick={safeCallback(onInactivateClick)}
/>
</If>
<If condition={!account.active}>
<MenuItem
text={intl.get('activate_account')}
icon={<Icon icon="play-16" iconSize={16} />}
onClick={safeCallback(onActivateClick)}
/>
</If>
</Can>
<Can I={CashflowAction.Delete} a={AbilitySubject.Cashflow}>
<MenuDivider />
<MenuItem
text={intl.get('delete_account')}
icon={<Icon icon="trash-16" iconSize={16} />}
intent={Intent.DANGER}
onClick={safeCallback(onDeleteClick)}
/>
</Can>
</Menu>
);
}
const CashflowAccountAnchor = styled(Link)`
&,
&:hover,
&:focus,
&:active {
color: inherit;
text-decoration: none;
}
`;
const CashflowAccountsGridWrap = styled.div`
margin: 30px;
`;
const CashflowBankAccountWrap = styled.div``;
const AccountsEmptyStateBase = styled.div`
flex: 1;
text-align: center;
margin: 2rem 0;
`;
const AccountsEmptyStateTitle = styled.h1`
font-size: 16px;
color: #626b76;
opacity: 0.8;
line-height: 1.6;
font-weight: 500;
`;

View File

@@ -0,0 +1,93 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import { Intent, Tag } from '@blueprintjs/core';
import { isBlank } from '@/utils';
import { Link } from 'react-router-dom';
/**
* Account code accessor.
*/
export const AccountCodeAccessor = (row) =>
!isBlank(row.code) ? (
<Tag minimal={true} round={true} intent={Intent.NONE}>
{row.code}
</Tag>
) : null;
/**
* Balance cell.
*/
export const BalanceCell = ({ cell }) => {
const account = cell.row.original;
return account.amount !== null ? (
<span>{account.formatted_amount}</span>
) : (
<span class="placeholder"></span>
);
};
/**
* Account cell.
*/
const AccountCell = ({ row }) => {
const account = row.original;
return (
<>
<div>X</div>
<Link to={`/account/${account.id}/transactions`}>{account.name}</Link>
</>
);
};
/**
* Retrieve Cash flow table columns.
*/
export function useCashFlowAccountsTableColumns() {
return React.useMemo(
() => [
{
id: 'name',
Header: intl.get('account_name'),
accessor: 'name',
Cell: AccountCell,
className: 'account_name',
width: 200,
textOverview: true,
},
{
id: 'code',
Header: intl.get('code'),
accessor: 'code',
className: 'code',
width: 80,
},
{
id: 'type',
Header: intl.get('type'),
accessor: 'account_type_label',
className: 'type',
width: 140,
textOverview: true,
},
{
id: 'currency',
Header: intl.get('currency'),
accessor: 'currency_code',
width: 75,
},
{
id: 'balance',
Header: intl.get('balance'),
accessor: 'amount',
className: 'balance',
Cell: BalanceCell,
width: 150,
align: 'right',
},
],
[],
);
}

View File

@@ -0,0 +1,12 @@
// @ts-nocheck
import { transformTableStateToQuery } from '@/utils';
/**
* Transformes the table state to list query.
*/
export const transformAccountsStateToQuery = (tableState) => {
return {
...transformTableStateToQuery(tableState),
inactive_mode: tableState.inactiveMode,
};
};