WIP Financial statements.

This commit is contained in:
Ahmed Bouhuolia
2020-04-03 01:17:17 +02:00
parent cf5f56ae32
commit 4227f2f9a8
40 changed files with 1750 additions and 761 deletions

View File

@@ -0,0 +1,67 @@
import React, {useMemo, useCallback, useState} from 'react';
import {omit} from 'lodash';
import {
MenuItem,
Button
} from '@blueprintjs/core';
// import {Select} from '@blueprintjs/select';
import MultiSelect from 'components/MultiSelect';
export default function AccountsMultiSelect({
accounts,
onAccountSelected,
}) {
const [selectedAccounts, setSelectedAccounts] = useState({});
const isAccountSelect = useCallback((accountId) => {
return 'undefined' !== typeof selectedAccounts[accountId];
}, [selectedAccounts]);
// Account item of select accounts field.
const accountItem = useCallback((item, { handleClick, modifiers, query }) => {
return (
<MenuItem
icon={isAccountSelect(item.id) ? "tick" : "blank"}
text={item.name}
label={item.code}
key={item.id}
onClick={handleClick} />
);
}, [isAccountSelect]);
const countSelectedAccounts = useMemo(() =>
Object.values(selectedAccounts).length,
[selectedAccounts]);
const onAccountSelect = useCallback((account) => {
const selected = {
...(!isAccountSelect(account.id)) ? {
...selectedAccounts,
[account.id]: true,
} : {
...omit(selectedAccounts, [account.id])
}
};
setSelectedAccounts({ ...selected });
onAccountSelected && onAccountSelected(selected);
}, [setSelectedAccounts, selectedAccounts, isAccountSelect, onAccountSelected]);
return (
<MultiSelect
items={accounts}
noResults={<MenuItem disabled={true} text='No results.' />}
itemRenderer={accountItem}
popoverProps={{ minimal: true }}
filterable={true}
onItemSelect={onAccountSelect}
>
<Button
rightIcon='caret-down'
text={countSelectedAccounts === 0 ?
'All accounts' :
`(${countSelectedAccounts}) Selected accounts`
}
/>
</MultiSelect>
);
}

View File

@@ -34,7 +34,8 @@ export default function DataTable({
onSelectedRowsChange,
manualSortBy = 'false',
selectionColumn = false,
className
className,
noResults = 'This report does not contain any data.'
}) {
const {
getTableProps,
@@ -144,7 +145,8 @@ export default function DataTable({
</div>
<div {...getTableBodyProps()} className="tbody">
{page.map((row, i) => {
prepareRow(row)
prepareRow(row);
return (
<div {...row.getRowProps()} className="tr">
{row.cells.map((cell) => {
@@ -154,6 +156,12 @@ export default function DataTable({
})}
</div>)
})}
{ (page.length === 0) && (
<div className={'tr no-results'}>
<div class="td">{ noResults }</div>
</div>
)}
</div>
</div>
</div>

View File

@@ -20,7 +20,7 @@ export default function FinancialSheet({
<LoadingIndicator loading={loading}>
<h1 class="financial-sheet__title">{ companyTitle }</h1>
<h6 class="financial-sheet__sheet-type">{ sheetType }</h6>
<div class="financial-sheet__date">As of { formattedDate }</div>
<div class="financial-sheet__date">From { formattedDate } | To { formattedDate }</div>
<div class="financial-sheet__table">
{ children }

View File

@@ -0,0 +1,177 @@
/*
* Copyright 2017 Palantir Technologies, Inc. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import classNames from "classnames";
import * as React from "react";
import {
Classes,
DISPLAYNAME_PREFIX,
Popover,
Position,
TagInput,
Utils,
} from "@blueprintjs/core";
import {
QueryList,
} from '@blueprintjs/select';
// export interface IMultiSelectProps<T> extends IListItemsProps<T> {
// /**
// * Whether the component should take up the full width of its container.
// * This overrides `popoverProps.fill` and `tagInputProps.fill`.
// */
// fill?: boolean;
// /**
// * Whether the popover opens on key down or when `TagInput` is focused.
// * @default false
// */
// openOnKeyDown?: boolean;
// /**
// * Input placeholder text. Shorthand for `tagInputProps.placeholder`.
// * @default "Search..."
// */
// placeholder?: string;
// /** Props to spread to `Popover`. Note that `content` cannot be changed. */
// popoverProps?: Partial<IPopoverProps> & object;
// /** Controlled selected values. */
// selectedItems?: T[];
// /** Props to spread to `TagInput`. Use `query` and `onQueryChange` to control the input. */
// tagInputProps?: Partial<ITagInputProps> & object;
// /** Custom renderer to transform an item into tag content. */
// tagRenderer: (item: T) => React.ReactNode;
// }
// export interface IMultiSelectState {
// isOpen: boolean;
// }
export default class MultiSelect extends React.Component {
static get displayName() {
return `${DISPLAYNAME_PREFIX}.MultiSelect`;
}
static get defaultProps() {
return {
fill: false,
placeholder: "Search...",
};
};
constructor(props) {
super(props);
this.state = { isOpen: (this.props.popoverProps && this.props.popoverProps.isOpen) || false };
this.input = null;
this.queryList = null;
this.listRef = React.createRef();
this.refHandlers = {
queryList: (ref) => {
this.queryList = ref;
},
};
}
render() {
// omit props specific to this component, spread the rest.
const { openOnKeyDown, popoverProps, tagInputProps, ...restProps } = this.props;
return (
<QueryList
{...restProps}
onItemSelect={this.handleItemSelect.bind(this)}
onQueryChange={this.handleQueryChange.bind(this)}
ref={this.refHandlers.queryList}
renderer={this.renderQueryList.bind(this)}
/>
);
}
renderQueryList(listProps) {
const { fill, tagInputProps = {}, popoverProps = {} } = this.props;
const { handleKeyDown, handleKeyUp } = listProps;
if (fill) {
popoverProps.fill = true;
tagInputProps.fill = true;
}
// add our own inputProps.className so that we can reference it in event handlers
const { inputProps = {} } = tagInputProps;
inputProps.className = classNames(inputProps.className, Classes.MULTISELECT_TAG_INPUT_INPUT);
return (
<Popover
autoFocus={false}
canEscapeKeyClose={true}
enforceFocus={false}
isOpen={this.state.isOpen}
position={Position.BOTTOM_LEFT}
{...popoverProps}
className={classNames(listProps.className, popoverProps.className)}
onInteraction={this.handlePopoverInteraction.bind(this)}
popoverClassName={classNames(Classes.MULTISELECT_POPOVER, popoverProps.popoverClassName)}
onOpened={this.handlePopoverOpened.bind(this)}
>
<div
onKeyDown={this.state.isOpen ? handleKeyDown : this.handleTargetKeyDown}
onKeyUp={this.state.isOpen ? handleKeyUp : undefined}
>
{this.props.children}
</div>
<div onKeyDown={handleKeyDown} onKeyUp={handleKeyUp} ref={this.listRef}>
{listProps.itemList}
</div>
</Popover>
);
};
handleItemSelect(item, evt) {
if (this.input != null) {
this.input.focus();
}
Utils.safeInvoke(this.props.onItemSelect, item, evt);
};
handleQueryChange(query, evt) {
this.setState({ isOpen: query.length > 0 || !this.props.openOnKeyDown });
Utils.safeInvoke(this.props.onQueryChange, query, evt);
};
handlePopoverInteraction = (isOpen, e) => {
if (e && this.listRef.current && this.listRef.current.contains(e.target)) {
this.setState({ isOpen: true })
} else {
this.setState({ isOpen });
}
Utils.safeInvokeMember(this.props.popoverProps, "onInteraction", isOpen);
}
handlePopoverOpened(node) {
if (this.queryList != null) {
// scroll active item into view after popover transition completes and all dimensions are stable.
this.queryList.scrollActiveItemIntoView();
}
Utils.safeInvokeMember(this.props.popoverProps, "onOpened", node);
};
}

View File

@@ -0,0 +1,17 @@
import React, {useState, useMemo, useCallback} from 'react';
import {Button} from '@blueprintjs/core';
import {Select} from '@blueprintjs/select';
export default function SelectList(props) {
const {buttonLabel, ...rest} = props;
return (
<Select {...rest}>
<Button
rightIcon="caret-down"
fill={true}>
{ buttonLabel }
</Button>
</Select>
)
}