mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 15:20:34 +00:00
WIP Make journal entries.
This commit is contained in:
47
client/src/components/AccountsSelectList.js
Normal file
47
client/src/components/AccountsSelectList.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
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 [selectedAccount, setSelectedAccount] = useState(null);
|
||||||
|
|
||||||
|
// Account item of select accounts field.
|
||||||
|
const accountItem = useCallback((item, { handleClick, modifiers, query }) => {
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
text={item.name}
|
||||||
|
label={item.code}
|
||||||
|
key={item.id}
|
||||||
|
onClick={handleClick} />
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onAccountSelect = useCallback((account) => {
|
||||||
|
setSelectedAccount({ ...account });
|
||||||
|
onAccountSelected && onAccountSelected(account);
|
||||||
|
}, [setSelectedAccount, onAccountSelected]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
items={accounts}
|
||||||
|
noResults={<MenuItem disabled={true} text='No results.' />}
|
||||||
|
itemRenderer={accountItem}
|
||||||
|
popoverProps={{ minimal: true }}
|
||||||
|
filterable={true}
|
||||||
|
onItemSelect={onAccountSelect}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
rightIcon='caret-down'
|
||||||
|
text={selectedAccount ? selectedAccount.name : 'Select account'}
|
||||||
|
/>
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}
|
||||||
62
client/src/components/CurrenciesSelectList.js
Normal file
62
client/src/components/CurrenciesSelectList.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import React, {useCallback} from 'react';
|
||||||
|
import {
|
||||||
|
FormGroup,
|
||||||
|
MenuItem,
|
||||||
|
Button,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
|
import {
|
||||||
|
Select
|
||||||
|
} from '@blueprintjs/select';
|
||||||
|
|
||||||
|
|
||||||
|
export default function CurrenciesSelectList(props) {
|
||||||
|
const {formGroupProps, selectProps, onItemSelect} = props;
|
||||||
|
const currencies = [{
|
||||||
|
name: 'USD US dollars', key: 'USD',
|
||||||
|
name: 'CAD Canadian dollars', key: 'CAD',
|
||||||
|
}];
|
||||||
|
|
||||||
|
// Handle currency item select.
|
||||||
|
const onCurrencySelect = useCallback((currency) => {
|
||||||
|
onItemSelect && onItemSelect(currency);
|
||||||
|
}, [onItemSelect]);
|
||||||
|
|
||||||
|
// Filters currencies list.
|
||||||
|
const filterCurrenciesPredicator = useCallback((query, currency, _index, exactMatch) => {
|
||||||
|
const normalizedTitle = currency.name.toLowerCase();
|
||||||
|
const normalizedQuery = query.toLowerCase();
|
||||||
|
return `${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Currency item of select currencies field.
|
||||||
|
const currencyItem = (item, { handleClick, modifiers, query }) => {
|
||||||
|
return (
|
||||||
|
<MenuItem text={item.name} label={item.code} key={item.id} onClick={handleClick} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormGroup
|
||||||
|
label={'Currency'}
|
||||||
|
className={'form-group--select-list form-group--currency'}
|
||||||
|
{...formGroupProps}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
items={currencies}
|
||||||
|
noResults={<MenuItem disabled={true} text='No results.' />}
|
||||||
|
itemRenderer={currencyItem}
|
||||||
|
itemPredicate={filterCurrenciesPredicator}
|
||||||
|
popoverProps={{ minimal: true }}
|
||||||
|
onItemSelect={onCurrencySelect}
|
||||||
|
{...selectProps}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
rightIcon='caret-down'
|
||||||
|
text={'USD US dollars'}
|
||||||
|
/>
|
||||||
|
</Select>
|
||||||
|
</FormGroup>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -44,6 +44,7 @@ export default function DataTable({
|
|||||||
virtualizedRows = false,
|
virtualizedRows = false,
|
||||||
fixedSizeHeight = 100,
|
fixedSizeHeight = 100,
|
||||||
fixedItemSize = 30,
|
fixedItemSize = 30,
|
||||||
|
payload,
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
getTableProps,
|
getTableProps,
|
||||||
@@ -78,6 +79,7 @@ export default function DataTable({
|
|||||||
getSubRows: row => row.children,
|
getSubRows: row => row.children,
|
||||||
manualSortBy,
|
manualSortBy,
|
||||||
expandSubRows,
|
expandSubRows,
|
||||||
|
payload,
|
||||||
},
|
},
|
||||||
useSortBy,
|
useSortBy,
|
||||||
useExpanded,
|
useExpanded,
|
||||||
@@ -122,7 +124,7 @@ export default function DataTable({
|
|||||||
// Renders table row.
|
// Renders table row.
|
||||||
const RenderRow = useCallback(({ style = {}, row }) => {
|
const RenderRow = useCallback(({ style = {}, row }) => {
|
||||||
prepareRow(row);
|
prepareRow(row);
|
||||||
const rowClasses = rowClassNames && rowClassNames(row.original);
|
const rowClasses = rowClassNames && rowClassNames(row);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div {...row.getRowProps({
|
<div {...row.getRowProps({
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import AccountsSelectList from 'components/AccountsSelectList';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import {
|
||||||
|
FormGroup,
|
||||||
|
Classes,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
|
|
||||||
|
// Account cell renderer.
|
||||||
|
const AccountCellRenderer = ({
|
||||||
|
row: { index, original },
|
||||||
|
payload: { accounts }
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<FormGroup
|
||||||
|
className={classNames('form-group--select-list',
|
||||||
|
'form-group--account', Classes.FILL)}
|
||||||
|
>
|
||||||
|
<AccountsSelectList
|
||||||
|
accounts={accounts}
|
||||||
|
onAccountSelected={() => {}} />
|
||||||
|
</FormGroup>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AccountCellRenderer;
|
||||||
31
client/src/components/DataTableCells/InputGroupCell.js
Normal file
31
client/src/components/DataTableCells/InputGroupCell.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import React, {useState, useEffect} from 'react';
|
||||||
|
import {
|
||||||
|
InputGroup
|
||||||
|
} from '@blueprintjs/core';
|
||||||
|
|
||||||
|
const InputEditableCell = ({
|
||||||
|
value: initialValue,
|
||||||
|
row: { index },
|
||||||
|
column: { id },
|
||||||
|
payload,
|
||||||
|
}) => {
|
||||||
|
const [value, setValue] = useState(initialValue)
|
||||||
|
|
||||||
|
const onChange = e => {
|
||||||
|
setValue(e.target.value)
|
||||||
|
}
|
||||||
|
const onBlur = () => {
|
||||||
|
payload.updateData(index, id, value)
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
setValue(initialValue)
|
||||||
|
}, [initialValue])
|
||||||
|
|
||||||
|
return (<InputGroup
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
fill={true} />);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InputEditableCell;
|
||||||
31
client/src/components/DataTableCells/MoneyFieldCell.js
Normal file
31
client/src/components/DataTableCells/MoneyFieldCell.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import React, { useCallback, useState } from 'react';
|
||||||
|
import MoneyInputGroup from 'components/MoneyInputGroup';
|
||||||
|
|
||||||
|
// Input form cell renderer.
|
||||||
|
const MoneyFieldCellRenderer = ({
|
||||||
|
row: { index },
|
||||||
|
column: { id },
|
||||||
|
cell: { value: initialValue },
|
||||||
|
payload
|
||||||
|
}) => {
|
||||||
|
const [value, setValue] = useState(initialValue);
|
||||||
|
|
||||||
|
const handleFieldChange = useCallback((e, value) => {
|
||||||
|
setValue(value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onBlur = () => {
|
||||||
|
payload.updateData(index, id, value)
|
||||||
|
};
|
||||||
|
|
||||||
|
return (<MoneyInputGroup
|
||||||
|
value={value}
|
||||||
|
prefix={'$'}
|
||||||
|
onChange={handleFieldChange}
|
||||||
|
inputGroupProps={{
|
||||||
|
fill: true,
|
||||||
|
onBlur,
|
||||||
|
}} />)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MoneyFieldCellRenderer;
|
||||||
9
client/src/components/DataTableCells/index.js
Normal file
9
client/src/components/DataTableCells/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import AccountsListFieldCell from './AccountsListFieldCell';
|
||||||
|
import MoneyFieldCell from './MoneyFieldCell';
|
||||||
|
import InputGroupCell from './InputGroupCell';
|
||||||
|
|
||||||
|
export {
|
||||||
|
AccountsListFieldCell,
|
||||||
|
MoneyFieldCell,
|
||||||
|
InputGroupCell,
|
||||||
|
}
|
||||||
@@ -1,13 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Currency from 'js-money/lib/currency';
|
import {formattedAmount} from 'utils';
|
||||||
import accounting from 'accounting';
|
|
||||||
|
|
||||||
function formattedAmount(cents, currency) {
|
|
||||||
const { symbol, decimal_digits: precision } = Currency[currency];
|
|
||||||
const amount = cents / Math.pow(10, precision);
|
|
||||||
|
|
||||||
return accounting.formatMoney(amount, { symbol, precision });
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Money({ amount, currency }) {
|
export default function Money({ amount, currency }) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
88
client/src/components/MoneyInputGroup.js
Normal file
88
client/src/components/MoneyInputGroup.js
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import React, {useState, useMemo, useEffect, useCallback} from 'react';
|
||||||
|
import {InputGroup} from '@blueprintjs/core';
|
||||||
|
|
||||||
|
const joinIntegerAndDecimal = (integer, decimal, separator) => {
|
||||||
|
let output = `${integer}`;
|
||||||
|
|
||||||
|
if (separator) {
|
||||||
|
output += separator;
|
||||||
|
output += decimal ? decimal : '';
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
};
|
||||||
|
|
||||||
|
const hasSeparator = (input, separator) => {
|
||||||
|
return -1 !== input.indexOf(separator);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addThousandSeparator = (integer, separator) => {
|
||||||
|
return integer.replace(/(\d)(?=(?:\d{3})+\b)/gm, `$1${separator}`)
|
||||||
|
};
|
||||||
|
|
||||||
|
const toString = (number) => `${number}`;
|
||||||
|
|
||||||
|
const onlyNumbers = (input) => {
|
||||||
|
return toString(input).replace(/\D+/g, '') || '0'
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatter = (value, options) => {
|
||||||
|
const input = toString(value);
|
||||||
|
const navigate = input.indexOf('-') >= 0 ? '-' : '';
|
||||||
|
const parts = toString(input).split(options.decimal);
|
||||||
|
const integer = parseInt(onlyNumbers(parts[0]), 10);
|
||||||
|
const decimal = parts[1] ? onlyNumbers(parts[1]) : null;
|
||||||
|
const integerThousand = addThousandSeparator(toString(integer), options.thousands);
|
||||||
|
const separator = hasSeparator(input, options.decimal)
|
||||||
|
? options.decimal : false;
|
||||||
|
|
||||||
|
return `${navigate}${options.prefix}${joinIntegerAndDecimal(integerThousand, decimal, separator)}${options.suffix}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const unformatter = (input, options) => {
|
||||||
|
const navigate = input.indexOf('-') >= 0 ? '-' : '';
|
||||||
|
const parts = toString(input).split(options.decimal);
|
||||||
|
const integer = parseInt(onlyNumbers(parts[0]), 10);
|
||||||
|
const decimal = parts[1] ? onlyNumbers(parts[1]) : null;
|
||||||
|
const separator = hasSeparator(input, options.decimal)
|
||||||
|
? options.decimal : false;
|
||||||
|
|
||||||
|
return `${navigate}${joinIntegerAndDecimal(integer, decimal, separator)}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default function MoneyFieldGroup({
|
||||||
|
value,
|
||||||
|
prefix = '',
|
||||||
|
suffix = '',
|
||||||
|
thousands = ',',
|
||||||
|
decimal = '.',
|
||||||
|
precision = 2,
|
||||||
|
inputGroupProps,
|
||||||
|
onChange,
|
||||||
|
}) {
|
||||||
|
const [state, setState] = useState(value);
|
||||||
|
|
||||||
|
const options = useMemo(() => ({
|
||||||
|
prefix, suffix, thousands, decimal, precision,
|
||||||
|
}), []);
|
||||||
|
|
||||||
|
const handleChange = useCallback((event) => {
|
||||||
|
const formatted = formatter(event.target.value, options);
|
||||||
|
const value = unformatter(event.target.value, options);
|
||||||
|
|
||||||
|
setState(formatted);
|
||||||
|
onChange && onChange(event, value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const formatted = formatter(value, options);
|
||||||
|
setState(formatted)
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InputGroup
|
||||||
|
value={state}
|
||||||
|
onChange={handleChange}
|
||||||
|
{...inputGroupProps} />
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -8,30 +8,9 @@ import { FormattedList } from 'react-intl';
|
|||||||
export default function MakeJournalEntriesFooter({
|
export default function MakeJournalEntriesFooter({
|
||||||
formik,
|
formik,
|
||||||
}) {
|
}) {
|
||||||
const creditSum = useMemo(() => {
|
|
||||||
return formik.values.entries.reduce((sum, entry) => {
|
|
||||||
return entry.credit + sum;
|
|
||||||
}, 0);
|
|
||||||
}, [formik.values.entries]);
|
|
||||||
|
|
||||||
const debitSum = useMemo(() => {
|
|
||||||
return formik.values.entries.reduce((sum, entry) => {
|
|
||||||
return entry.debit + sum;
|
|
||||||
}, 0);
|
|
||||||
}, [formik.values.entries]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td><strong>Total</strong></td>
|
|
||||||
<td>{ creditSum }</td>
|
|
||||||
<td>{ debitSum }</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="form__floating-footer">
|
<div class="form__floating-footer">
|
||||||
<Button
|
<Button
|
||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
@@ -42,9 +21,21 @@ export default function MakeJournalEntriesFooter({
|
|||||||
<Button
|
<Button
|
||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
type="submit"
|
type="submit"
|
||||||
className={'ml2'}>
|
className={'ml1'}>
|
||||||
Save & New
|
Save & New
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
className={'button-secondary ml1'}>
|
||||||
|
Save as Draft
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
className={'button-secondary ml1'}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -76,13 +76,14 @@ function MakeJournalEntriesForm({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(formik.errors);
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={formik.handleSubmit}>
|
<div class="make-journal-entries">
|
||||||
<MakeJournalEntriesHeader formik={formik} />
|
<form onSubmit={formik.handleSubmit}>
|
||||||
<MakeJournalEntriesTable formik={formik} />
|
<MakeJournalEntriesHeader formik={formik} />
|
||||||
<MakeJournalEntriesFooter formik={formik} />
|
<MakeJournalEntriesTable formik={formik} defaultRow={defaultEntry} />
|
||||||
</form>
|
<MakeJournalEntriesFooter formik={formik} />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, {useMemo, useCallback} from 'react';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import {
|
import {
|
||||||
InputGroup,
|
InputGroup,
|
||||||
@@ -12,6 +12,9 @@ import {useIntl} from 'react-intl';
|
|||||||
import {Row, Col} from 'react-grid-system';
|
import {Row, Col} from 'react-grid-system';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {momentFormatter} from 'utils';
|
import {momentFormatter} from 'utils';
|
||||||
|
import Icon from 'components/Icon';
|
||||||
|
import CurrenciesSelectList from 'components/CurrenciesSelectList';
|
||||||
|
|
||||||
|
|
||||||
export default function MakeJournalEntriesHeader({
|
export default function MakeJournalEntriesHeader({
|
||||||
formik
|
formik
|
||||||
@@ -22,25 +25,29 @@ export default function MakeJournalEntriesHeader({
|
|||||||
const formatted = moment(date).format('YYYY-MM-DD');
|
const formatted = moment(date).format('YYYY-MM-DD');
|
||||||
formik.setFieldValue('date', formatted);
|
formik.setFieldValue('date', formatted);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const infoIcon = useMemo(() => (<Icon icon="info-circle" iconSize={12} />), []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="make-journal-entries__header">
|
<div class="make-journal-entries__header">
|
||||||
<Row>
|
<Row>
|
||||||
<Col sm={4}>
|
<Col sm={3}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={intl.formatMessage({'id': 'reference'})}
|
label={'Journal number'}
|
||||||
className={'form-group--reference'}
|
labelInfo={infoIcon}
|
||||||
intent={formik.errors.name && Intent.DANGER}
|
className={'form-group--journal-number'}
|
||||||
helperText={formik.errors.name && formik.errors.label}
|
intent={formik.errors.journal_number && Intent.DANGER}
|
||||||
|
helperText={formik.errors.journal_number && formik.errors.journal_number}
|
||||||
fill={true}>
|
fill={true}>
|
||||||
|
|
||||||
<InputGroup
|
<InputGroup
|
||||||
intent={formik.errors.name && Intent.DANGER}
|
intent={formik.errors.journal_number && Intent.DANGER}
|
||||||
fill={true}
|
fill={true}
|
||||||
{...formik.getFieldProps('reference')} />
|
{...formik.getFieldProps('journal_number')} />
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col sm={3}>
|
<Col sm={2}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={intl.formatMessage({'id': 'date'})}
|
label={intl.formatMessage({'id': 'date'})}
|
||||||
intent={formik.errors.date && Intent.DANGER}
|
intent={formik.errors.date && Intent.DANGER}
|
||||||
@@ -70,6 +77,28 @@ export default function MakeJournalEntriesHeader({
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
|
<Row>
|
||||||
|
<Col sm={3}>
|
||||||
|
<FormGroup
|
||||||
|
label={'Reference'}
|
||||||
|
labelInfo={infoIcon}
|
||||||
|
className={'form-group--reference'}
|
||||||
|
intent={formik.errors.reference && Intent.DANGER}
|
||||||
|
helperText={formik.errors.reference && formik.errors.reference}
|
||||||
|
fill={true}>
|
||||||
|
|
||||||
|
<InputGroup
|
||||||
|
intent={formik.errors.reference && Intent.DANGER}
|
||||||
|
fill={true}
|
||||||
|
{...formik.getFieldProps('reference')} />
|
||||||
|
</FormGroup>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col sm={4}>
|
||||||
|
<CurrenciesSelectList />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,55 +1,88 @@
|
|||||||
import React, {useState, useMemo} from 'react';
|
import React, {useState, useMemo, useCallback} from 'react';
|
||||||
import DataTable from 'components/DataTable';
|
import DataTable from 'components/DataTable';
|
||||||
import {
|
import {
|
||||||
FormGroup,
|
|
||||||
InputGroup,
|
|
||||||
MenuItem,
|
|
||||||
Button,
|
Button,
|
||||||
Intent,
|
Intent,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import {Select} from '@blueprintjs/select';
|
|
||||||
import Icon from 'components/Icon';
|
import Icon from 'components/Icon';
|
||||||
import AccountsConnect from 'connectors/Accounts.connector.js';
|
import AccountsConnect from 'connectors/Accounts.connector.js';
|
||||||
import {compose} from 'utils';
|
import {compose, formattedAmount} from 'utils';
|
||||||
|
import {
|
||||||
|
AccountsListFieldCell,
|
||||||
|
MoneyFieldCell,
|
||||||
|
InputGroupCell,
|
||||||
|
} from 'comp}onents/DataTableCells';
|
||||||
|
|
||||||
|
// Actions cell renderer.
|
||||||
|
const ActionsCellRenderer = ({
|
||||||
|
row: { index },
|
||||||
|
column: { id },
|
||||||
|
cell: { value: initialValue },
|
||||||
|
data,
|
||||||
|
payload,
|
||||||
|
}) => {
|
||||||
|
if (data.length <= (index + 2)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const onClickRemoveRole = () => {
|
||||||
|
payload.removeRow(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
icon={<Icon icon="times-circle" iconSize={14} />}
|
||||||
|
iconSize={14}
|
||||||
|
className="ml2"
|
||||||
|
minimal={true}
|
||||||
|
intent={Intent.DANGER}
|
||||||
|
onClick={onClickRemoveRole} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Total text cell renderer.
|
||||||
|
const TotalAccountCellRenderer = (chainedComponent) => (props) => {
|
||||||
|
if (props.data.length === (props.row.index + 2)) {
|
||||||
|
return (<span>{ 'Total USD' }</span>);
|
||||||
|
}
|
||||||
|
return chainedComponent(props);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Total credit/debit cell renderer.
|
||||||
|
const TotalCreditDebitCellRenderer = (chainedComponent, type) => (props) => {
|
||||||
|
if (props.data.length === (props.row.index + 2)) {
|
||||||
|
const total = props.data.reduce((total, entry) => {
|
||||||
|
const amount = parseInt(entry[type], 10);
|
||||||
|
const computed = amount ? total + amount : total;
|
||||||
|
|
||||||
|
return computed;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
return (<span>{ formattedAmount(total, 'USD') }</span>);
|
||||||
|
}
|
||||||
|
return chainedComponent(props);
|
||||||
|
};
|
||||||
|
|
||||||
|
const NoteCellRenderer = (chainedComponent) => (props) => {
|
||||||
|
if (props.data.length === (props.row.index + 2)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return chainedComponent(props);
|
||||||
|
};
|
||||||
|
|
||||||
function MakeJournalEntriesTable({
|
function MakeJournalEntriesTable({
|
||||||
formik,
|
formik,
|
||||||
accounts,
|
accounts,
|
||||||
|
onClickRemoveRow,
|
||||||
|
onClickAddNewRow,
|
||||||
|
defaultRow,
|
||||||
}) {
|
}) {
|
||||||
const [selectAccountsState, setSelectedAccount] = useState(false);
|
const [rows, setRow] = useState([
|
||||||
|
...formik.values.entries.map((e) => ({ ...e, rowType: 'editor'})),
|
||||||
// Account item of select accounts field.
|
|
||||||
const accountItem = (item, { handleClick, modifiers, query }) => {
|
|
||||||
return (<MenuItem text={item.name} label={item.code} key={item.id} onClick={handleClick} />)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Filters accounts options by account name or code.
|
|
||||||
const filterAccountsPredicater = (query, account, _index, exactMatch) => {
|
|
||||||
const normalizedTitle = account.name.toLowerCase();
|
|
||||||
const normalizedQuery = query.toLowerCase();
|
|
||||||
|
|
||||||
if (exactMatch) {
|
|
||||||
return normalizedTitle === normalizedQuery;
|
|
||||||
} else {
|
|
||||||
return `${account.code} ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle account field change.
|
|
||||||
const onChangeAccount = (index) => (account) => {
|
|
||||||
setSelectedAccount({
|
|
||||||
...selectAccountsState,
|
|
||||||
[index + 1]: account,
|
|
||||||
});
|
|
||||||
formik.setFieldValue(`entries[${index}].account_id`, account.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const [data, setData] = useState([
|
|
||||||
...formik.values.entries,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const updateData = (rowIndex, columnId, value) => {
|
// Handles update datatable data.
|
||||||
setData((old) =>
|
const handleUpdateData = useCallback((rowIndex, columnId, value) => {
|
||||||
|
setRow((old) =>
|
||||||
old.map((row, index) => {
|
old.map((row, index) => {
|
||||||
if (index === rowIndex) {
|
if (index === rowIndex) {
|
||||||
return {
|
return {
|
||||||
@@ -60,51 +93,18 @@ function MakeJournalEntriesTable({
|
|||||||
return row
|
return row
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}, []);
|
||||||
|
|
||||||
const CellInputGroupRenderer = ({
|
// Handles click remove datatable row.
|
||||||
row: { index },
|
const handleRemoveRow = useCallback((rowIndex) => {
|
||||||
column: { id },
|
const removeIndex = parseInt(rowIndex, 10);
|
||||||
cell: { value: initialValue },
|
setRow([
|
||||||
}) => {
|
...rows.filter((row, index) => index !== removeIndex),
|
||||||
const [state, setState] = useState(initialValue);
|
]);
|
||||||
|
onClickRemoveRow && onClickRemoveRow(removeIndex);
|
||||||
|
}, [rows, onClickRemoveRow]);
|
||||||
|
|
||||||
return (
|
// Memorized data table columns.
|
||||||
<InputGroup
|
|
||||||
fill={true}
|
|
||||||
value={state}
|
|
||||||
onChange={(event) => {
|
|
||||||
setState(event.target.value);
|
|
||||||
}}
|
|
||||||
onBlur={(event) => {
|
|
||||||
formik.setFieldValue(`entries[${index}].[${id}]`, event.target.value);
|
|
||||||
updateData(index, id, state);
|
|
||||||
}}
|
|
||||||
/>);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const ActionsCellRenderer = ({
|
|
||||||
row: { index },
|
|
||||||
column: { id },
|
|
||||||
cell: { value: initialValue },
|
|
||||||
}) => {
|
|
||||||
|
|
||||||
const onClickRemoveRole = () => {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
icon={<Icon icon="mines" />}
|
|
||||||
iconSize={14}
|
|
||||||
className="ml2"
|
|
||||||
minimal={true}
|
|
||||||
intent={Intent.DANGER}
|
|
||||||
onClick={onClickRemoveRole()} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const columns = useMemo(() => [
|
const columns = useMemo(() => [
|
||||||
{
|
{
|
||||||
Header: '#',
|
Header: '#',
|
||||||
@@ -112,89 +112,93 @@ function MakeJournalEntriesTable({
|
|||||||
Cell: ({ row: {index} }) => (
|
Cell: ({ row: {index} }) => (
|
||||||
<span>{ index + 1 }</span>
|
<span>{ index + 1 }</span>
|
||||||
),
|
),
|
||||||
className: "actions",
|
className: "index",
|
||||||
|
width: 40,
|
||||||
|
disableResizing: true,
|
||||||
|
disableSortBy: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: 'Account',
|
Header: 'Account',
|
||||||
accessor: 'account',
|
accessor: 'account',
|
||||||
Cell: ({ row: { index } }) => (
|
Cell: TotalAccountCellRenderer(AccountsListFieldCell),
|
||||||
<FormGroup
|
|
||||||
className="{'form-group--account'}"
|
|
||||||
inline={true}>
|
|
||||||
<Select
|
|
||||||
items={accounts}
|
|
||||||
noResults={<MenuItem disabled={true} text="No results." />}
|
|
||||||
itemRenderer={accountItem}
|
|
||||||
itemPredicate={filterAccountsPredicater}
|
|
||||||
popoverProps={{ minimal: true }}
|
|
||||||
onItemSelect={onChangeAccount(index)}>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
rightIcon="caret-down"
|
|
||||||
text={(selectAccountsState[(index + 1)])
|
|
||||||
? selectAccountsState[(index + 1)].name : "Select Account"}
|
|
||||||
/>
|
|
||||||
</Select>
|
|
||||||
</FormGroup>
|
|
||||||
),
|
|
||||||
className: "account",
|
className: "account",
|
||||||
|
disableSortBy: true,
|
||||||
|
disableResizing: true,
|
||||||
|
width: 250,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: 'Credit (USD)',
|
||||||
|
accessor: 'credit',
|
||||||
|
Cell: TotalCreditDebitCellRenderer(MoneyFieldCell, 'credit'),
|
||||||
|
className: "credit",
|
||||||
|
disableSortBy: true,
|
||||||
|
disableResizing: true,
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: 'Debit (USD)',
|
||||||
|
accessor: 'debit',
|
||||||
|
Cell: TotalCreditDebitCellRenderer(MoneyFieldCell, 'debit'),
|
||||||
|
className: "debit",
|
||||||
|
disableSortBy: true,
|
||||||
|
disableResizing: true,
|
||||||
|
width: 150,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: 'Note',
|
Header: 'Note',
|
||||||
accessor: 'note',
|
accessor: 'note',
|
||||||
Cell: CellInputGroupRenderer,
|
Cell: NoteCellRenderer(InputGroupCell),
|
||||||
|
disableSortBy: true,
|
||||||
className: "note",
|
className: "note",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Header: 'Credit',
|
|
||||||
accessor: 'credit',
|
|
||||||
Cell: CellInputGroupRenderer,
|
|
||||||
className: "credit",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: 'Debit',
|
|
||||||
accessor: 'debit',
|
|
||||||
Cell: CellInputGroupRenderer,
|
|
||||||
className: "debit",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Header: '',
|
Header: '',
|
||||||
accessor: 'action',
|
accessor: 'action',
|
||||||
Cell: ActionsCellRenderer,
|
Cell: ActionsCellRenderer,
|
||||||
className: "actions",
|
className: "actions",
|
||||||
|
disableSortBy: true,
|
||||||
|
disableResizing: true,
|
||||||
|
width: 45,
|
||||||
}
|
}
|
||||||
]);
|
], []);
|
||||||
|
|
||||||
const onClickNewRow = () => {
|
// Handles click new line.
|
||||||
setData([
|
const onClickNewRow = useCallback(() => {
|
||||||
...data,
|
setRow([
|
||||||
{
|
...rows,
|
||||||
credit: 0,
|
{ ...defaultRow, rowType: 'editor' },
|
||||||
debit: 0,
|
|
||||||
account_id: null,
|
|
||||||
note: '',
|
|
||||||
}
|
|
||||||
]);
|
]);
|
||||||
}
|
onClickAddNewRow && onClickAddNewRow();
|
||||||
|
}, [defaultRow, rows, onClickAddNewRow]);
|
||||||
|
|
||||||
|
const rowClassNames = useCallback((row) => ({
|
||||||
|
'row--total': rows.length === (row.index + 2),
|
||||||
|
}), [rows]);
|
||||||
return (
|
return (
|
||||||
<div class="make-journal-entries__table">
|
<div class="make-journal-entries__table">
|
||||||
<DataTable
|
<DataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={data} />
|
data={rows}
|
||||||
|
rowClassNames={rowClassNames}
|
||||||
|
payload={{
|
||||||
|
accounts,
|
||||||
|
updateData: handleUpdateData,
|
||||||
|
removeRow: handleRemoveRow,
|
||||||
|
}}/>
|
||||||
|
|
||||||
<div class="mt1">
|
<div class="mt1">
|
||||||
<Button
|
<Button
|
||||||
minimal={true}
|
small={true}
|
||||||
intent={Intent.PRIMARY}
|
className={'button--secondary button--new-line'}
|
||||||
onClick={onClickNewRow}>
|
onClick={onClickNewRow}>
|
||||||
+ New Entry
|
New lines
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
minimal={true}
|
small={true}
|
||||||
intent={Intent.PRIMARY}
|
className={'button--secondary button--clear-lines ml1'}
|
||||||
onClick={onClickNewRow}>
|
onClick={onClickNewRow}>
|
||||||
- Clear all entries
|
Clear all lines
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export default function BalanceSheetHeader({
|
|||||||
formik.setFieldValue('display_columns_by', item.by);
|
formik.setFieldValue('display_columns_by', item.by);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// handle submit filter submit button.
|
// Handle submit filter submit button.
|
||||||
const handleSubmitClick = useCallback(() => {
|
const handleSubmitClick = useCallback(() => {
|
||||||
formik.submitForm();
|
formik.submitForm();
|
||||||
}, [formik]);
|
}, [formik]);
|
||||||
|
|||||||
@@ -95,4 +95,8 @@ export default {
|
|||||||
path: ['M452.515 237l31.843-18.382c9.426-5.441 13.996-16.542 11.177-27.054-11.404-42.531-33.842-80.547-64.058-110.797-7.68-7.688-19.575-9.246-28.985-3.811l-31.785 18.358a196.276 196.276 0 0 0-32.899-19.02V39.541a24.016 24.016 0 0 0-17.842-23.206c-41.761-11.107-86.117-11.121-127.93-.001-10.519 2.798-17.844 12.321-17.844 23.206v36.753a196.276 196.276 0 0 0-32.899 19.02l-31.785-18.358c-9.41-5.435-21.305-3.877-28.985 3.811-30.216 30.25-52.654 68.265-64.058 110.797-2.819 10.512 1.751 21.613 11.177 27.054L59.485 237a197.715 197.715 0 0 0 0 37.999l-31.843 18.382c-9.426 5.441-13.996 16.542-11.177 27.054 11.404 42.531 33.842 80.547 64.058 110.797 7.68 7.688 19.575 9.246 28.985 3.811l31.785-18.358a196.202 196.202 0 0 0 32.899 19.019v36.753a24.016 24.016 0 0 0 17.842 23.206c41.761 11.107 86.117 11.122 127.93.001 10.519-2.798 17.844-12.321 17.844-23.206v-36.753a196.34 196.34 0 0 0 32.899-19.019l31.785 18.358c9.41 5.435 21.305 3.877 28.985-3.811 30.216-30.25 52.654-68.266 64.058-110.797 2.819-10.512-1.751-21.613-11.177-27.054L452.515 275c1.22-12.65 1.22-25.35 0-38zm-52.679 63.019l43.819 25.289a200.138 200.138 0 0 1-33.849 58.528l-43.829-25.309c-31.984 27.397-36.659 30.077-76.168 44.029v50.599a200.917 200.917 0 0 1-67.618 0v-50.599c-39.504-13.95-44.196-16.642-76.168-44.029l-43.829 25.309a200.15 200.15 0 0 1-33.849-58.528l43.819-25.289c-7.63-41.299-7.634-46.719 0-88.038l-43.819-25.289c7.85-21.229 19.31-41.049 33.849-58.529l43.829 25.309c31.984-27.397 36.66-30.078 76.168-44.029V58.845a200.917 200.917 0 0 1 67.618 0v50.599c39.504 13.95 44.196 16.642 76.168 44.029l43.829-25.309a200.143 200.143 0 0 1 33.849 58.529l-43.819 25.289c7.631 41.3 7.634 46.718 0 88.037zM256 160c-52.935 0-96 43.065-96 96s43.065 96 96 96 96-43.065 96-96-43.065-96-96-96zm0 144c-26.468 0-48-21.532-48-48 0-26.467 21.532-48 48-48s48 21.533 48 48c0 26.468-21.532 48-48 48'],
|
path: ['M452.515 237l31.843-18.382c9.426-5.441 13.996-16.542 11.177-27.054-11.404-42.531-33.842-80.547-64.058-110.797-7.68-7.688-19.575-9.246-28.985-3.811l-31.785 18.358a196.276 196.276 0 0 0-32.899-19.02V39.541a24.016 24.016 0 0 0-17.842-23.206c-41.761-11.107-86.117-11.121-127.93-.001-10.519 2.798-17.844 12.321-17.844 23.206v36.753a196.276 196.276 0 0 0-32.899 19.02l-31.785-18.358c-9.41-5.435-21.305-3.877-28.985 3.811-30.216 30.25-52.654 68.265-64.058 110.797-2.819 10.512 1.751 21.613 11.177 27.054L59.485 237a197.715 197.715 0 0 0 0 37.999l-31.843 18.382c-9.426 5.441-13.996 16.542-11.177 27.054 11.404 42.531 33.842 80.547 64.058 110.797 7.68 7.688 19.575 9.246 28.985 3.811l31.785-18.358a196.202 196.202 0 0 0 32.899 19.019v36.753a24.016 24.016 0 0 0 17.842 23.206c41.761 11.107 86.117 11.122 127.93.001 10.519-2.798 17.844-12.321 17.844-23.206v-36.753a196.34 196.34 0 0 0 32.899-19.019l31.785 18.358c9.41 5.435 21.305 3.877 28.985-3.811 30.216-30.25 52.654-68.266 64.058-110.797 2.819-10.512-1.751-21.613-11.177-27.054L452.515 275c1.22-12.65 1.22-25.35 0-38zm-52.679 63.019l43.819 25.289a200.138 200.138 0 0 1-33.849 58.528l-43.829-25.309c-31.984 27.397-36.659 30.077-76.168 44.029v50.599a200.917 200.917 0 0 1-67.618 0v-50.599c-39.504-13.95-44.196-16.642-76.168-44.029l-43.829 25.309a200.15 200.15 0 0 1-33.849-58.528l43.819-25.289c-7.63-41.299-7.634-46.719 0-88.038l-43.819-25.289c7.85-21.229 19.31-41.049 33.849-58.529l43.829 25.309c31.984-27.397 36.66-30.078 76.168-44.029V58.845a200.917 200.917 0 0 1 67.618 0v50.599c39.504 13.95 44.196 16.642 76.168 44.029l43.829-25.309a200.143 200.143 0 0 1 33.849 58.529l-43.819 25.289c7.631 41.3 7.634 46.718 0 88.037zM256 160c-52.935 0-96 43.065-96 96s43.065 96 96 96 96-43.065 96-96-43.065-96-96-96zm0 144c-26.468 0-48-21.532-48-48 0-26.467 21.532-48 48-48s48 21.533 48 48c0 26.468-21.532 48-48 48'],
|
||||||
viewBox: '0 0 512 512',
|
viewBox: '0 0 512 512',
|
||||||
},
|
},
|
||||||
|
"times-circle": {
|
||||||
|
path: ['M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 464c-118.7 0-216-96.1-216-216 0-118.7 96.1-216 216-216 118.7 0 216 96.1 216 216 0 118.7-96.1 216-216 216zm94.8-285.3L281.5 256l69.3 69.3c4.7 4.7 4.7 12.3 0 17l-8.5 8.5c-4.7 4.7-12.3 4.7-17 0L256 281.5l-69.3 69.3c-4.7 4.7-12.3 4.7-17 0l-8.5-8.5c-4.7-4.7-4.7-12.3 0-17l69.3-69.3-69.3-69.3c-4.7-4.7-4.7-12.3 0-17l8.5-8.5c4.7-4.7 12.3-4.7 17 0l69.3 69.3 69.3-69.3c4.7-4.7 12.3-4.7 17 0l8.5 8.5c4.6 4.7 4.6 12.3 0 17z'],
|
||||||
|
viewBox: '0 0 512 512',
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
|
|
||||||
:last-child {
|
&:last-child {
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,11 @@
|
|||||||
color: #555555;
|
color: #555555;
|
||||||
box-shadow: 0 0 0 transparent;
|
box-shadow: 0 0 0 transparent;
|
||||||
|
|
||||||
|
&.bp3-small{
|
||||||
|
font-size: 13px;
|
||||||
|
min-height: 29px;
|
||||||
|
}
|
||||||
|
|
||||||
.form-group--select-list &{
|
.form-group--select-list &{
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ label{
|
|||||||
}
|
}
|
||||||
|
|
||||||
.#{$ns}-input{
|
.#{$ns}-input{
|
||||||
box-shadow: 0 0 0;
|
box-shadow: 0 0 0 transparent;
|
||||||
border: 1px solid #ced4da;
|
border: 1px solid #ced4da;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
@@ -94,6 +94,10 @@ label{
|
|||||||
.#{$ns}-icon-caret-down{
|
.#{$ns}-icon-caret-down{
|
||||||
color: #8D8D8D;
|
color: #8D8D8D;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.bp3-fill{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,38 +2,147 @@
|
|||||||
.make-journal-entries{
|
.make-journal-entries{
|
||||||
|
|
||||||
&__header{
|
&__header{
|
||||||
padding: 25px 40px;
|
padding: 25px 27px 20px;
|
||||||
background: #fbfbfb;
|
background: #fbfbfb;
|
||||||
|
|
||||||
|
.bp3-form-group{
|
||||||
|
|
||||||
|
.bp3-label{
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__table{
|
&__table{
|
||||||
|
padding: 15px;
|
||||||
|
|
||||||
.bp3-form-group{
|
.bp3-form-group{
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
table{
|
.table{
|
||||||
border: 1px solid transparent;
|
border: 1px dotted rgb(195, 195, 195);
|
||||||
|
border-bottom: transparent;
|
||||||
|
border-left: transparent;
|
||||||
|
|
||||||
thead{
|
.th,
|
||||||
th.index{ width: 3%; }
|
.td{
|
||||||
th.account{ width: 22%; }
|
border-left: 1px dotted rgb(195, 195, 195);
|
||||||
th.note{ width: 40%; }
|
|
||||||
th.credit{ width: 17.5%; }
|
&.index{
|
||||||
th.debit{ width: 17.5%; }
|
|
||||||
|
span{
|
||||||
|
width: 100%;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
th,
|
.thead{
|
||||||
td{
|
.tr .th{
|
||||||
border-right: 1px dotted #999;
|
padding: 10px 10px;
|
||||||
|
background-color: #F2F5FA;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
th{
|
|
||||||
|
.tbody{
|
||||||
|
.tr .td{
|
||||||
|
padding: 7px;
|
||||||
|
border-bottom: 1px dotted rgb(195, 195, 195);
|
||||||
|
min-height: 46px;
|
||||||
|
|
||||||
|
&.index{
|
||||||
|
background-color: #F2F5FA;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
> span{
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tr{
|
||||||
|
.bp3-input,
|
||||||
|
.form-group--select-list .bp3-button{
|
||||||
|
border-color: #E5E5E5;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-of-type{
|
||||||
|
|
||||||
|
.td{
|
||||||
|
border-bottom: transparent;
|
||||||
|
|
||||||
|
.bp3-button,
|
||||||
|
.bp3-input-group{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.td.actions{
|
||||||
|
.bp3-button{
|
||||||
|
background-color: transparent;
|
||||||
|
color: #E68F8E;
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
color: #c23030;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.row--total{
|
||||||
|
|
||||||
|
.account.td,
|
||||||
|
.debit.td,
|
||||||
|
.credit.td{
|
||||||
|
> span{
|
||||||
|
padding-top: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.debit.td,
|
||||||
|
.credit.td{
|
||||||
|
> span{
|
||||||
|
font-weight: 600;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.th{
|
||||||
color: #444;
|
color: #444;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
border-bottom: 1px dotted #666;
|
border-bottom: 1px dotted #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
td{
|
.td{
|
||||||
border-bottom: 1px dotted #999;
|
border-bottom: 1px dotted #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.actions.td{
|
||||||
|
.bp3-button{
|
||||||
|
background: transparent;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bp3-button{
|
||||||
|
&.button--clear-lines{
|
||||||
|
background-color: #FCEFEF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.button--clear-lines,
|
||||||
|
.button--new-line{
|
||||||
|
padding-left: 14px;
|
||||||
|
padding-right: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user