mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 04:40:32 +00:00
feat: apply new cards design system.
feat: empty status datatables. fix: edit account.
This commit is contained in:
@@ -42,7 +42,7 @@
|
||||
"eslint-plugin-react-hooks": "^1.6.1",
|
||||
"file-loader": "4.3.0",
|
||||
"flow-bin": "^0.123.0",
|
||||
"formik": "^2.1.4",
|
||||
"formik": "^2.2.5",
|
||||
"fs-extra": "^8.1.0",
|
||||
"html-webpack-plugin": "4.0.0-beta.11",
|
||||
"identity-obj-proxy": "3.0.0",
|
||||
@@ -70,6 +70,7 @@
|
||||
"react-dev-utils": "^10.2.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-dropzone": "^11.0.1",
|
||||
"react-error-boundary": "^3.0.2",
|
||||
"react-grid-system": "^6.2.3",
|
||||
"react-hook-form": "^4.9.4",
|
||||
"react-intl": "^3.12.0",
|
||||
@@ -130,6 +131,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-flow": "^7.9.0",
|
||||
"@welldone-software/why-did-you-render": "^6.0.0-rc.1",
|
||||
"http-proxy-middleware": "^1.0.0",
|
||||
"react-query-devtools": "^2.1.1",
|
||||
"redux-devtools": "^3.5.0"
|
||||
|
||||
@@ -2,6 +2,9 @@ import { Classes } from '@blueprintjs/core';
|
||||
|
||||
const CLASSES = {
|
||||
DASHBOARD_DATATABLE: 'dashboard__datatable',
|
||||
DASHBOARD_CARD: 'dashboard__card',
|
||||
DASHBOARD_CARD_PAGE: 'dashboard__card--page',
|
||||
|
||||
DATATABLE_EDITOR: 'datatable-editor',
|
||||
DATATABLE_EDITOR_ACTIONS: 'datatable-editor__actions',
|
||||
DATATABLE_EDITOR_ITEMS_ENTRIES: 'items-entries-table',
|
||||
@@ -13,7 +16,7 @@ const CLASSES = {
|
||||
PAGE_FORM_HEADER_BIG_NUMBERS: 'page-form__big-numbers',
|
||||
PAGE_FORM_TABS: 'page-form__tabs',
|
||||
PAGE_FORM_BODY: 'page-form__body',
|
||||
|
||||
|
||||
PAGE_FORM_FOOTER: 'page-form__footer',
|
||||
PAGE_FORM_FLOATING_ACTIONS: 'page-form__floating-actions',
|
||||
|
||||
|
||||
17
client/src/components/Dashboard/DashboardCard.js
Normal file
17
client/src/components/Dashboard/DashboardCard.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
// Dashboard card.
|
||||
export default function DashboardCard({ children, page }) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(CLASSES.DASHBOARD_CARD, {
|
||||
[CLASSES.DASHBOARD_CARD_PAGE]: page,
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
import React from 'react';
|
||||
import { ErrorBoundary } from 'react-error-boundary';
|
||||
import DashboardTopbar from 'components/Dashboard/DashboardTopbar';
|
||||
import DashboardContentRoute from 'components/Dashboard/DashboardContentRoute';
|
||||
import DashboardFooter from 'components/Dashboard/DashboardFooter';
|
||||
import DashboardErrorBoundary from './DashboardErrorBoundary';
|
||||
|
||||
export default function() {
|
||||
export default function () {
|
||||
return (
|
||||
<div className="dashboard-content" id="dashboard">
|
||||
<DashboardTopbar />
|
||||
<DashboardContentRoute />
|
||||
|
||||
<DashboardFooter />
|
||||
</div>
|
||||
<ErrorBoundary FallbackComponent={DashboardErrorBoundary}>
|
||||
<div className="dashboard-content" id="dashboard">
|
||||
<DashboardTopbar />
|
||||
<DashboardContentRoute />
|
||||
<DashboardFooter />
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
12
client/src/components/Dashboard/DashboardErrorBoundary.js
Normal file
12
client/src/components/Dashboard/DashboardErrorBoundary.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import { Icon } from 'components';
|
||||
|
||||
export default function DashboardErrorBoundary({}) {
|
||||
return (
|
||||
<div class="dashboard__error-boundary">
|
||||
<h1>Sorry about that! Something went wrong</h1>
|
||||
<p>If the problem stuck, please <a href="#">contact us</a> as soon as possible.</p>
|
||||
<Icon icon="bigcapital" height={30} width={160} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { useHistory } from 'react-router';
|
||||
import {
|
||||
Navbar,
|
||||
@@ -14,7 +13,7 @@ import { FormattedMessage as T } from 'react-intl';
|
||||
|
||||
import DashboardTopbarUser from 'components/Dashboard/TopbarUser';
|
||||
import DashboardBreadcrumbs from 'components/Dashboard/DashboardBreadcrumbs';
|
||||
import { Icon, If } from 'components';
|
||||
import { Icon, Hint, If } from 'components';
|
||||
|
||||
import withSearch from 'containers/GeneralSearch/withSearch';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
@@ -78,8 +77,18 @@ function DashboardTopbar({
|
||||
<div class="dashboard__title">
|
||||
<h1>{pageTitle}</h1>
|
||||
|
||||
<If condition={true}>
|
||||
<div class="dashboard__hint">
|
||||
<Hint
|
||||
content={
|
||||
'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.'
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</If>
|
||||
|
||||
<If condition={pageSubtitle}>
|
||||
<h3>{ pageSubtitle }</h3>
|
||||
<h3>{pageSubtitle}</h3>
|
||||
</If>
|
||||
|
||||
<If condition={pageSubtitle && editViewId}>
|
||||
|
||||
@@ -343,6 +343,7 @@ export default function DataTable({
|
||||
<div
|
||||
className={classnames('bigcapital-datatable', className, {
|
||||
'has-sticky': sticky,
|
||||
'has-pagination': pagination,
|
||||
'is-expandable': expandable,
|
||||
'is-loading': loading,
|
||||
'has-virtualized-rows': virtualizedRows,
|
||||
|
||||
@@ -2,11 +2,15 @@ import React from 'react';
|
||||
import { Tooltip, Position } from '@blueprintjs/core';
|
||||
import Icon from './Icon';
|
||||
|
||||
export default function FieldHint({ content, position }) {
|
||||
export default function FieldHint({
|
||||
content,
|
||||
position,
|
||||
iconSize = 12
|
||||
}) {
|
||||
return (
|
||||
<span class="hint">
|
||||
<Tooltip content={content} position={position}>
|
||||
<Icon icon="info-circle" iconSize={12} />
|
||||
<Icon icon="info-circle" iconSize={iconSize} />
|
||||
</Tooltip>
|
||||
</span>
|
||||
);
|
||||
|
||||
27
client/src/components/Forms/Checkbox.tsx
Normal file
27
client/src/components/Forms/Checkbox.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Checkbox as BPCheckbox,
|
||||
} from '@blueprintjs/core';
|
||||
|
||||
export default function CheckboxComponent(props) {
|
||||
const { field, form, ...rest } = props;
|
||||
const [value, setValue] = useState(field.value || false);
|
||||
|
||||
const handleChange = () => {
|
||||
const checked = !value;
|
||||
form.setFieldValue(field.name, checked);
|
||||
setValue(checked);
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
form.setFieldTouched(field.name);
|
||||
};
|
||||
|
||||
const checkboxProps = {
|
||||
...rest,
|
||||
onChange: handleChange,
|
||||
onBlur: handleBlur,
|
||||
checked: value,
|
||||
}
|
||||
return <BPCheckbox {...checkboxProps} />;
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import DisplayNameList from './DisplayNameList';
|
||||
import MoneyInputGroup from './MoneyInputGroup';
|
||||
import Dragzone from './Dragzone';
|
||||
import EmptyStatus from './EmptyStatus';
|
||||
import DashboardCard from './Dashboard/DashboardCard';
|
||||
|
||||
const Hint = FieldHint;
|
||||
|
||||
@@ -81,5 +82,6 @@ export {
|
||||
SalutationList,
|
||||
MoneyInputGroup,
|
||||
Dragzone,
|
||||
EmptyStatus
|
||||
EmptyStatus,
|
||||
DashboardCard,
|
||||
};
|
||||
|
||||
@@ -444,7 +444,6 @@ function MakeJournalEntriesForm({
|
||||
},
|
||||
[changePageSubtitle],
|
||||
);
|
||||
console.log(values, 'Val');
|
||||
return (
|
||||
<div class="make-journal-entries">
|
||||
<form onSubmit={handleSubmit}>
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import React, { useEffect, useCallback, useState, useMemo } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import {
|
||||
Intent,
|
||||
Button,
|
||||
Classes,
|
||||
Popover,
|
||||
Tooltip,
|
||||
Menu,
|
||||
MenuItem,
|
||||
MenuDivider,
|
||||
Position,
|
||||
Tag,
|
||||
} from '@blueprintjs/core';
|
||||
import { withRouter, useParams } from 'react-router-dom';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import { useIntl } from 'react-intl';
|
||||
import moment from 'moment';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import {
|
||||
DataTable,
|
||||
@@ -23,9 +22,11 @@ import {
|
||||
Icon,
|
||||
LoadingIndicator,
|
||||
} from 'components';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { useIsValuePassed } from 'hooks';
|
||||
|
||||
import ManualJournalsEmptyStatus from './ManualJournalsEmptyStatus';
|
||||
import { AmountPopoverContent, NoteAccessor, StatusAccessor } from './components';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withManualJournals from 'containers/Accounting/withManualJournals';
|
||||
@@ -33,44 +34,7 @@ import withManualJournalsActions from 'containers/Accounting/withManualJournalsA
|
||||
|
||||
import { compose, saveInvoke } from 'utils';
|
||||
|
||||
/**
|
||||
* Status column accessor.
|
||||
*/
|
||||
const StatusAccessor = (row) => {
|
||||
return (
|
||||
<Choose>
|
||||
<Choose.When condition={!!row.status}>
|
||||
<Tag minimal={true}>
|
||||
<T id={'published'} />
|
||||
</Tag>
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<Tag minimal={true} intent={Intent.WARNING}>
|
||||
<T id={'draft'} />
|
||||
</Tag>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Note column accessor.
|
||||
*/
|
||||
function NoteAccessor(row) {
|
||||
return (
|
||||
<If condition={row.description}>
|
||||
<Tooltip
|
||||
className={Classes.TOOLTIP_INDICATOR}
|
||||
content={row.description}
|
||||
position={Position.LEFT_TOP}
|
||||
hoverOpenDelay={50}
|
||||
>
|
||||
<Icon icon={'file-alt'} iconSize={16} />
|
||||
</Tooltip>
|
||||
</If>
|
||||
);
|
||||
}
|
||||
|
||||
function ManualJournalsDataTable({
|
||||
// #withManualJournals
|
||||
@@ -166,7 +130,14 @@ function ManualJournalsDataTable({
|
||||
{
|
||||
id: 'amount',
|
||||
Header: formatMessage({ id: 'amount' }),
|
||||
accessor: (r) => <Money amount={r.amount} currency={'USD'} />,
|
||||
accessor: (r) => (
|
||||
<Tooltip
|
||||
content={<AmountPopoverContent journalEntries={r.entries} />}
|
||||
position={Position.RIGHT_BOTTOM}
|
||||
>
|
||||
<Money amount={r.amount} currency={'USD'} />
|
||||
</Tooltip>
|
||||
),
|
||||
className: 'amount',
|
||||
width: 115,
|
||||
},
|
||||
@@ -254,37 +225,39 @@ function ManualJournalsDataTable({
|
||||
const showEmptyStatus = [
|
||||
manualJournalsCurrentViewId === -1,
|
||||
manualJournalsCurrentPage.length === 0,
|
||||
].every(condition => condition === true);
|
||||
].every((condition) => condition === true);
|
||||
|
||||
return (
|
||||
<LoadingIndicator loading={manualJournalsLoading && !isLoadedBefore}>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<ManualJournalsEmptyStatus />
|
||||
</Choose.When>
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<LoadingIndicator loading={manualJournalsLoading && !isLoadedBefore}>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<ManualJournalsEmptyStatus />
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={manualJournalsCurrentPage}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
expandable={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagesCount={manualJournalsPagination.pagesCount}
|
||||
pagination={true}
|
||||
initialPageSize={manualJournalsTableQuery.page_size}
|
||||
initialPageIndex={manualJournalsTableQuery.page - 1}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={manualJournalsCurrentPage}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
expandable={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagesCount={manualJournalsPagination.pagesCount}
|
||||
pagination={true}
|
||||
initialPageSize={manualJournalsTableQuery.page_size}
|
||||
initialPageIndex={manualJournalsTableQuery.page - 1}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -304,7 +277,7 @@ export default compose(
|
||||
manualJournalsLoading,
|
||||
manualJournalsPagination,
|
||||
manualJournalsTableQuery,
|
||||
manualJournalsCurrentViewId
|
||||
manualJournalsCurrentViewId,
|
||||
}),
|
||||
),
|
||||
)(ManualJournalsDataTable);
|
||||
|
||||
102
client/src/containers/Accounting/components.js
Normal file
102
client/src/containers/Accounting/components.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Intent,
|
||||
Classes,
|
||||
Tooltip,
|
||||
Position,
|
||||
Tag,
|
||||
} from '@blueprintjs/core';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { Choose, Money, If, Icon } from 'components';
|
||||
import withAccountDetails from 'containers/Accounts/withAccountDetail';
|
||||
import { compose } from 'utils';
|
||||
|
||||
const AmountPopoverContentLineRender = ({
|
||||
journalEntry,
|
||||
accountId,
|
||||
|
||||
// #withAccountDetail
|
||||
account,
|
||||
}) => {
|
||||
const isCredit = !!journalEntry.credit;
|
||||
const isDebit = !!journalEntry.debit;
|
||||
|
||||
return (
|
||||
<Choose>
|
||||
<Choose.When condition={isDebit}>
|
||||
<div>
|
||||
C. <Money amount={journalEntry.debit} currency={'USD'} /> USD -{' '}
|
||||
{account.name} <If condition={account.code}>({account.code})</If>
|
||||
</div>
|
||||
</Choose.When>
|
||||
|
||||
<Choose.When condition={isCredit}>
|
||||
<div class={'ml1'}>
|
||||
D. <Money amount={journalEntry.credit} currency={'USD'} /> USD -{' '}
|
||||
{account.name} <If condition={account.code}>({account.code})</If>
|
||||
</div>
|
||||
</Choose.When>
|
||||
</Choose>
|
||||
);
|
||||
};
|
||||
|
||||
const AmountPopoverContentLine = compose(withAccountDetails)(
|
||||
AmountPopoverContentLineRender,
|
||||
);
|
||||
|
||||
export function AmountPopoverContent({ journalEntries }) {
|
||||
const journalLinesProps = journalEntries.map((journalEntry) => ({
|
||||
journalEntry,
|
||||
accountId: journalEntry.account_id,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div>
|
||||
{journalLinesProps.map(({ journalEntry, accountId }) => (
|
||||
<AmountPopoverContentLine
|
||||
journalEntry={journalEntry}
|
||||
accountId={accountId}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Status column accessor.
|
||||
*/
|
||||
export const StatusAccessor = (row) => {
|
||||
return (
|
||||
<Choose>
|
||||
<Choose.When condition={!!row.status}>
|
||||
<Tag minimal={true}>
|
||||
<T id={'published'} />
|
||||
</Tag>
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<Tag minimal={true} intent={Intent.WARNING}>
|
||||
<T id={'draft'} />
|
||||
</Tag>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Note column accessor.
|
||||
*/
|
||||
export function NoteAccessor(row) {
|
||||
return (
|
||||
<If condition={row.description}>
|
||||
<Tooltip
|
||||
className={Classes.TOOLTIP_INDICATOR}
|
||||
content={row.description}
|
||||
position={Position.LEFT_TOP}
|
||||
hoverOpenDelay={50}
|
||||
>
|
||||
<Icon icon={'file-alt'} iconSize={16} />
|
||||
</Tooltip>
|
||||
</If>
|
||||
);
|
||||
}
|
||||
@@ -12,17 +12,13 @@ import {
|
||||
} from '@blueprintjs/core';
|
||||
import { withRouter } from 'react-router';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import classnames from 'classnames';
|
||||
import {
|
||||
Icon,
|
||||
DataTable,
|
||||
Money,
|
||||
If,
|
||||
Choose,
|
||||
} from 'components';
|
||||
import classNames from 'classnames';
|
||||
import { Icon, DataTable, Money, If, Choose } from 'components';
|
||||
import { compose } from 'utils';
|
||||
import { useUpdateEffect } from 'hooks';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
import withAccounts from 'containers/Accounts/withAccounts';
|
||||
@@ -30,6 +26,7 @@ import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withCurrentView from 'containers/Views/withCurrentView';
|
||||
|
||||
|
||||
|
||||
function NormalCell({ cell }) {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
@@ -52,7 +49,7 @@ function NormalCell({ cell }) {
|
||||
function BalanceCell({ cell }) {
|
||||
const account = cell.row.original;
|
||||
|
||||
return (account.amount) ? (
|
||||
return account.amount ? (
|
||||
<span>
|
||||
<Money amount={account.amount} currency={'USD'} />
|
||||
</span>
|
||||
@@ -64,13 +61,14 @@ function BalanceCell({ cell }) {
|
||||
function InactiveSemafro() {
|
||||
return (
|
||||
<Tooltip
|
||||
content={<T id='inactive' />}
|
||||
className={classnames(
|
||||
content={<T id="inactive" />}
|
||||
className={classNames(
|
||||
Classes.TOOLTIP_INDICATOR,
|
||||
'bp3-popover-wrapper--inactive-semafro'
|
||||
'bp3-popover-wrapper--inactive-semafro',
|
||||
)}
|
||||
position={Position.TOP}
|
||||
hoverOpenDelay={250}>
|
||||
hoverOpenDelay={250}
|
||||
>
|
||||
<div className="inactive-semafro"></div>
|
||||
</Tooltip>
|
||||
);
|
||||
@@ -82,7 +80,7 @@ function AccountNameAccessor(row) {
|
||||
<Choose>
|
||||
<Choose.When condition={!!row.description}>
|
||||
<Tooltip
|
||||
className={classnames(
|
||||
className={classNames(
|
||||
Classes.TOOLTIP_INDICATOR,
|
||||
'bp3-popover-wrapper--account-desc',
|
||||
)}
|
||||
@@ -94,9 +92,7 @@ function AccountNameAccessor(row) {
|
||||
</Tooltip>
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
{ row.name }
|
||||
</Choose.Otherwise>
|
||||
<Choose.Otherwise>{row.name}</Choose.Otherwise>
|
||||
</Choose>
|
||||
|
||||
<If condition={!row.active}>
|
||||
@@ -159,7 +155,8 @@ function AccountsDataTable({
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon={<Icon icon="reader-18" />}
|
||||
text={formatMessage({ id: 'view_details' })} />
|
||||
text={formatMessage({ id: 'view_details' })}
|
||||
/>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
icon={<Icon icon="pen-18" />}
|
||||
@@ -287,20 +284,22 @@ function AccountsDataTable({
|
||||
);
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={accountsTable}
|
||||
onFetchData={handleDatatableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={selectionColumn}
|
||||
expandable={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
loading={accountsLoading && !isMounted}
|
||||
rowContextMenu={rowContextMenu}
|
||||
expandColumnSpace={1}
|
||||
/>
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={accountsTable}
|
||||
onFetchData={handleDatatableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={selectionColumn}
|
||||
expandable={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
loading={accountsLoading && !isMounted}
|
||||
rowContextMenu={rowContextMenu}
|
||||
expandColumnSpace={1}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useCallback } from 'react';
|
||||
import { useParams, useHistory } from 'react-router-dom';
|
||||
import { useQuery } from 'react-query';
|
||||
|
||||
import { DashboardCard } from 'components';
|
||||
import CustomerForm from 'containers/Customers/CustomerForm';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
|
||||
@@ -40,12 +41,7 @@ function Customer({
|
||||
requestFetchCurrencies(),
|
||||
);
|
||||
|
||||
const handleFormSubmit = useCallback(
|
||||
(payload) => {
|
||||
|
||||
},
|
||||
[history],
|
||||
);
|
||||
const handleFormSubmit = useCallback((payload) => {}, [history]);
|
||||
|
||||
const handleCancel = useCallback(() => {
|
||||
history.goBack();
|
||||
@@ -60,11 +56,13 @@ function Customer({
|
||||
}
|
||||
name={'customer-form'}
|
||||
>
|
||||
<CustomerForm
|
||||
onFormSubmit={handleFormSubmit}
|
||||
customerId={id}
|
||||
onCancelForm={handleCancel}
|
||||
/>
|
||||
<DashboardCard page>
|
||||
<CustomerForm
|
||||
onFormSubmit={handleFormSubmit}
|
||||
customerId={id}
|
||||
onCancelForm={handleCancel}
|
||||
/>
|
||||
</DashboardCard>
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -172,9 +172,9 @@ function CustomerForm({
|
||||
const onSuccess = () => {
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: customer ?
|
||||
'the_item_customer_has_been_successfully_edited' :
|
||||
'the_customer_has_been_successfully_created',
|
||||
id: customer
|
||||
? 'the_item_customer_has_been_successfully_edited'
|
||||
: 'the_customer_has_been_successfully_created',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
@@ -191,7 +191,9 @@ function CustomerForm({
|
||||
};
|
||||
|
||||
if (customer && customer.id) {
|
||||
requestEditCustomer(customer.id, formValues).then(onSuccess).catch(onError);
|
||||
requestEditCustomer(customer.id, formValues)
|
||||
.then(onSuccess)
|
||||
.catch(onError);
|
||||
} else {
|
||||
requestSubmitCustomer(formValues).then(onSuccess).catch(onError);
|
||||
}
|
||||
@@ -239,14 +241,12 @@ function CustomerForm({
|
||||
>
|
||||
{({ isSubmitting }) => (
|
||||
<Form>
|
||||
<div class={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_PRIMARY)}>
|
||||
<CustomerFormPrimarySection />
|
||||
</div>
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_PRIMARY)}>
|
||||
<CustomerFormPrimarySection />
|
||||
</div>
|
||||
|
||||
<div className={'page-form__after-priamry-section'}>
|
||||
<CustomerFormAfterPrimarySection />
|
||||
</div>
|
||||
<div className={'page-form__after-priamry-section'}>
|
||||
<CustomerFormAfterPrimarySection />
|
||||
</div>
|
||||
|
||||
<div className={classNames(CLASSES.PAGE_FORM_TABS)}>
|
||||
|
||||
@@ -10,9 +10,11 @@ import {
|
||||
} from '@blueprintjs/core';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import { useIsValuePassed } from 'hooks';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import CustomersEmptyStatus from './CustomersEmptyStatus';
|
||||
import { DataTable, Icon, Money, Choose, LoadingIndicator } from 'components';
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
import withCustomers from './withCustomers';
|
||||
import withCustomersActions from './withCustomersActions';
|
||||
@@ -186,42 +188,41 @@ const CustomerTable = ({
|
||||
const showEmptyStatus = [
|
||||
customersCurrentViewId === -1,
|
||||
customers.length === 0,
|
||||
].every(condition => condition === true);
|
||||
].every((condition) => condition === true);
|
||||
|
||||
return (
|
||||
<LoadingIndicator
|
||||
loading={customersLoading && !isLoadedBefore}
|
||||
mount={false}
|
||||
>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<CustomersEmptyStatus />
|
||||
</Choose.When>
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<LoadingIndicator loading={customersLoading && !isLoadedBefore}>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<CustomersEmptyStatus />
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={customers}
|
||||
// loading={customersLoading}
|
||||
onFetchData={handleFetchData}
|
||||
selectionColumn={true}
|
||||
expandable={false}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
spinnerProps={{ size: 30 }}
|
||||
rowContextMenu={rowContextMenu}
|
||||
pagination={true}
|
||||
manualSortBy={true}
|
||||
pagesCount={customerPagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
initialPageSize={customersTableQuery.page_size}
|
||||
initialPageIndex={customersTableQuery.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={customers}
|
||||
// loading={customersLoading}
|
||||
onFetchData={handleFetchData}
|
||||
selectionColumn={true}
|
||||
expandable={false}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
spinnerProps={{ size: 30 }}
|
||||
rowContextMenu={rowContextMenu}
|
||||
pagination={true}
|
||||
manualSortBy={true}
|
||||
pagesCount={customerPagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
initialPageSize={customersTableQuery.page_size}
|
||||
initialPageIndex={customersTableQuery.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -238,7 +239,7 @@ export default compose(
|
||||
customersLoading,
|
||||
customerPagination,
|
||||
customersTableQuery,
|
||||
customersCurrentViewId
|
||||
customersCurrentViewId,
|
||||
}),
|
||||
),
|
||||
withCustomersActions,
|
||||
|
||||
@@ -6,6 +6,7 @@ export default (mapState) => {
|
||||
const mapped = {
|
||||
pageTitle: state.dashboard.pageTitle,
|
||||
pageSubtitle: state.dashboard.pageSubtitle,
|
||||
pageHint: state.dashboard.pageHint,
|
||||
editViewId: state.dashboard.topbarEditViewId,
|
||||
sidebarExpended: state.dashboard.sidebarExpended,
|
||||
preferencesPageTitle: state.dashboard.preferencesPageTitle,
|
||||
|
||||
@@ -14,6 +14,12 @@ const mapActionsToProps = (dispatch) => ({
|
||||
pageSubtitle,
|
||||
}),
|
||||
|
||||
changePageHint: (pageHint) =>
|
||||
dispatch({
|
||||
type: t.CHANGE_DASHBOARD_PAGE_HINT,
|
||||
payload: { pageHint }
|
||||
}),
|
||||
|
||||
setTopbarEditView: (id) =>
|
||||
dispatch({
|
||||
type: t.SET_TOPBAR_EDIT_VIEW,
|
||||
|
||||
@@ -88,6 +88,9 @@ function AccountFormDialogContent({
|
||||
if (errors.find((e) => e.type === 'NOT_UNIQUE_CODE')) {
|
||||
fields.code = formatMessage({ id: 'account_code_is_not_unique' });
|
||||
}
|
||||
if (errors.find((e) => e.type === 'ACCOUNT.NAME.NOT.UNIQUE')) {
|
||||
fields.name = formatMessage({ id: 'account_name_is_already_used' });
|
||||
}
|
||||
return fields;
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@ import {
|
||||
} from '@blueprintjs/core';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import moment from 'moment';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
import { DataTable, Icon, MoneyExchangeRate } from 'components';
|
||||
import LoadingIndicator from 'components/LoadingIndicator';
|
||||
@@ -140,24 +143,26 @@ function ExchangeRateTable({
|
||||
);
|
||||
|
||||
return (
|
||||
<LoadingIndicator loading={loading} mount={false}>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={exchangeRatesList}
|
||||
onFetchData={handelFetchData}
|
||||
loading={exchangeRatesLoading && !initialMount}
|
||||
manualSortBy={true}
|
||||
selectionColumn={selectionColumn}
|
||||
expandable={true}
|
||||
treeGraph={true}
|
||||
onSelectedRowsChange={handelSelectedRowsChange}
|
||||
rowContextMenu={rowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={exchangeRatesPageination.pagesCount}
|
||||
initialPageSize={exchangeRatesPageination.pageSize}
|
||||
initialPageIndex={exchangeRatesPageination.page - 1}
|
||||
/>
|
||||
</LoadingIndicator>
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<LoadingIndicator loading={loading} mount={false}>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={exchangeRatesList}
|
||||
onFetchData={handelFetchData}
|
||||
loading={exchangeRatesLoading && !initialMount}
|
||||
manualSortBy={true}
|
||||
selectionColumn={selectionColumn}
|
||||
expandable={true}
|
||||
treeGraph={true}
|
||||
onSelectedRowsChange={handelSelectedRowsChange}
|
||||
rowContextMenu={rowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={exchangeRatesPageination.pagesCount}
|
||||
initialPageSize={exchangeRatesPageination.pageSize}
|
||||
initialPageIndex={exchangeRatesPageination.page - 1}
|
||||
/>
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useCallback, useState, useMemo } from 'react';
|
||||
import React, { useEffect, useCallback, useMemo } from 'react';
|
||||
import {
|
||||
Intent,
|
||||
Button,
|
||||
@@ -15,12 +15,15 @@ import { useParams } from 'react-router-dom';
|
||||
import { withRouter } from 'react-router';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import moment from 'moment';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import Icon from 'components/Icon';
|
||||
import { compose, saveInvoke } from 'utils';
|
||||
import { useIsValuePassed } from 'hooks';
|
||||
|
||||
import { If, Money, Choose, LoadingIndicator } from 'components';
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
import DataTable from 'components/DataTable';
|
||||
import ExpensesEmptyStatus from './ExpensesEmptyStatus';
|
||||
|
||||
@@ -268,40 +271,39 @@ function ExpensesDataTable({
|
||||
|
||||
const showEmptyStatus = [
|
||||
expensesCurrentViewId === -1,
|
||||
expensesCurrentPage.length === 0
|
||||
].every(condition => condition === true);
|
||||
expensesCurrentPage.length === 0,
|
||||
].every((condition) => condition === true);
|
||||
|
||||
return (
|
||||
<LoadingIndicator
|
||||
loading={expensesLoading && !isLoadedBefore}
|
||||
mount={false}
|
||||
>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<ExpensesEmptyStatus />
|
||||
</Choose.When>
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<LoadingIndicator loading={expensesLoading && !isLoadedBefore}>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<ExpensesEmptyStatus />
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={expensesCurrentPage}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
onFetchData={handleFetchData}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={expensesPagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
initialPageSize={expensesTableQuery.page_size}
|
||||
initialPageIndex={expensesTableQuery.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={expensesCurrentPage}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
onFetchData={handleFetchData}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={expensesPagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
initialPageSize={expensesTableQuery.page_size}
|
||||
initialPageIndex={expensesTableQuery.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useIntl } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { For } from 'components';
|
||||
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import financialReportMenus from 'config/financialReportsMenu';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
|
||||
@@ -42,9 +43,11 @@ function FinancialReports({
|
||||
}, [changePageTitle, formatMessage]);
|
||||
|
||||
return (
|
||||
<div class="financial-reports">
|
||||
<For render={FinancialReportsSection} of={financialReportMenus} />
|
||||
</div>
|
||||
<DashboardInsider name={'financial-reports'}>
|
||||
<div class="financial-reports">
|
||||
<For render={FinancialReportsSection} of={financialReportMenus} />
|
||||
</div>
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,15 @@ import {
|
||||
Position,
|
||||
} from '@blueprintjs/core';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import Icon from 'components/Icon';
|
||||
import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import { compose } from 'utils';
|
||||
import DataTable from 'components/DataTable';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
import withItemCategories from './withItemCategories';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
|
||||
@@ -139,21 +142,23 @@ const ItemsCategoryList = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<LoadingIndicator mount={false}>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={categoriesList}
|
||||
onFetchData={handelFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={selectionColumn}
|
||||
expandable={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
loading={categoriesTableLoading}
|
||||
rowContextMenu={handleRowContextMenu}
|
||||
/>
|
||||
</LoadingIndicator>
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<LoadingIndicator mount={false}>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={categoriesList}
|
||||
onFetchData={handelFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={selectionColumn}
|
||||
expandable={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
loading={categoriesTableLoading}
|
||||
rowContextMenu={handleRowContextMenu}
|
||||
/>
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, { useState, useMemo, useCallback, useEffect } from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import { Formik, Form } from 'formik';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { queryCache } from 'react-query';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useIntl } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import { defaultTo } from 'lodash';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
import AppToaster from 'components/AppToaster';
|
||||
@@ -22,6 +22,8 @@ import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
|
||||
import { compose, transformToForm } from 'utils';
|
||||
import { transitionItemTypeKeyToLabel } from './utils';
|
||||
import { EditItemFormSchema, CreateItemFormSchema } from './ItemForm.schema';
|
||||
|
||||
const defaultInitialValues = {
|
||||
active: true,
|
||||
@@ -83,66 +85,15 @@ function ItemForm({
|
||||
deleteCallback: requestDeleteMedia,
|
||||
});
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
active: Yup.boolean(),
|
||||
name: Yup.string()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'item_name_' })),
|
||||
type: Yup.string()
|
||||
.trim()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'item_type_' })),
|
||||
sku: Yup.string().trim(),
|
||||
cost_price: Yup.number().when(['purchasable'], {
|
||||
is: true,
|
||||
then: Yup.number()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'cost_price_' })),
|
||||
otherwise: Yup.number().nullable(true),
|
||||
}),
|
||||
sell_price: Yup.number().when(['sellable'], {
|
||||
is: true,
|
||||
then: Yup.number()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'sell_price_' })),
|
||||
otherwise: Yup.number().nullable(true),
|
||||
}),
|
||||
cost_account_id: Yup.number()
|
||||
.when(['purchasable'], {
|
||||
is: true,
|
||||
then: Yup.number().required(),
|
||||
otherwise: Yup.number().nullable(true),
|
||||
})
|
||||
.label(formatMessage({ id: 'cost_account_id' })),
|
||||
sell_account_id: Yup.number()
|
||||
.when(['sellable'], {
|
||||
is: true,
|
||||
then: Yup.number().required(),
|
||||
otherwise: Yup.number().nullable(),
|
||||
})
|
||||
.label(formatMessage({ id: 'sell_account_id' })),
|
||||
inventory_account_id: Yup.number()
|
||||
.when(['type'], {
|
||||
is: (value) => value === 'inventory',
|
||||
then: Yup.number().required(),
|
||||
otherwise: Yup.number().nullable(),
|
||||
})
|
||||
.label(formatMessage({ id: 'inventory_account' })),
|
||||
category_id: Yup.number().positive().nullable(),
|
||||
stock: Yup.string() || Yup.boolean(),
|
||||
sellable: Yup.boolean().required(),
|
||||
purchasable: Yup.boolean().required(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Initial values in create and edit mode.
|
||||
*/
|
||||
const initialValues = useMemo(
|
||||
() => ({
|
||||
...defaultInitialValues,
|
||||
cost_account_id: parseInt(preferredCostAccount),
|
||||
sell_account_id: parseInt(preferredSellAccount),
|
||||
inventory_account_id: parseInt(preferredInventoryAccount),
|
||||
cost_account_id: defaultTo(preferredCostAccount, ''),
|
||||
sell_account_id: defaultTo(preferredSellAccount, ''),
|
||||
inventory_account_id: defaultTo(preferredInventoryAccount, ''),
|
||||
/**
|
||||
* We only care about the fields in the form. Previously unfilled optional
|
||||
* values such as `notes` come back from the API as null, so remove those
|
||||
@@ -150,7 +101,12 @@ function ItemForm({
|
||||
*/
|
||||
...transformToForm(itemDetail, defaultInitialValues),
|
||||
}),
|
||||
[],
|
||||
[
|
||||
itemDetail,
|
||||
preferredCostAccount,
|
||||
preferredSellAccount,
|
||||
preferredInventoryAccount,
|
||||
],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -214,7 +170,7 @@ function ItemForm({
|
||||
|
||||
useEffect(() => {
|
||||
if (itemDetail && itemDetail.type) {
|
||||
changePageSubtitle(formatMessage({ id: itemDetail.type }));
|
||||
changePageSubtitle(transitionItemTypeKeyToLabel(itemDetail.type));
|
||||
}
|
||||
}, [itemDetail, changePageSubtitle, formatMessage]);
|
||||
|
||||
@@ -262,14 +218,14 @@ function ItemForm({
|
||||
<div class={classNames(CLASSES.PAGE_FORM_ITEM)}>
|
||||
<Formik
|
||||
enableReinitialize={true}
|
||||
validationSchema={validationSchema}
|
||||
validationSchema={isNewMode ? CreateItemFormSchema : EditItemFormSchema}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
{({ isSubmitting, handleSubmit }) => (
|
||||
<Form>
|
||||
<div class={classNames(CLASSES.PAGE_FORM_BODY)}>
|
||||
<ItemFormPrimarySection />
|
||||
<ItemFormPrimarySection itemId={itemId} />
|
||||
<ItemFormBody />
|
||||
<ItemFormInventorySection />
|
||||
</div>
|
||||
@@ -294,8 +250,10 @@ export default compose(
|
||||
withDashboardActions,
|
||||
withMediaActions,
|
||||
withSettings(({ itemsSettings }) => ({
|
||||
preferredCostAccount: itemsSettings.preferredCostAccount,
|
||||
preferredSellAccount: itemsSettings.preferredSellAccount,
|
||||
preferredInventoryAccount: itemsSettings.preferredInventoryAccount,
|
||||
preferredCostAccount: parseInt(itemsSettings?.preferredCostAccount),
|
||||
preferredSellAccount: parseInt(itemsSettings?.preferredSellAccount),
|
||||
preferredInventoryAccount: parseInt(
|
||||
itemsSettings?.preferredInventoryAccount,
|
||||
),
|
||||
})),
|
||||
)(ItemForm);
|
||||
|
||||
56
client/src/containers/Items/ItemForm.schema.js
Normal file
56
client/src/containers/Items/ItemForm.schema.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import * as Yup from 'yup';
|
||||
import { formatMessage } from 'services/intl';
|
||||
|
||||
const Schema = Yup.object().shape({
|
||||
active: Yup.boolean(),
|
||||
name: Yup.string()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'item_name_' })),
|
||||
type: Yup.string()
|
||||
.trim()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'item_type_' })),
|
||||
sku: Yup.string().trim(),
|
||||
cost_price: Yup.number().when(['purchasable'], {
|
||||
is: true,
|
||||
then: Yup.number()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'cost_price_' })),
|
||||
otherwise: Yup.number().nullable(true),
|
||||
}),
|
||||
sell_price: Yup.number().when(['sellable'], {
|
||||
is: true,
|
||||
then: Yup.number()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'sell_price_' })),
|
||||
otherwise: Yup.number().nullable(true),
|
||||
}),
|
||||
cost_account_id: Yup.number()
|
||||
.when(['purchasable'], {
|
||||
is: true,
|
||||
then: Yup.number().required(),
|
||||
otherwise: Yup.number().nullable(true),
|
||||
})
|
||||
.label(formatMessage({ id: 'cost_account_id' })),
|
||||
sell_account_id: Yup.number()
|
||||
.when(['sellable'], {
|
||||
is: true,
|
||||
then: Yup.number().required(),
|
||||
otherwise: Yup.number().nullable(),
|
||||
})
|
||||
.label(formatMessage({ id: 'sell_account_id' })),
|
||||
inventory_account_id: Yup.number()
|
||||
.when(['type'], {
|
||||
is: (value) => value === 'inventory',
|
||||
then: Yup.number().required(),
|
||||
otherwise: Yup.number().nullable(),
|
||||
})
|
||||
.label(formatMessage({ id: 'inventory_account' })),
|
||||
category_id: Yup.number().positive().nullable(),
|
||||
stock: Yup.string() || Yup.boolean(),
|
||||
sellable: Yup.boolean().required(),
|
||||
purchasable: Yup.boolean().required(),
|
||||
});
|
||||
|
||||
export const CreateItemFormSchema = Schema;
|
||||
export const EditItemFormSchema = Schema;
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { FastField, ErrorMessage } from 'formik';
|
||||
import { FastField, Field, ErrorMessage } from 'formik';
|
||||
import {
|
||||
FormGroup,
|
||||
Classes,
|
||||
@@ -27,8 +27,8 @@ function ItemFormBody({ accountsList }) {
|
||||
<Row>
|
||||
<Col xs={6}>
|
||||
{/*------------- Purchasable checbox ------------- */}
|
||||
<FastField name={'sellable'}>
|
||||
{({ field, field: { value } }) => (
|
||||
<FastField name={'sellable'} type="checkbox">
|
||||
{({ field: { onChange, onBlur, name, checked } }) => (
|
||||
<FormGroup inline={true} className={'form-group--sellable'}>
|
||||
<Checkbox
|
||||
inline={true}
|
||||
@@ -37,8 +37,10 @@ function ItemFormBody({ accountsList }) {
|
||||
<T id={'i_sell_this_item'} />
|
||||
</h3>
|
||||
}
|
||||
checked={value}
|
||||
{...field}
|
||||
name={'sellable'}
|
||||
checked={!!checked}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function ItemFormFloatingActions({
|
||||
{/*----------- Active ----------*/}
|
||||
<FastField name={'active'}>
|
||||
{({ field, field: { value } }) => (
|
||||
<FormGroup label={' '} inline={true} className={'form-group--active'}>
|
||||
<FormGroup inline={true} className={'form-group--active'}>
|
||||
<Checkbox
|
||||
inline={true}
|
||||
label={<T id={'active'} />}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useParams, useHistory } from 'react-router-dom';
|
||||
import { useQuery } from 'react-query';
|
||||
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import DashboardCard from 'components/Dashboard/DashboardCard';
|
||||
import ItemForm from 'containers/Items/ItemForm';
|
||||
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
@@ -62,11 +63,13 @@ const ItemFormContainer = ({
|
||||
}
|
||||
name={'item-form'}
|
||||
>
|
||||
<ItemForm
|
||||
onFormSubmit={handleFormSubmit}
|
||||
itemId={id}
|
||||
onCancelForm={handleCancel}
|
||||
/>
|
||||
<DashboardCard page>
|
||||
<ItemForm
|
||||
onFormSubmit={handleFormSubmit}
|
||||
itemId={id}
|
||||
onCancelForm={handleCancel}
|
||||
/>
|
||||
</DashboardCard>
|
||||
</DashboardInsider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@ import withAccounts from 'containers/Accounts/withAccounts';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
|
||||
import { compose, handleStringChange, inputIntent } from 'utils';
|
||||
import { transitionItemTypeKeyToLabel } from './utils';
|
||||
|
||||
/**
|
||||
* Item form primary section.
|
||||
@@ -35,8 +36,12 @@ function ItemFormPrimarySection({
|
||||
|
||||
// #withDashboardActions
|
||||
changePageSubtitle,
|
||||
|
||||
// #ownProps
|
||||
itemId,
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
const isNewMode = !itemId;
|
||||
|
||||
const itemTypeHintContent = (
|
||||
<>
|
||||
@@ -59,48 +64,45 @@ function ItemFormPrimarySection({
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_PRIMARY)}>
|
||||
{/*----------- Item type ----------*/}
|
||||
<FastField name={'type'}>
|
||||
{({ form, field: { value }, meta: { touched, error } }) => (
|
||||
<FormGroup
|
||||
medium={true}
|
||||
label={<T id={'item_type'} />}
|
||||
labelInfo={
|
||||
<span>
|
||||
<FieldRequiredHint />
|
||||
<Hint
|
||||
content={itemTypeHintContent}
|
||||
position={Position.BOTTOM_LEFT}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
className={'form-group--item-type'}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="item_type" />}
|
||||
inline={true}
|
||||
>
|
||||
<RadioGroup
|
||||
inline={true}
|
||||
onChange={handleStringChange((_value) => {
|
||||
form.setFieldValue('type', _value);
|
||||
changePageSubtitle(transitionItemTypeKeyToLabel(_value));
|
||||
})}
|
||||
selectedValue={value}
|
||||
disabled={value === 'inventory' && !isNewMode}
|
||||
>
|
||||
<Radio label={<T id={'service'} />} value="service" />
|
||||
<Radio label={<T id={'non_inventory'} />} value="non-inventory" />
|
||||
<Radio label={<T id={'inventory'} />} value="inventory" />
|
||||
</RadioGroup>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
<Row>
|
||||
<Col xs={7}>
|
||||
{/*----------- Item type ----------*/}
|
||||
<FastField name={'type'}>
|
||||
{({ form, field: { value }, meta: { touched, error } }) => (
|
||||
<FormGroup
|
||||
medium={true}
|
||||
label={<T id={'item_type'} />}
|
||||
labelInfo={
|
||||
<span>
|
||||
<FieldRequiredHint />
|
||||
<Hint
|
||||
content={itemTypeHintContent}
|
||||
position={Position.BOTTOM_LEFT}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
className={'form-group--item-type'}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="item_type" />}
|
||||
inline={true}
|
||||
>
|
||||
<RadioGroup
|
||||
inline={true}
|
||||
onChange={handleStringChange((_value) => {
|
||||
form.setFieldValue('type', _value);
|
||||
changePageSubtitle(formatMessage({ id: _value }));
|
||||
})}
|
||||
selectedValue={value}
|
||||
disabled={value === 'inventory'}
|
||||
>
|
||||
<Radio label={<T id={'service'} />} value="service" />
|
||||
<Radio
|
||||
label={<T id={'non_inventory'} />}
|
||||
value="non-inventory"
|
||||
/>
|
||||
<Radio label={<T id={'inventory'} />} value="inventory" />
|
||||
</RadioGroup>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/*----------- Item name ----------*/}
|
||||
<FastField name={'name'}>
|
||||
{({ field, meta: { error, touched } }) => (
|
||||
|
||||
10
client/src/containers/Items/utils.js
Normal file
10
client/src/containers/Items/utils.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import { formatMessage } from "services/intl";
|
||||
|
||||
export const transitionItemTypeKeyToLabel = (itemTypeKey) => {
|
||||
const table = {
|
||||
'service': formatMessage({ id: 'service' }),
|
||||
'inventory': formatMessage({ id: 'inventory' }),
|
||||
'non-inventory': formatMessage({ id: 'non_inventory' }),
|
||||
};
|
||||
return typeof table[itemTypeKey] === 'string' ? table[itemTypeKey] : '';
|
||||
};
|
||||
@@ -1,8 +1,7 @@
|
||||
import React, { useEffect, useCallback, useState, useMemo } from 'react';
|
||||
import React, { useEffect, useCallback, useMemo } from 'react';
|
||||
import {
|
||||
Intent,
|
||||
Button,
|
||||
Classes,
|
||||
Popover,
|
||||
Menu,
|
||||
MenuItem,
|
||||
@@ -14,9 +13,11 @@ import { useParams } from 'react-router-dom';
|
||||
import { withRouter } from 'react-router';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import moment from 'moment';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import Icon from 'components/Icon';
|
||||
import { compose, saveInvoke } from 'utils';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { useIsValuePassed } from 'hooks';
|
||||
|
||||
import { LoadingIndicator, Choose } from 'components';
|
||||
@@ -221,34 +222,36 @@ function BillsDataTable({
|
||||
const showEmptyStatus = [
|
||||
billsCurrentViewId === -1,
|
||||
billsCurrentPage.length === 0,
|
||||
].every(condition => condition === true);
|
||||
].every((condition) => condition === true);
|
||||
|
||||
return (
|
||||
<LoadingIndicator loading={billsLoading && !isLoadedBefore} mount={false}>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<BillsEmptyStatus />
|
||||
</Choose.When>
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<LoadingIndicator loading={billsLoading && !isLoadedBefore} mount={false}>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<BillsEmptyStatus />
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={billsCurrentPage}
|
||||
onFetchData={handleFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={billsPageination.pagesCount}
|
||||
initialPageSize={billsPageination.pageSize}
|
||||
initialPageIndex={billsPageination.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={billsCurrentPage}
|
||||
onFetchData={handleFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={billsPageination.pagesCount}
|
||||
initialPageSize={billsPageination.pageSize}
|
||||
initialPageIndex={billsPageination.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -264,13 +267,13 @@ export default compose(
|
||||
billsLoading,
|
||||
billsPageination,
|
||||
billsTableQuery,
|
||||
billsCurrentViewId
|
||||
billsCurrentViewId,
|
||||
}) => ({
|
||||
billsCurrentPage,
|
||||
billsLoading,
|
||||
billsPageination,
|
||||
billsTableQuery,
|
||||
billsCurrentViewId
|
||||
billsCurrentViewId,
|
||||
}),
|
||||
),
|
||||
withViewDetails(),
|
||||
|
||||
@@ -11,10 +11,12 @@ import {
|
||||
import { withRouter } from 'react-router';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import moment from 'moment';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { compose, saveInvoke } from 'utils';
|
||||
import { useIsValuePassed } from 'hooks';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { DataTable, Money, Icon, Choose, LoadingIndicator } from 'components';
|
||||
import PaymentMadesEmptyStatus from './PaymentMadesEmptyStatus';
|
||||
|
||||
@@ -182,36 +184,38 @@ function PaymentMadeDataTable({
|
||||
const showEmptyStatuts = [
|
||||
paymentMadeCurrentPage.length === 0,
|
||||
paymentMadesCurrentViewId === -1,
|
||||
].every(condition => condition === true);
|
||||
].every((condition) => condition === true);
|
||||
|
||||
return (
|
||||
<LoadingIndicator loading={paymentMadesLoading && !isLoaded}>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatuts}>
|
||||
<PaymentMadesEmptyStatus />
|
||||
</Choose.When>
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<LoadingIndicator loading={paymentMadesLoading && !isLoaded}>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatuts}>
|
||||
<PaymentMadesEmptyStatus />
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={paymentMadeCurrentPage}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={paymentMadePageination.pagesCount}
|
||||
initialPageSize={paymentMadeTableQuery.page_size}
|
||||
initialPageIndex={paymentMadeTableQuery.page - 1}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={paymentMadeCurrentPage}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={paymentMadePageination.pagesCount}
|
||||
initialPageSize={paymentMadeTableQuery.page_size}
|
||||
initialPageIndex={paymentMadeTableQuery.page - 1}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -225,13 +229,13 @@ export default compose(
|
||||
paymentMadesLoading,
|
||||
paymentMadePageination,
|
||||
paymentMadeTableQuery,
|
||||
paymentMadesCurrentViewId
|
||||
paymentMadesCurrentViewId,
|
||||
}) => ({
|
||||
paymentMadeCurrentPage,
|
||||
paymentMadesLoading,
|
||||
paymentMadePageination,
|
||||
paymentMadeTableQuery,
|
||||
paymentMadesCurrentViewId
|
||||
paymentMadesCurrentViewId,
|
||||
}),
|
||||
),
|
||||
)(PaymentMadeDataTable);
|
||||
|
||||
@@ -63,7 +63,9 @@ function PaymentReceiveFormPage({
|
||||
fetchAccounts.isFetching ||
|
||||
// fetchSettings.isFetching ||
|
||||
fetchCustomers.isFetching
|
||||
}>
|
||||
}
|
||||
name={'payment-receive-form'}
|
||||
>
|
||||
<PaymentReceiveForm
|
||||
paymentReceiveId={paymentReceiveId}
|
||||
/>
|
||||
|
||||
@@ -11,10 +11,13 @@ import {
|
||||
import { withRouter } from 'react-router';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import moment from 'moment';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { compose, saveInvoke } from 'utils';
|
||||
import { useIsValuePassed } from 'hooks';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
import PaymentReceivesEmptyStatus from './PaymentReceivesEmptyStatus';
|
||||
import { LoadingIndicator, DataTable, Choose, Money, Icon } from 'components';
|
||||
|
||||
@@ -186,6 +189,7 @@ function PaymentReceivesDataTable({
|
||||
].every(condition => condition === true);
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<LoadingIndicator
|
||||
loading={paymentReceivesLoading && !isLoaded}
|
||||
mount={false}
|
||||
@@ -216,6 +220,7 @@ function PaymentReceivesDataTable({
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,12 @@ import {
|
||||
import { withRouter } from 'react-router';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import moment from 'moment';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { compose, saveInvoke } from 'utils';
|
||||
import { useIsValuePassed } from 'hooks';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { Choose, LoadingIndicator, DataTable, Money, Icon } from 'components';
|
||||
|
||||
import ReceiptsEmptyStatus from './ReceiptsEmptyStatus';
|
||||
@@ -192,36 +194,38 @@ function ReceiptsDataTable({
|
||||
const showEmptyStatus = [
|
||||
receiptsCurrentViewId === -1,
|
||||
receiptsCurrentPage.length === 0,
|
||||
].every(condition => condition === true);
|
||||
].every((condition) => condition === true);
|
||||
|
||||
return (
|
||||
<LoadingIndicator loading={receiptsLoading && !isLoadedBefore}>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<ReceiptsEmptyStatus />
|
||||
</Choose.When>
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
<LoadingIndicator loading={receiptsLoading && !isLoadedBefore}>
|
||||
<Choose>
|
||||
<Choose.When condition={showEmptyStatus}>
|
||||
<ReceiptsEmptyStatus />
|
||||
</Choose.When>
|
||||
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={receiptsCurrentPage}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={receiptsPagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
initialPageSize={receiptTableQuery.page_size}
|
||||
initialPageIndex={receiptTableQuery.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
<Choose.Otherwise>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={receiptsCurrentPage}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
rowContextMenu={onRowContextMenu}
|
||||
pagination={true}
|
||||
pagesCount={receiptsPagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
initialPageSize={receiptTableQuery.page_size}
|
||||
initialPageIndex={receiptTableQuery.page - 1}
|
||||
/>
|
||||
</Choose.Otherwise>
|
||||
</Choose>
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -236,13 +240,13 @@ export default compose(
|
||||
receiptsLoading,
|
||||
receiptsPagination,
|
||||
receiptTableQuery,
|
||||
receiptsCurrentViewId
|
||||
receiptsCurrentViewId,
|
||||
}) => ({
|
||||
receiptsCurrentPage,
|
||||
receiptsLoading,
|
||||
receiptsPagination,
|
||||
receiptTableQuery,
|
||||
receiptsCurrentViewId
|
||||
receiptsCurrentViewId,
|
||||
}),
|
||||
),
|
||||
)(ReceiptsDataTable);
|
||||
|
||||
@@ -7,12 +7,17 @@ import App from 'components/App';
|
||||
import * as serviceWorker from 'serviceWorker';
|
||||
import createStore from 'store/createStore';
|
||||
import AppProgress from 'components/NProgress/AppProgress';
|
||||
import { setLocale } from 'yup';
|
||||
|
||||
import {locale} from 'lang/en/locale';
|
||||
import whyDidYouRender from "@welldone-software/why-did-you-render";
|
||||
|
||||
whyDidYouRender(React, {
|
||||
onlyLogs: true,
|
||||
titleColor: "green",
|
||||
diffNameColor: "aqua"
|
||||
});
|
||||
|
||||
|
||||
|
||||
setLocale(locale)
|
||||
ReactDOM.render(
|
||||
<Provider store={createStore}>
|
||||
<BrowserRouter>
|
||||
|
||||
@@ -213,8 +213,11 @@ export default {
|
||||
once_delete_this_item_you_will_able_to_restore_it: `Once you delete this item, you won\'t be able to restore the item later. Are you sure you want to delete ?<br /><br />If you're not sure, you can inactivate it instead.`,
|
||||
the_item_has_been_successfully_deleted:
|
||||
'The item has been successfully deleted.',
|
||||
the_item_has_been_created_successfully:
|
||||
'The item has been created successfully.',
|
||||
the_item_has_been_successfully_edited:
|
||||
'The item #{number} has been successfully edited.',
|
||||
|
||||
the_item_category_has_been_successfully_created:
|
||||
'The item category has been successfully created.',
|
||||
the_item_category_has_been_successfully_edited:
|
||||
@@ -819,4 +822,5 @@ export default {
|
||||
the_name_used_before: 'The name is already used.',
|
||||
the_item_has_associated_transactions: 'The item has associated transactions.',
|
||||
customer_has_sales_invoices: 'Customer has sales invoices',
|
||||
account_name_is_already_used: 'Account name is already used.',
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createReducer } from '@reduxjs/toolkit';
|
||||
const initialState = {
|
||||
pageTitle: '',
|
||||
pageSubtitle: '',
|
||||
pageHint: '',
|
||||
preferencesPageTitle: '',
|
||||
sidebarExpended: true,
|
||||
dialogs: {},
|
||||
@@ -20,6 +21,10 @@ export default createReducer(initialState, {
|
||||
state.pageSubtitle = action.pageSubtitle;
|
||||
},
|
||||
|
||||
[t.CHANGE_DASHBOARD_PAGE_HINT]: (state, action) => {
|
||||
state.pageHint = action.pageHint;
|
||||
},
|
||||
|
||||
[t.CHANGE_PREFERENCES_PAGE_TITLE]: (state, action) => {
|
||||
state.preferencesPageTitle = action.pageTitle;
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@ export default {
|
||||
CLOSE_DIALOG: 'CLOSE_DIALOG',
|
||||
CLOSE_ALL_DIALOGS: 'CLOSE_ALL_DIALOGS',
|
||||
CHANGE_DASHBOARD_PAGE_TITLE: 'CHANGE_DASHBOARD_PAGE_TITLE',
|
||||
CHANGE_DASHBOARD_PAGE_HINT: 'CHANGE_DASHBOARD_PAGE_HINT',
|
||||
CHANGE_PREFERENCES_PAGE_TITLE: 'CHANGE_PREFERENCES_PAGE_TITLE',
|
||||
ALTER_DASHBOARD_PAGE_SUBTITLE: 'ALTER_DASHBOARD_PAGE_SUBTITLE',
|
||||
SET_TOPBAR_EDIT_VIEW: 'SET_TOPBAR_EDIT_VIEW',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { omit } from 'lodash';
|
||||
import { omit, flatten } from 'lodash';
|
||||
import ApiService from 'services/ApiService';
|
||||
import t from 'store/types';
|
||||
|
||||
@@ -135,7 +135,14 @@ export const fetchManualJournalsTable = ({ query } = {}) => {
|
||||
});
|
||||
dispatch({
|
||||
type: t.MANUAL_JOURNALS_ITEMS_SET,
|
||||
manual_journals: response.data.manual_journals,
|
||||
manual_journals: [
|
||||
...response.data.manual_journals.map((manualJournal) => ({
|
||||
...manualJournal,
|
||||
entries: manualJournal.entries.map((entry) => ({
|
||||
...omit(entry, ['account']),
|
||||
}))
|
||||
})),
|
||||
]
|
||||
});
|
||||
dispatch({
|
||||
type: t.MANUAL_JOURNALS_PAGINATION_SET,
|
||||
@@ -145,6 +152,12 @@ export const fetchManualJournalsTable = ({ query } = {}) => {
|
||||
response.data.manual_journals?.viewMeta?.customViewId || -1,
|
||||
},
|
||||
});
|
||||
dispatch({
|
||||
type: t.ACCOUNTS_ITEMS_SET,
|
||||
accounts: flatten(response.data.manual_journals?.map(
|
||||
journal => journal?.entries.map(entry => entry.account),
|
||||
)),
|
||||
});
|
||||
dispatch({
|
||||
type: t.MANUAL_JOURNALS_TABLE_LOADING,
|
||||
loading: false,
|
||||
|
||||
@@ -204,17 +204,20 @@ body.authentication {
|
||||
}
|
||||
|
||||
|
||||
// .page-form
|
||||
// .page-form__header
|
||||
// .page-form__content
|
||||
// .page-form__floating-actions
|
||||
.page-form{
|
||||
|
||||
&__header{
|
||||
padding: 20px;
|
||||
&__header{
|
||||
background-color: #fbfbfb;
|
||||
padding: 30px 20px 20px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
&__primary-section{
|
||||
background-color: #fbfbfb;
|
||||
padding: 30px 20px 20px;
|
||||
margin: -20px;
|
||||
padding-bottom: 6px;
|
||||
|
||||
}
|
||||
|
||||
&__header-fields{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
.table .thead{
|
||||
.th{
|
||||
border-bottom-color: #eaeaea;
|
||||
border-bottom-color: #D2DDE2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,10 @@
|
||||
padding: 0.6rem 0.5rem;
|
||||
background: #fafafa;
|
||||
font-size: 14px;
|
||||
color: #445165;
|
||||
color: #58667b;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid rgb(224, 224, 224);
|
||||
}
|
||||
|
||||
.sort-icon{
|
||||
width: 0;
|
||||
height: 0;
|
||||
@@ -145,7 +144,7 @@
|
||||
}
|
||||
}
|
||||
.tr:hover .td{
|
||||
background: #fafafa;
|
||||
background: #f3f7fc;
|
||||
}
|
||||
|
||||
.tr.is-context-menu-active .td{
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
|
||||
.Pane.Pane2 {
|
||||
overflow: auto;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.Resizer {
|
||||
|
||||
@@ -19,13 +19,20 @@ $form-check-input-indeterminate-bg-image: url("data:image/svg+xml,<svg xmlns='ht
|
||||
}
|
||||
|
||||
// Form
|
||||
.bp3-label{
|
||||
label.bp3-label{
|
||||
color: #353535;
|
||||
font-weight: 400;
|
||||
|
||||
.required{
|
||||
color: red;
|
||||
}
|
||||
|
||||
.bp3-form-group.bp3-inline &{
|
||||
margin: 0 10px 0 0;
|
||||
line-height: 1.6;
|
||||
padding-top: calc(.3rem + 1px);
|
||||
padding-bottom: calc(.3rem + 1px);
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}-input{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
.dashboard__insider--bill-form{
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.page-form--bill{
|
||||
$self: '.page-form';
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
padding: 0;
|
||||
}
|
||||
#{$self}__primary-section{
|
||||
padding: 30px 22px 0;
|
||||
margin: -20px -20px 14px;
|
||||
padding: 10px 0 0;
|
||||
margin: 0 0 20px;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid #e4e4e4;
|
||||
max-width: 1000px;
|
||||
}
|
||||
|
||||
.bp3-form-group{
|
||||
@@ -41,7 +43,6 @@
|
||||
&:not(:last-child) {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
&.input-group--salutation-list{
|
||||
width: 25%;
|
||||
}
|
||||
@@ -158,8 +159,8 @@
|
||||
}
|
||||
|
||||
#{$self}__floating-actions {
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
margin-left: -40px;
|
||||
margin-right: -40px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
|
||||
|
||||
&__topbar{
|
||||
width: 100%;
|
||||
min-height: 60px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #F2EFEF;
|
||||
|
||||
&-right,
|
||||
@@ -121,7 +121,7 @@
|
||||
|
||||
&,
|
||||
&-group{
|
||||
height: 42px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.#{$ns}-navbar-divider{
|
||||
@@ -138,7 +138,7 @@
|
||||
}
|
||||
&.bp3-minimal:active,
|
||||
&.bp3-minimal.bp3-active{
|
||||
background: rgba(167, 182, 194, 0.12);
|
||||
background: #a7b6c21f;
|
||||
color: #32304a;
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
}
|
||||
}
|
||||
.#{$ns}-icon{
|
||||
color: #2A293D;
|
||||
color: #32304a;
|
||||
margin-right: 7px;
|
||||
}
|
||||
&.#{$ns}-minimal.#{$ns}-intent-danger{
|
||||
@@ -203,7 +203,7 @@
|
||||
|
||||
h1{
|
||||
font-size: 22px;
|
||||
color: #333363;
|
||||
color: #48485c;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
}
|
||||
@@ -233,13 +233,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__hint{
|
||||
display: inline-block;
|
||||
margin-top: 4px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
&__subtitle{
|
||||
|
||||
}
|
||||
&__insider{
|
||||
margin-bottom: 40px;
|
||||
flex: 1 0 0;
|
||||
|
||||
}
|
||||
|
||||
&__offline-badge{
|
||||
@@ -260,6 +264,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-width: 850px;
|
||||
|
||||
&:before{
|
||||
content: "";
|
||||
@@ -279,7 +284,9 @@
|
||||
&__insider{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
flex: 1 0 0;
|
||||
background-color: #FBFBFB;
|
||||
|
||||
> .dashboard__loading-indicator{
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
@@ -313,6 +320,23 @@
|
||||
display: flex;
|
||||
flex: 1 0 0;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
margin: 20px;
|
||||
border: 1px solid #d2dce2;
|
||||
|
||||
.bigcapital-datatable{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 0 0;
|
||||
|
||||
.pagination{
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
&:not(.has-pagination){
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.datatable-empty-status{
|
||||
margin-top: auto;
|
||||
@@ -323,7 +347,6 @@
|
||||
|
||||
&__preferences-topbar{
|
||||
border-bottom: 1px solid #E5E5E5;
|
||||
// height: 70px;
|
||||
height: 65px;
|
||||
padding: 0 0 0 22px;
|
||||
display: flex;
|
||||
@@ -362,6 +385,43 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__card{
|
||||
border: 1px solid #d2dce2;
|
||||
background: #fff;
|
||||
|
||||
&--page{
|
||||
flex: 1 0 0;
|
||||
margin: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&__error-boundary{
|
||||
text-align: center;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
|
||||
h1{
|
||||
font-size: 26px;
|
||||
font-weight: 600;
|
||||
margin: 0px 0 10px;
|
||||
color: #2c3a5d;
|
||||
}
|
||||
|
||||
p{
|
||||
font-size: 16px;
|
||||
color: #1f3255;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.bp3-icon{
|
||||
margin-top: 6px;
|
||||
|
||||
path{
|
||||
fill: #a1afca;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabs--dashboard-views{
|
||||
@@ -408,7 +468,7 @@
|
||||
|
||||
.navbar--dashboard-views{
|
||||
box-shadow: 0 0 0;
|
||||
border-bottom: 1px solid #EAEAEA;
|
||||
border-bottom: 1px solid #d2dce2;
|
||||
}
|
||||
|
||||
.navbar-omnibar{
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
.dashboard__insider--estimate-form{
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.estimate-form {
|
||||
padding-bottom: 30px;
|
||||
display: flex;
|
||||
@@ -185,195 +189,3 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// .estimate-form {
|
||||
// padding-bottom: 30px;
|
||||
// display: flex;
|
||||
// flex-direction: column;
|
||||
|
||||
// .bp3-form-group {
|
||||
// margin: 25px 20px 15px;
|
||||
// width: 100%;
|
||||
// .bp3-label {
|
||||
// font-weight: 500;
|
||||
// font-size: 13px;
|
||||
// color: #444;
|
||||
// width: 130px;
|
||||
// }
|
||||
// .bp3-form-content {
|
||||
// // width: 400px;
|
||||
// width: 45%;
|
||||
// }
|
||||
// }
|
||||
// // .expense-form-footer {
|
||||
// // display: flex;
|
||||
// // padding: 30px 25px 0;
|
||||
// // justify-content: space-between;
|
||||
// // }
|
||||
|
||||
// &__primary-section {
|
||||
// background: #fbfbfb;
|
||||
// }
|
||||
// &__table {
|
||||
// padding: 15px 15px 0;
|
||||
|
||||
// .bp3-form-group {
|
||||
// margin-bottom: 0;
|
||||
// }
|
||||
// .table {
|
||||
// border: 1px dotted rgb(195, 195, 195);
|
||||
// border-bottom: transparent;
|
||||
// border-left: transparent;
|
||||
|
||||
// .th,
|
||||
// .td {
|
||||
// border-left: 1px dotted rgb(195, 195, 195);
|
||||
|
||||
// &.index {
|
||||
// > span,
|
||||
// > div {
|
||||
// text-align: center;
|
||||
// width: 100%;
|
||||
// font-weight: 500;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// .thead {
|
||||
// .tr .th {
|
||||
// padding: 10px 10px;
|
||||
// background-color: #f2f5fa;
|
||||
// font-size: 14px;
|
||||
// font-weight: 500;
|
||||
// color: #333;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .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-form-group .bp3-input,
|
||||
// .form-group--select-list .bp3-button {
|
||||
// border-radius: 3px;
|
||||
// padding-left: 8px;
|
||||
// padding-right: 8px;
|
||||
// }
|
||||
|
||||
// .bp3-form-group:not(.bp3-intent-danger) .bp3-input,
|
||||
// .form-group--select-list:not(.bp3-intent-danger) .bp3-button {
|
||||
// border-color: #e5e5e5;
|
||||
// }
|
||||
|
||||
// &: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 {
|
||||
// .td.amount {
|
||||
// font-weight: bold;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .th {
|
||||
// color: #444;
|
||||
// font-weight: 600;
|
||||
// border-bottom: 1px dotted #666;
|
||||
// }
|
||||
|
||||
// .td {
|
||||
// border-bottom: 1px dotted #999;
|
||||
|
||||
// &.description {
|
||||
// .bp3-form-group {
|
||||
// width: 100%;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// .actions.td {
|
||||
// .bp3-button {
|
||||
// background: transparent;
|
||||
// margin: 0;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// &__floating-footer {
|
||||
// position: fixed;
|
||||
// bottom: 0;
|
||||
// width: 100%;
|
||||
// background: #fff;
|
||||
// padding: 18px 18px;
|
||||
// border-top: 1px solid #ececec;
|
||||
|
||||
// .has-mini-sidebar & {
|
||||
// left: 50px;
|
||||
// }
|
||||
// }
|
||||
// .bp3-button {
|
||||
// &.button--clear-lines {
|
||||
// background-color: #fcefef;
|
||||
// }
|
||||
// }
|
||||
// .button--clear-lines,
|
||||
// .button--new-line {
|
||||
// padding-left: 14px;
|
||||
// padding-right: 14px;
|
||||
// }
|
||||
// .dropzone-container {
|
||||
// margin-top: 0;
|
||||
// align-self: flex-end;
|
||||
// }
|
||||
// .dropzone {
|
||||
// width: 300px;
|
||||
// height: 75px;
|
||||
// }
|
||||
|
||||
// .form-group--description {
|
||||
// .bp3-label {
|
||||
// font-weight: 500;
|
||||
// font-size: 13px;
|
||||
// color: #444;
|
||||
// }
|
||||
// .bp3-form-content {
|
||||
// // width: 280px;
|
||||
// textarea {
|
||||
// width: 450px;
|
||||
// min-height: 75px;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
.dashboard__insider--estimate-form{
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.page-form--estimate{
|
||||
$self: '.page-form';
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
padding-bottom: 80px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
|
||||
&__header {
|
||||
padding: 25px 27px 20px;
|
||||
|
||||
@@ -285,15 +285,18 @@
|
||||
&__list{
|
||||
display: flex;
|
||||
flex-flow: wrap;
|
||||
margin-left: -28px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
&__item{
|
||||
width: 270px;
|
||||
margin-bottom: 40px;
|
||||
margin-left: 28px;
|
||||
border-top: 2px solid #DDD;
|
||||
margin-bottom: 20px;
|
||||
margin-left: 20px;
|
||||
border: 1px solid #d1dee2;
|
||||
border-top: 3px solid #d1dee2;
|
||||
padding-top: 16px;
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
|
||||
.title{
|
||||
font-size: 16px;
|
||||
@@ -303,6 +306,7 @@
|
||||
color: rgb(31, 50, 85);
|
||||
line-height: 1.55;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
.dashboard__insider--invoice-form{
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.page-form--invoice{
|
||||
$self: '.page-form';
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
|
||||
.page-form--item{
|
||||
$self: '.page-form';
|
||||
padding: 20px;
|
||||
@@ -8,9 +7,12 @@
|
||||
padding: 0;
|
||||
}
|
||||
#{$self}__primary-section{
|
||||
padding: 30px 22px 0;
|
||||
margin: -20px -20px 24px;
|
||||
overflow: hidden;
|
||||
padding-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 1px solid #eaeaea;
|
||||
padding-bottom: 5px;
|
||||
max-width: 1000px;
|
||||
}
|
||||
|
||||
#{$self}__body{
|
||||
@@ -65,8 +67,8 @@
|
||||
}
|
||||
|
||||
#{$self}__floating-actions{
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
margin-left: -40px;
|
||||
margin-right: -40px;
|
||||
|
||||
.form-group--active{
|
||||
display: inline-block;
|
||||
|
||||
@@ -58,4 +58,11 @@
|
||||
min-width: 75px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard__insider{
|
||||
|
||||
&--make-journal-page{
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,13 @@
|
||||
}
|
||||
|
||||
.tbody{
|
||||
.amount > span{
|
||||
font-weight: 600;
|
||||
.td.amount{
|
||||
.bp3-popover-target{
|
||||
border-bottom: 1px solid #e7e7e7;
|
||||
}
|
||||
> span{
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
.note{
|
||||
.bp3-icon{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
.dashboard__insider--payment-made{
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.page-form--payment-made {
|
||||
$self: '.page-form';
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
|
||||
.dashboard__insider--payment-receive-form{
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.page-form--payment-receive {
|
||||
$self: '.page-form';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
.dashboard__insider--receipt-form{
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.page-form--receipt{
|
||||
$self: '.page-form';
|
||||
|
||||
@@ -107,7 +107,7 @@ $sidebar-submenu-item-bg-color: #01287d;
|
||||
padding-top: 6px;
|
||||
}
|
||||
.#{$ns}-menu-item {
|
||||
padding: 7px 16px;
|
||||
padding: 8px 16px;
|
||||
font-size: 15px;
|
||||
color: $sidebar-submenu-item-color;
|
||||
|
||||
|
||||
@@ -198,7 +198,11 @@ export default class AccountsController extends BaseController{
|
||||
|
||||
try {
|
||||
const account = await this.accountsService.editAccount(tenantId, accountId, accountDTO);
|
||||
return res.status(200).send({ id: account.id });
|
||||
|
||||
return res.status(200).send({
|
||||
id: account.id,
|
||||
message: 'The account has been edited successfully',
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
@@ -107,10 +107,12 @@ export default class AccountRepository extends TenantRepository {
|
||||
* @param {IAccount} account
|
||||
* @return {void}
|
||||
*/
|
||||
async edit(accountId: number, account: IAccount): Promise<void> {
|
||||
async edit(accountId: number, accountInput: IAccount): Promise<void> {
|
||||
const { Account } = this.models;
|
||||
await Account.query().findById(accountId).patch({ ...account });
|
||||
const account = await Account.query().patchAndFetchById(accountId, { ...accountInput });
|
||||
this.flushCache();
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -203,6 +203,8 @@ export default class AccountsService {
|
||||
* @param {IAccountDTO} accountDTO
|
||||
*/
|
||||
public async editAccount(tenantId: number, accountId: number, accountDTO: IAccountDTO) {
|
||||
this.logger.info('[account] trying to edit account.', { tenantId, accountId });
|
||||
|
||||
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
const oldAccount = await this.getAccountOrThrowError(tenantId, accountId);
|
||||
|
||||
|
||||
@@ -407,6 +407,7 @@ export default class ManualJournalsService implements IManualJournalsService {
|
||||
this.logger.info('[manual_journals] trying to get manual journals list.', { tenantId, filter });
|
||||
const { results, pagination } = await ManualJournal.query().onBuild((builder) => {
|
||||
dynamicList.buildQuery()(builder);
|
||||
builder.withGraphFetched('entries.account');
|
||||
}).pagination(filter.page - 1, filter.pageSize);
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user