mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-22 07:40:32 +00:00
Merge branch 'master' of https://github.com/abouolia/Bigcapital
This commit is contained in:
@@ -15,7 +15,7 @@ export default function AccountsSuggestField({
|
|||||||
defaultSelectText = 'Select account',
|
defaultSelectText = 'Select account',
|
||||||
onAccountSelected,
|
onAccountSelected,
|
||||||
|
|
||||||
filterByRootTypes = [],
|
filterByParentTypes = [],
|
||||||
filterByTypes = [],
|
filterByTypes = [],
|
||||||
filterByNormal,
|
filterByNormal,
|
||||||
popoverFill = false,
|
popoverFill = false,
|
||||||
@@ -26,24 +26,23 @@ export default function AccountsSuggestField({
|
|||||||
const filteredAccounts = useMemo(() => {
|
const filteredAccounts = useMemo(() => {
|
||||||
let filteredAccounts = [...accounts];
|
let filteredAccounts = [...accounts];
|
||||||
|
|
||||||
if (!isEmpty(filterByRootTypes)) {
|
if (!isEmpty(filterByParentTypes)) {
|
||||||
filteredAccounts = filteredAccounts.filter(
|
filteredAccounts = filteredAccounts.filter(
|
||||||
(account) => filterByRootTypes.indexOf(account.type.root_type) !== -1,
|
(account) => filterByParentTypes.indexOf(account.account_parent_type) !== -1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!isEmpty(filterByTypes)) {
|
if (!isEmpty(filterByTypes)) {
|
||||||
filteredAccounts = filteredAccounts.filter(
|
filteredAccounts = filteredAccounts.filter(
|
||||||
(account) => filterByTypes.indexOf(account.type.key) !== -1,
|
(account) => filterByTypes.indexOf(account.account_type) !== -1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!isEmpty(filterByNormal)) {
|
if (!isEmpty(filterByNormal)) {
|
||||||
filteredAccounts = filteredAccounts.filter(
|
filteredAccounts = filteredAccounts.filter(
|
||||||
(account) =>
|
(account) => filterByTypes.indexOf(account.account_normal) === filterByNormal,
|
||||||
filterByTypes.indexOf(account.type.normal) === filterByNormal,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return filteredAccounts;
|
return filteredAccounts;
|
||||||
}, [accounts, filterByRootTypes, filterByTypes, filterByNormal]);
|
}, [accounts, filterByParentTypes, filterByTypes, filterByNormal]);
|
||||||
|
|
||||||
// Find initial account object to set it as default account in initial render.
|
// Find initial account object to set it as default account in initial render.
|
||||||
const initialAccount = useMemo(
|
const initialAccount = useMemo(
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useRef, useCallback, useMemo } from 'react';
|
||||||
import AccountsSuggestField from 'components/AccountsSuggestField';
|
|
||||||
// import AccountsSelectList from 'components/AccountsSelectList';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { useCellAutoFocus } from 'hooks';
|
||||||
|
|
||||||
|
import AccountsSuggestField from 'components/AccountsSuggestField';
|
||||||
|
|
||||||
|
// import AccountsSelectList from 'components/AccountsSelectList';
|
||||||
import { FormGroup, Classes, Intent } from '@blueprintjs/core';
|
import { FormGroup, Classes, Intent } from '@blueprintjs/core';
|
||||||
|
|
||||||
// Account cell renderer.
|
// Account cell renderer.
|
||||||
const AccountCellRenderer = ({
|
export default function AccountCellRenderer({
|
||||||
column: {
|
column: {
|
||||||
id,
|
id,
|
||||||
accountsDataProp,
|
accountsDataProp,
|
||||||
@@ -18,9 +21,14 @@ const AccountCellRenderer = ({
|
|||||||
accounts: defaultAccounts,
|
accounts: defaultAccounts,
|
||||||
updateData,
|
updateData,
|
||||||
errors,
|
errors,
|
||||||
|
autoFocus,
|
||||||
...restPayloadProps
|
...restPayloadProps
|
||||||
},
|
},
|
||||||
}) => {
|
}) {
|
||||||
|
const accountRef = useRef();
|
||||||
|
|
||||||
|
useCellAutoFocus(accountRef, autoFocus, id, index);
|
||||||
|
|
||||||
const handleAccountSelected = useCallback(
|
const handleAccountSelected = useCallback(
|
||||||
(account) => {
|
(account) => {
|
||||||
updateData(index, id, account.id);
|
updateData(index, id, account.id);
|
||||||
@@ -49,9 +57,12 @@ const AccountCellRenderer = ({
|
|||||||
selectedAccountId={initialValue}
|
selectedAccountId={initialValue}
|
||||||
filterByRootTypes={filterAccountsByRootType}
|
filterByRootTypes={filterAccountsByRootType}
|
||||||
filterByTypes={filterAccountsByTypes}
|
filterByTypes={filterAccountsByTypes}
|
||||||
|
inputProps={{
|
||||||
|
inputRef: (ref) => (accountRef.current = ref),
|
||||||
|
}}
|
||||||
|
openOnKeyDown={true}
|
||||||
|
blurOnSelectClose={false}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default AccountCellRenderer;
|
|
||||||
|
|||||||
@@ -1,15 +1,23 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback, useRef } from 'react';
|
||||||
// import ItemsListField from 'components/ItemsListField';
|
// import ItemsListField from 'components/ItemsListField';
|
||||||
import ItemsSuggestField from 'components/ItemsSuggestField';
|
import ItemsSuggestField from 'components/ItemsSuggestField';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { FormGroup, Classes, Intent } from '@blueprintjs/core';
|
import { FormGroup, Classes, Intent } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
import { useCellAutoFocus } from 'hooks';
|
||||||
|
|
||||||
export default function ItemsListCell({
|
export default function ItemsListCell({
|
||||||
column: { id, filterSellable, filterPurchasable },
|
column: { id, filterSellable, filterPurchasable },
|
||||||
row: { index },
|
row: { index },
|
||||||
cell: { value: initialValue },
|
cell: { value: initialValue },
|
||||||
payload: { items, updateData, errors },
|
payload: { items, updateData, errors, autoFocus },
|
||||||
}) {
|
}) {
|
||||||
|
const fieldRef = useRef();
|
||||||
|
|
||||||
|
// Auto-focus the items list input field.
|
||||||
|
useCellAutoFocus(fieldRef, autoFocus, id, index);
|
||||||
|
|
||||||
const handleItemSelected = useCallback(
|
const handleItemSelected = useCallback(
|
||||||
(item) => {
|
(item) => {
|
||||||
updateData(index, id, item.id);
|
updateData(index, id, item.id);
|
||||||
@@ -30,6 +38,11 @@ export default function ItemsListCell({
|
|||||||
selectedItemId={initialValue}
|
selectedItemId={initialValue}
|
||||||
sellable={filterSellable}
|
sellable={filterSellable}
|
||||||
purchasable={filterPurchasable}
|
purchasable={filterPurchasable}
|
||||||
|
inputProps={{
|
||||||
|
inputRef: (ref) => (fieldRef.current = ref),
|
||||||
|
}}
|
||||||
|
openOnKeyDown={true}
|
||||||
|
blurOnSelectClose={false}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default function TableCell({
|
|||||||
<div
|
<div
|
||||||
className={classNames({
|
className={classNames({
|
||||||
'text-overview': cell.column.textOverview,
|
'text-overview': cell.column.textOverview,
|
||||||
})}
|
}, 'cell-inner')}
|
||||||
style={{
|
style={{
|
||||||
'padding-left':
|
'padding-left':
|
||||||
isExpandColumn && expandable
|
isExpandColumn && expandable
|
||||||
|
|||||||
@@ -4,59 +4,66 @@ import { ScrollSyncPane } from 'react-scroll-sync';
|
|||||||
import { If } from 'components';
|
import { If } from 'components';
|
||||||
import TableContext from './TableContext';
|
import TableContext from './TableContext';
|
||||||
|
|
||||||
function TableHeaderGroup({ headerGroup }) {
|
function TableHeaderCell({ column, index }) {
|
||||||
const {
|
const {
|
||||||
table: { getToggleAllRowsExpandedProps, isAllRowsExpanded },
|
table: { getToggleAllRowsExpandedProps, isAllRowsExpanded },
|
||||||
props: { expandable, expandToggleColumn },
|
props: { expandable, expandToggleColumn },
|
||||||
} = useContext(TableContext);
|
} = useContext(TableContext);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
{...column.getHeaderProps({
|
||||||
|
className: classNames(column.className || '', 'th'),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<If condition={expandable && index + 1 === expandToggleColumn}>
|
||||||
|
<span {...getToggleAllRowsExpandedProps()} className="expand-toggle">
|
||||||
|
<span
|
||||||
|
className={classNames({
|
||||||
|
'arrow-down': isAllRowsExpanded,
|
||||||
|
'arrow-right': !isAllRowsExpanded,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</If>
|
||||||
|
|
||||||
|
<div {...column.getSortByToggleProps({
|
||||||
|
className: classNames('cell-inner', {
|
||||||
|
'text-overview': column.textOverview,
|
||||||
|
})
|
||||||
|
})}>
|
||||||
|
{column.render('Header')}
|
||||||
|
|
||||||
|
<If condition={column.isSorted}>
|
||||||
|
<span
|
||||||
|
className={classNames(
|
||||||
|
{
|
||||||
|
'sort-icon--desc': column.isSortedDesc,
|
||||||
|
'sort-icon--asc': !column.isSortedDesc,
|
||||||
|
},
|
||||||
|
'sort-icon',
|
||||||
|
)}
|
||||||
|
></span>
|
||||||
|
</If>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{column.canResize && (
|
||||||
|
<div
|
||||||
|
{...column.getResizerProps()}
|
||||||
|
className={`resizer ${column.isResizing ? 'isResizing' : ''}`}
|
||||||
|
>
|
||||||
|
<div class="inner-resizer" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TableHeaderGroup({ headerGroup }) {
|
||||||
return (
|
return (
|
||||||
<div {...headerGroup.getHeaderGroupProps()} className="tr">
|
<div {...headerGroup.getHeaderGroupProps()} className="tr">
|
||||||
{headerGroup.headers.map((column, index) => (
|
{headerGroup.headers.map((column, index) => (
|
||||||
<div
|
<TableHeaderCell column={column} index={index} />
|
||||||
{...column.getHeaderProps({
|
|
||||||
className: classNames(column.className || '', 'th'),
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<If condition={expandable && index + 1 === expandToggleColumn}>
|
|
||||||
<span
|
|
||||||
{...getToggleAllRowsExpandedProps()}
|
|
||||||
className="expand-toggle"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className={classNames({
|
|
||||||
'arrow-down': isAllRowsExpanded,
|
|
||||||
'arrow-right': !isAllRowsExpanded,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</If>
|
|
||||||
|
|
||||||
<div {...column.getSortByToggleProps()}>
|
|
||||||
{column.render('Header')}
|
|
||||||
|
|
||||||
<If condition={column.isSorted}>
|
|
||||||
<span
|
|
||||||
className={classNames(
|
|
||||||
{
|
|
||||||
'sort-icon--desc': column.isSortedDesc,
|
|
||||||
'sort-icon--asc': !column.isSortedDesc,
|
|
||||||
},
|
|
||||||
'sort-icon',
|
|
||||||
)}
|
|
||||||
></span>
|
|
||||||
</If>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{column.canResize && (
|
|
||||||
<div
|
|
||||||
{...column.getResizerProps()}
|
|
||||||
className={`resizer ${column.isResizing ? 'isResizing' : ''}`}
|
|
||||||
>
|
|
||||||
<div class="inner-resizer" />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,11 +2,7 @@ import React, { useState, useMemo, useEffect, useCallback } from 'react';
|
|||||||
import { Button } from '@blueprintjs/core';
|
import { Button } from '@blueprintjs/core';
|
||||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
import { omit } from 'lodash';
|
import { omit } from 'lodash';
|
||||||
import classNames from 'classnames';
|
import { compose, saveInvoke } from 'utils';
|
||||||
|
|
||||||
import { CLASSES } from 'common/classes';
|
|
||||||
import DataTable from 'components/DataTable';
|
|
||||||
import { compose, transformUpdatedRows, saveInvoke } from 'utils';
|
|
||||||
import {
|
import {
|
||||||
AccountsListFieldCell,
|
AccountsListFieldCell,
|
||||||
MoneyFieldCell,
|
MoneyFieldCell,
|
||||||
@@ -21,9 +17,12 @@ import {
|
|||||||
NoteCellRenderer,
|
NoteCellRenderer,
|
||||||
} from './components';
|
} from './components';
|
||||||
import { DataTableEditable } from 'components';
|
import { DataTableEditable } from 'components';
|
||||||
|
|
||||||
import withAccounts from 'containers/Accounts/withAccounts';
|
import withAccounts from 'containers/Accounts/withAccounts';
|
||||||
import withCustomers from 'containers/Customers/withCustomers';
|
import withCustomers from 'containers/Customers/withCustomers';
|
||||||
|
|
||||||
|
import { updateDataReducer } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make journal entries table component.
|
* Make journal entries table component.
|
||||||
*/
|
*/
|
||||||
@@ -126,8 +125,9 @@ function MakeJournalEntriesTable({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Handles update datatable data.
|
// Handles update datatable data.
|
||||||
const handleUpdateData = (rowIndex, columnIdOrObj, value) => {
|
const handleUpdateData = (rowIndex, columnId, value) => {
|
||||||
const newRows = transformUpdatedRows(rows, rowIndex, columnIdOrObj, value);
|
const newRows = updateDataReducer(rows, rowIndex, columnId, value);
|
||||||
|
|
||||||
saveInvoke(
|
saveInvoke(
|
||||||
onChange,
|
onChange,
|
||||||
newRows
|
newRows
|
||||||
@@ -185,6 +185,7 @@ function MakeJournalEntriesTable({
|
|||||||
contact_type: 'customer',
|
contact_type: 'customer',
|
||||||
})),
|
})),
|
||||||
],
|
],
|
||||||
|
autoFocus: ['account_id', 0],
|
||||||
}}
|
}}
|
||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ export default function MakeJournalFloatingAction({
|
|||||||
<Button
|
<Button
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
type="submit"
|
|
||||||
onClick={handleSubmitPublishBtnClick}
|
onClick={handleSubmitPublishBtnClick}
|
||||||
text={<T id={'save_publish'} />}
|
text={<T id={'save_publish'} />}
|
||||||
/>
|
/>
|
||||||
@@ -123,7 +122,6 @@ export default function MakeJournalFloatingAction({
|
|||||||
<Button
|
<Button
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
className={'ml1'}
|
className={'ml1'}
|
||||||
type="submit"
|
|
||||||
onClick={handleSubmitDraftBtnClick}
|
onClick={handleSubmitDraftBtnClick}
|
||||||
text={<T id={'save_as_draft'} />}
|
text={<T id={'save_as_draft'} />}
|
||||||
/>
|
/>
|
||||||
@@ -156,7 +154,6 @@ export default function MakeJournalFloatingAction({
|
|||||||
<Button
|
<Button
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
type="submit"
|
|
||||||
onClick={handleSubmitPublishBtnClick}
|
onClick={handleSubmitPublishBtnClick}
|
||||||
text={<T id={'save'} />}
|
text={<T id={'save'} />}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Intent } from '@blueprintjs/core';
|
import { Intent } from '@blueprintjs/core';
|
||||||
|
import { get, sumBy, setWith, toSafeInteger } from 'lodash';
|
||||||
import { AppToaster } from 'components';
|
import { AppToaster } from 'components';
|
||||||
import { formatMessage } from 'services/intl';
|
import { formatMessage } from 'services/intl';
|
||||||
import { setWith } from 'lodash';
|
import { transformUpdatedRows } from 'utils';
|
||||||
|
|
||||||
const ERROR = {
|
const ERROR = {
|
||||||
JOURNAL_NUMBER_ALREADY_EXISTS: 'JOURNAL.NUMBER.ALREADY.EXISTS',
|
JOURNAL_NUMBER_ALREADY_EXISTS: 'JOURNAL.NUMBER.ALREADY.EXISTS',
|
||||||
@@ -15,6 +16,46 @@ const ERROR = {
|
|||||||
ENTRIES_SHOULD_ASSIGN_WITH_CONTACT: 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT',
|
ENTRIES_SHOULD_ASSIGN_WITH_CONTACT: 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function adjustmentEntries(entries) {
|
||||||
|
const credit = sumBy(entries, e => toSafeInteger(e.credit));
|
||||||
|
const debit = sumBy(entries, e => toSafeInteger(e.debit));
|
||||||
|
|
||||||
|
return {
|
||||||
|
debit: Math.max(credit - debit, 0),
|
||||||
|
credit: Math.max(debit - credit, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateDataReducer = (rows, rowIndex, columnId, value) => {
|
||||||
|
let newRows = transformUpdatedRows(rows, rowIndex, columnId, value);
|
||||||
|
|
||||||
|
const oldCredit = get(rows, `[${rowIndex}].credit`);
|
||||||
|
const oldDebit = get(rows, `[${rowIndex}].debit`);
|
||||||
|
|
||||||
|
if (columnId === 'account_id' && !oldCredit && !oldDebit) {
|
||||||
|
const adjustment = adjustmentEntries(rows);
|
||||||
|
|
||||||
|
if (adjustment.credit) {
|
||||||
|
newRows = transformUpdatedRows(
|
||||||
|
newRows,
|
||||||
|
rowIndex,
|
||||||
|
'credit',
|
||||||
|
adjustment.credit,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (adjustment.debit) {
|
||||||
|
newRows = transformUpdatedRows(
|
||||||
|
newRows,
|
||||||
|
rowIndex,
|
||||||
|
'debit',
|
||||||
|
adjustment.debit,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newRows;
|
||||||
|
};
|
||||||
|
|
||||||
// Transform API errors in toasts messages.
|
// Transform API errors in toasts messages.
|
||||||
export const transformErrors = (resErrors, { setErrors, errors }) => {
|
export const transformErrors = (resErrors, { setErrors, errors }) => {
|
||||||
const getError = (errorType) => resErrors.find((e) => e.type === errorType);
|
const getError = (errorType) => resErrors.find((e) => e.type === errorType);
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ function ItemsEntriesTable({
|
|||||||
errors: errors || [],
|
errors: errors || [],
|
||||||
updateData: handleUpdateData,
|
updateData: handleUpdateData,
|
||||||
removeRow: handleRemoveRow,
|
removeRow: handleRemoveRow,
|
||||||
|
autoFocus: ['item_id', 0],
|
||||||
}}
|
}}
|
||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -234,6 +234,7 @@ function ExpenseTable({
|
|||||||
errors: error,
|
errors: error,
|
||||||
updateData: handleUpdateData,
|
updateData: handleUpdateData,
|
||||||
removeRow: handleRemoveRow,
|
removeRow: handleRemoveRow,
|
||||||
|
autoFocus: ['expense_account_id', 0],
|
||||||
}}
|
}}
|
||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {useRef, useEffect} from 'react';
|
import {useRef, useEffect, useMemo } from 'react';
|
||||||
import useAsync from './async';
|
import useAsync from './async';
|
||||||
import useAutofocus from './useAutofocus';
|
import useAutofocus from './useAutofocus';
|
||||||
|
|
||||||
@@ -35,7 +35,37 @@ export function useIsValuePassed(value, compatatorValue) {
|
|||||||
return cache.current.indexOf(compatatorValue) !== -1;
|
return cache.current.indexOf(compatatorValue) !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isCurrentFocus = (autoFocus, columnId, rowIndex) => {
|
||||||
|
let _columnId;
|
||||||
|
let _rowIndex;
|
||||||
|
|
||||||
|
if (Array.isArray(autoFocus)) {
|
||||||
|
_columnId = autoFocus[0];
|
||||||
|
_rowIndex = autoFocus[1] || 0;
|
||||||
|
}
|
||||||
|
_rowIndex = parseInt(_rowIndex, 10);
|
||||||
|
|
||||||
|
return columnId === _columnId && _rowIndex === rowIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useCellAutoFocus(ref, autoFocus, columnId, rowIndex) {
|
||||||
|
const focus = useMemo(() => isCurrentFocus(autoFocus, columnId, rowIndex), [
|
||||||
|
autoFocus,
|
||||||
|
columnId,
|
||||||
|
rowIndex,
|
||||||
|
]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (ref.current && focus) {
|
||||||
|
ref.current.focus();
|
||||||
|
}
|
||||||
|
}, [ref, focus]);
|
||||||
|
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
useAsync,
|
useAsync,
|
||||||
useAutofocus,
|
useAutofocus,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { useRef, useEffect } from 'react';
|
import { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
export default function useAutofocus() {
|
export default function useAutofocus(focus = true) {
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ref.current) {
|
if (ref.current && focus) {
|
||||||
ref.current.focus();
|
ref.current.focus();
|
||||||
}
|
}
|
||||||
}, [ref]);
|
}, [ref, focus]);
|
||||||
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,10 @@
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|
||||||
.th {
|
.th {
|
||||||
padding: 0.6rem 0.5rem;
|
padding: 0.7rem 0.5rem;
|
||||||
background: #fafafa;
|
background: #f5f5f5;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #58667b;
|
color: #505e71;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
border-bottom: 1px solid rgb(224, 224, 224);
|
border-bottom: 1px solid rgb(224, 224, 224);
|
||||||
|
|
||||||
@@ -76,6 +76,10 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
|
|
||||||
|
.cell-inner{
|
||||||
|
flex: 1 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
}
|
}
|
||||||
@@ -102,7 +106,7 @@
|
|||||||
.inner-resizer {
|
.inner-resizer {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
border-left: 1px solid #ececec;
|
border-left: 1px solid #E6E6E6;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +144,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tr .td {
|
.tr .td {
|
||||||
border-bottom: 1px solid #e8e8e8;
|
border-bottom: 1px solid #e0e0e0;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: #101219;
|
color: #101219;
|
||||||
|
|
||||||
@@ -151,7 +155,6 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bp3-form-group {
|
.bp3-form-group {
|
||||||
@@ -168,7 +171,6 @@
|
|||||||
.tr:hover .td {
|
.tr:hover .td {
|
||||||
background: #f3f7fc;
|
background: #f3f7fc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tr.is-context-menu-active .td {
|
.tr.is-context-menu-active .td {
|
||||||
background: #f3fafc;
|
background: #f3fafc;
|
||||||
}
|
}
|
||||||
@@ -183,11 +185,9 @@
|
|||||||
&:focus {
|
&:focus {
|
||||||
background-color: #cfdcee;
|
background-color: #cfdcee;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
color: #425361;
|
color: #425361;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bp3-icon-more-h-16 {
|
.bp3-icon-more-h-16 {
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
@@ -264,12 +264,10 @@
|
|||||||
|
|
||||||
.thead {
|
.thead {
|
||||||
top: 0;
|
top: 0;
|
||||||
// box-shadow: 0px 3px 3px #ccc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tfoot {
|
.tfoot {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
// box-shadow: 0px -3px 3px #ccc;
|
|
||||||
}
|
}
|
||||||
.tbody {
|
.tbody {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
@import '../../Base.scss';
|
@import '../../Base.scss';
|
||||||
|
$dashboard-views-bar-height: 45px;
|
||||||
|
|
||||||
.dashboard {
|
.dashboard {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -412,10 +413,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tabs--dashboard-views {
|
.tabs--dashboard-views {
|
||||||
|
|
||||||
.#{$ns}-tab {
|
.#{$ns}-tab {
|
||||||
color: #5b606d;
|
color: #474d5e;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 50px;
|
line-height: $dashboard-views-bar-height;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
@@ -430,12 +432,12 @@
|
|||||||
|
|
||||||
.#{$ns}-tab-indicator-wrapper {
|
.#{$ns}-tab-indicator-wrapper {
|
||||||
.#{$ns}-tab-indicator {
|
.#{$ns}-tab-indicator {
|
||||||
height: 4px;
|
height: 3px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.button--new-view {
|
.button--new-view {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
height: 50px;
|
height: $dashboard-views-bar-height;
|
||||||
|
|
||||||
&,
|
&,
|
||||||
&:hover,
|
&:hover,
|
||||||
@@ -455,6 +457,11 @@
|
|||||||
.navbar--dashboard-views {
|
.navbar--dashboard-views {
|
||||||
box-shadow: 0 0 0;
|
box-shadow: 0 0 0;
|
||||||
border-bottom: 1px solid #d2dce2;
|
border-bottom: 1px solid #d2dce2;
|
||||||
|
height: $dashboard-views-bar-height;
|
||||||
|
|
||||||
|
.bp3-navbar-group{
|
||||||
|
height: $dashboard-views-bar-height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-omnibar {
|
.navbar-omnibar {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
.thead{
|
.thead{
|
||||||
.tr .td.customer_name ~ .td,
|
.tr .td.customer_name ~ .td,
|
||||||
.tr .th.customer_name ~ .th{
|
.tr .th.customer_name ~ .th{
|
||||||
justify-content: flex-end;
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tbody{
|
.tbody{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
.tbody{
|
.tbody{
|
||||||
.tr .td.account_name ~ .td,
|
.tr .td.account_name ~ .td,
|
||||||
.tr .th.account_name ~ .th{
|
.tr .th.account_name ~ .th{
|
||||||
justify-content: flex-end;
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tbody{
|
.tbody{
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
&.debit,
|
&.debit,
|
||||||
&.running_balance,
|
&.running_balance,
|
||||||
&.amount{
|
&.amount{
|
||||||
justify-content: flex-end;
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
.tr .th.credit,
|
.tr .th.credit,
|
||||||
.tr .td.debit,
|
.tr .td.debit,
|
||||||
.tr .th.debit{
|
.tr .th.debit{
|
||||||
justify-content: flex-end;
|
text-align: right;
|
||||||
}
|
}
|
||||||
.tbody{
|
.tbody{
|
||||||
.tr:not(.no-results) .td{
|
.tr:not(.no-results) .td{
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
.tbody{
|
.tbody{
|
||||||
.tr .td:not(:first-child),
|
.tr .td:not(:first-child),
|
||||||
.tr .th:not(:first-child) {
|
.tr .th:not(:first-child) {
|
||||||
justify-content: flex-end;
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tbody{
|
.tbody{
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
|
|
||||||
.#{$ns}-menu-item {
|
.#{$ns}-menu-item {
|
||||||
padding: 10px 18px;
|
padding: 8px 18px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
|||||||
@@ -48,7 +48,12 @@
|
|||||||
font-size: 13.5px;
|
font-size: 13.5px;
|
||||||
}
|
}
|
||||||
.bp3-progress-bar{
|
.bp3-progress-bar{
|
||||||
height: 6px;
|
height: 4px;
|
||||||
|
|
||||||
|
&,
|
||||||
|
.bp3-progress-meter{
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ $button-background-color-hover: #CFDCEE !default;
|
|||||||
$sidebar-background: #01194e;
|
$sidebar-background: #01194e;
|
||||||
$sidebar-text-color: #fff;
|
$sidebar-text-color: #fff;
|
||||||
$sidebar-width: 100%;
|
$sidebar-width: 100%;
|
||||||
$sidebar-menu-item-color: rgba(255, 255, 255, 0.9);
|
$sidebar-menu-item-color: rgb(255, 255, 255);
|
||||||
$sidebar-menu-item-color-active: rgb(255, 255, 255);
|
$sidebar-menu-item-color-active: rgb(255, 255, 255);
|
||||||
$sidebar-popover-submenu-bg: rgb(1, 20, 62);
|
$sidebar-popover-submenu-bg: rgb(1, 20, 62);
|
||||||
$sidebar-menu-label-color: rgba(255, 255, 255, 0.45);
|
$sidebar-menu-label-color: rgba(255, 255, 255, 0.45);
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
|
import Container from 'typedi';
|
||||||
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
|
|
||||||
exports.up = (knex) => {
|
exports.up = (knex) => {
|
||||||
// Inserts seed entries
|
const tenancyService = Container.get(TenancyService);
|
||||||
return knex('settings').insert([
|
const settings = tenancyService.settings(knex.userParams.tenantId);
|
||||||
{ group: 'manual_journals', key: 'next_number', value: 1 },
|
|
||||||
|
|
||||||
{ group: 'sales_invoices', key: 'next_number', value: 1},
|
settings.set({ group: 'manual_journals', key: 'next_number', value: 1 });
|
||||||
{ group: 'sales_invoices', key: 'number_prefix', value: 'INV' },
|
settings.set({ group: 'sales_invoices', key: 'next_number', value: 1 });
|
||||||
|
settings.set({ group: 'sales_invoices', key: 'number_prefix', value: 'INV' });
|
||||||
|
settings.set({ group: 'sales_receipts', key: 'next_number', value: 1 });
|
||||||
|
settings.set({ group: 'sales_receipts', key: 'number_prefix', value: 'REC' });
|
||||||
|
settings.set({ group: 'sales_estimates', key: 'next_number', value: 1 });
|
||||||
|
settings.set({ group: 'sales_estimates', key: 'number_prefix', value: 'EST' });
|
||||||
|
settings.set({ group: 'payment_receives', key: 'next_number', value: 1 });
|
||||||
|
|
||||||
{ group: 'sales_receipts', key: 'next_number', value: 1 },
|
return settings.save();
|
||||||
{ group: 'sales_receipts', key: 'number_prefix', value: 'REC' },
|
|
||||||
|
|
||||||
{ group: 'sales_estimates', key: 'next_number', value: 1 },
|
|
||||||
{ group: 'sales_estimates', key: 'number_prefix', value: 'EST' },
|
|
||||||
|
|
||||||
{ group: 'payment_receives', key: 'next_number', value: 1 },
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.down = (knex) => {
|
exports.down = (knex) => {};
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -201,4 +201,11 @@ export default class MetableStore implements IMetableStore{
|
|||||||
|
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the momerized metadata.
|
||||||
|
*/
|
||||||
|
resetMetadata() {
|
||||||
|
this.metadata = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export default class MetableDBStore extends MetableStore implements IMetableStor
|
|||||||
this.saveInserted(this.metadata),
|
this.saveInserted(this.metadata),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the updated metadata.
|
* Saves the updated metadata.
|
||||||
* @param {IMetadata[]} metadata -
|
* @param {IMetadata[]} metadata -
|
||||||
@@ -155,6 +155,8 @@ export default class MetableDBStore extends MetableStore implements IMetableStor
|
|||||||
const metadata = await this.repository.all();
|
const metadata = await this.repository.all();
|
||||||
const mappedMetadata = this.mapMetadataCollection(metadata);
|
const mappedMetadata = this.mapMetadataCollection(metadata);
|
||||||
|
|
||||||
|
this.resetMetadata();
|
||||||
|
|
||||||
mappedMetadata.forEach((meta: IMetadata) => {
|
mappedMetadata.forEach((meta: IMetadata) => {
|
||||||
this.metadata.push(meta);
|
this.metadata.push(meta);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user