feat: accounts list as tree structure.

This commit is contained in:
Ahmed Bouhuolia
2020-11-24 11:24:11 +02:00
parent 7ec3c0f9d7
commit 4cdaacfa61
4 changed files with 112 additions and 18 deletions

View File

@@ -40,6 +40,8 @@ const CLASSES = {
DATATABLE_EMPTY_STATUS_DESC: 'datatable-empty-status__desc',
DATATABLE_EMPTY_STATUS_ACTIONS: 'datatable-empty-status__actions',
SELECT_LIST_FILL_POPOVER: 'select-list--fill-popover',
...Classes,
};

View File

@@ -4,6 +4,7 @@ import { Select } from '@blueprintjs/select';
import { FormattedMessage as T } from 'react-intl';
import classNames from 'classnames';
import { isEmpty } from 'lodash';
import { CLASSES } from 'common/classes';
export default function AccountsSelectList({
accounts,
@@ -12,6 +13,7 @@ export default function AccountsSelectList({
defaultSelectText = 'Select account',
onAccountSelected,
disabled = false,
popoverFill = false,
filterByRootTypes = [],
filterByTypes = [],
filterByNormal
@@ -61,7 +63,7 @@ export default function AccountsSelectList({
const accountItem = useCallback((item, { handleClick, modifiers, query }) => {
return (
<MenuItem
text={item.name}
text={item.htmlName || item.name}
label={item.code}
key={item.id}
onClick={handleClick}
@@ -100,11 +102,13 @@ export default function AccountsSelectList({
noResults={<MenuItem disabled={true} text={<T id={'no_accounts'} />} />}
itemRenderer={accountItem}
itemPredicate={filterAccountsPredicater}
popoverProps={{ minimal: true }}
popoverProps={{ minimal: true, usePortal: !popoverFill, inline: popoverFill }}
filterable={true}
onItemSelect={onAccountSelect}
disabled={disabled}
className={classNames('form-group--select-list')}
className={classNames('form-group--select-list', {
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
})}
>
<Button
disabled={disabled}

View File

@@ -1,12 +1,13 @@
import { createSelector } from 'reselect';
import { repeat } from 'lodash';
import { pickItemsFromIds, getItemById } from 'store/selectors';
import { flatToNestedArray } from 'utils';
import { flatToNestedArray, treeToList } from 'utils';
const accountsViewsSelector = (state) => state.accounts.views;
const accountsDataSelector = (state) => state.accounts.items;
const accountsCurrentViewSelector = (state) => state.accounts.currentViewId;
const accountIdPropSelector = (state, props) => props.accountId;
const accountsListSelector = (state) => state.accounts.list;
const accountsListSelector = (state) => state.accounts.listTree;
export const getAccountsItems = createSelector(
accountsViewsSelector,
@@ -30,8 +31,23 @@ export const getAccountsListFactory = () =>
createSelector(
accountsListSelector,
accountsDataSelector,
(accounts, accountsItems) => {
return pickItemsFromIds(accountsItems, accounts);
(accountsTree, accountsItems) => {
return treeToList(accountsTree, {
idFieldKey: 'id',
childrenFieldKey: 'children',
nodeMapper: (node, depth) => {
const account = accountsItems[node.id];
const spaceChar = String.fromCharCode(160);
return {
...account,
htmlName: (depth > 1)
? (`${repeat(spaceChar, (depth - 1) * 2)}${account.name}`) :
account.name,
depth,
};
}
});
},
);

View File

@@ -1,8 +1,6 @@
import moment from 'moment';
import _ from 'lodash';
import {
Intent,
} from '@blueprintjs/core';
import { Intent } from '@blueprintjs/core';
import Currency from 'js-money/lib/currency';
import PProgress from 'p-progress';
import accounting from 'accounting';
@@ -270,13 +268,12 @@ export const orderingLinesIndexes = (lines, attribute = 'index') => {
return lines.map((line, index) => ({ ...line, [attribute]: index + 1 }));
};
export const transformToObject = (arr, key) => {
return arr.reduce(function(acc, cur, i) {
return arr.reduce(function (acc, cur, i) {
acc[key ? cur[key] : i] = cur;
return acc;
}, {});
}
};
export const itemsStartWith = (items, char) => {
return items.filter((item) => item.indexOf(char) === 0);
@@ -284,15 +281,90 @@ export const itemsStartWith = (items, char) => {
export const saveInvoke = (func, ...rest) => {
return func && func(...rest);
}
};
export const transformToForm = (obj, emptyInitialValues) => {
return _.pickBy(
obj,
(val, key) => val !== null && Object.keys(emptyInitialValues).includes(key),
)
);
};
export function inputIntent({ error, touched }) {
return error && touched ? Intent.DANGER : '';
}
export function inputIntent({ error, touched }){
return error && touched ? Intent.DANGER : '';
}
export function listToTree(
inputList,
{
idFieldKey = 'id',
parentFieldKey = 'parent_account_id',
nodeMapper = (node) => ({ ...node }),
},
) {
var map = {},
node,
roots = [],
i;
const list = inputList.map((item) => nodeMapper(item));
for (i = 0; i < list.length; i += 1) {
map[list[i][idFieldKey]] = i;
list[i].children = [];
}
for (i = 0; i < list.length; i += 1) {
node = list[i];
if (node[parentFieldKey]) {
list[map[node[parentFieldKey]]].children.push(node);
} else {
roots.push(node);
}
}
return roots;
}
export function treeToList(
list,
{
idFieldKey = 'id',
childrenFieldKey = 'children',
nodeMapper = (node, depth) => node,
},
) {
let depth = 0;
const walker = (tree) => {
return tree.reduce(function (acc, o) {
depth += 1;
if (o[idFieldKey]) {
acc.push(nodeMapper(o, depth));
}
if (o[childrenFieldKey]) {
acc = acc.concat(walker(o.children));
}
depth -= 1;
return acc;
}, []);
};
return walker(list);
}
export function defaultToTransform(
value,
defaultOrTransformedValue,
defaultValue,
) {
const _defaultValue =
typeof defaultValue === 'undefined'
? defaultOrTransformedValue
: defaultValue;
const _transfromedValue =
typeof defaultValue === 'undefined' ? value : defaultOrTransformedValue;
return value == null || value !== value || value === ''
? _defaultValue
: _transfromedValue;
}