mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 23:00:34 +00:00
feat: style bill form.
feat: add row and column of grid components.
This commit is contained in:
@@ -41,6 +41,7 @@
|
|||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flexboxgrid/6.3.1/flexboxgrid.min.css" type="text/css" >
|
||||||
<!-- <link href="https://cdn.syncfusion.com/ej2/material.css" rel="stylesheet"> -->
|
<!-- <link href="https://cdn.syncfusion.com/ej2/material.css" rel="stylesheet"> -->
|
||||||
<!-- <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" /> -->
|
<!-- <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" /> -->
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,6 +1,17 @@
|
|||||||
|
import { Classes } from '@blueprintjs/core';
|
||||||
|
|
||||||
const CLASSES = {
|
const CLASSES = {
|
||||||
DATATABLE_EDITOR: 'DATATABLE_EDITOR'
|
DATATABLE_EDITOR: 'DATATABLE_EDITOR',
|
||||||
|
|
||||||
|
PAGE_FORM: 'page-form',
|
||||||
|
PAGE_FORM_HEADER: 'page-form__header',
|
||||||
|
PAGE_FORM_FOOTER: 'page-form__footer',
|
||||||
|
PAGE_FORM_FLOATING_ACTIONS: 'page-form__floating-action',
|
||||||
|
|
||||||
|
PAGE_FORM_BILL: 'page-form--bill',
|
||||||
|
PAGE_FORM_ESTIMATE: 'page-form--estimate',
|
||||||
|
|
||||||
|
...Classes,
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import React, { useCallback, useMemo, useEffect, useState } from 'react';
|
import React, { useCallback, useMemo, useEffect, useState } from 'react';
|
||||||
import { MenuItem } from '@blueprintjs/core';
|
import { MenuItem } from '@blueprintjs/core';
|
||||||
import ListSelect from 'components/ListSelect';
|
import ListSelect from 'components/ListSelect';
|
||||||
import { FormattedMessage as T } from 'react-intl';
|
|
||||||
|
|
||||||
function EstimateListField({
|
function EstimateListField({
|
||||||
products,
|
products,
|
||||||
initialProductId,
|
initialProductId,
|
||||||
selectedProductId,
|
selectedProductId,
|
||||||
defautlSelectText = <T id={'select_product'} />,
|
defautlSelectText = 'Click to select an item.',
|
||||||
onProductSelected,
|
onProductSelected,
|
||||||
}) {
|
}) {
|
||||||
const initialProduct = useMemo(
|
const initialProduct = useMemo(
|
||||||
|
|||||||
113
client/src/components/Grid/Col.js
Normal file
113
client/src/components/Grid/Col.js
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const DEVICE_SIZES = ['xl', 'lg', 'md', 'sm', 'xs'];
|
||||||
|
const rowColWidth = PropTypes.oneOfType([PropTypes.number, PropTypes.string]);
|
||||||
|
|
||||||
|
const rowColumns = PropTypes.oneOfType([
|
||||||
|
rowColWidth,
|
||||||
|
PropTypes.shape({
|
||||||
|
cols: rowColWidth,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
/**
|
||||||
|
* @default 'row'
|
||||||
|
*/
|
||||||
|
bsPrefix: PropTypes.string,
|
||||||
|
|
||||||
|
/** Removes the gutter spacing between `Col`s as well as any added negative margins. */
|
||||||
|
noGutters: PropTypes.bool.isRequired,
|
||||||
|
as: PropTypes.elementType,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of columns that will fit next to each other on extra small devices (<576px)
|
||||||
|
*
|
||||||
|
* @type {(number|{ cols: number })}
|
||||||
|
*/
|
||||||
|
xs: rowColumns,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of columns that will fit next to each other on small devices (≥576px)
|
||||||
|
*
|
||||||
|
* @type {(number|{ cols: number })}
|
||||||
|
*/
|
||||||
|
sm: rowColumns,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of columns that will fit next to each other on medium devices (≥768px)
|
||||||
|
*
|
||||||
|
* @type {(number|{ cols: number })}
|
||||||
|
*/
|
||||||
|
md: rowColumns,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of columns that will fit next to each other on large devices (≥992px)
|
||||||
|
*
|
||||||
|
* @type {(number|{ cols: number })}
|
||||||
|
*/
|
||||||
|
lg: rowColumns,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of columns that will fit next to each other on extra large devices (≥1200px)
|
||||||
|
*
|
||||||
|
* @type {(number|{ cols: number })}
|
||||||
|
*/
|
||||||
|
xl: rowColumns,
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
noGutters: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function Row ({
|
||||||
|
bsPrefix,
|
||||||
|
className,
|
||||||
|
noGutters,
|
||||||
|
// Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
|
||||||
|
as: Component = 'div',
|
||||||
|
...props
|
||||||
|
}) {
|
||||||
|
const decoratedBsPrefix = '';
|
||||||
|
const sizePrefix = `col`;
|
||||||
|
const classes = [];
|
||||||
|
|
||||||
|
DEVICE_SIZES.forEach((brkPoint) => {
|
||||||
|
const propValue = props[brkPoint];
|
||||||
|
delete props[brkPoint];
|
||||||
|
|
||||||
|
let cols;
|
||||||
|
if (propValue != null && typeof propValue === 'object') {
|
||||||
|
({ cols } = propValue);
|
||||||
|
} else {
|
||||||
|
cols = propValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const infix = brkPoint !== 'xs' ? `-${brkPoint}` : '';
|
||||||
|
|
||||||
|
if (cols != null) classes.push(`${sizePrefix}${infix}-${cols}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Component
|
||||||
|
{...props}
|
||||||
|
className={classNames(
|
||||||
|
'col',
|
||||||
|
className,
|
||||||
|
decoratedBsPrefix,
|
||||||
|
noGutters && 'no-gutters',
|
||||||
|
...classes,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Row.displayName = 'Row';
|
||||||
|
Row.propTypes = propTypes;
|
||||||
|
Row.defaultProps = defaultProps;
|
||||||
|
|
||||||
|
export default Row;
|
||||||
111
client/src/components/Grid/Row.js
Normal file
111
client/src/components/Grid/Row.js
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const DEVICE_SIZES = ['xl', 'lg', 'md', 'sm', 'xs'];
|
||||||
|
const rowColWidth = PropTypes.oneOfType([PropTypes.number, PropTypes.string]);
|
||||||
|
|
||||||
|
const rowColumns = PropTypes.oneOfType([
|
||||||
|
rowColWidth,
|
||||||
|
PropTypes.shape({
|
||||||
|
cols: rowColWidth,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
/**
|
||||||
|
* @default 'row'
|
||||||
|
*/
|
||||||
|
bsPrefix: PropTypes.string,
|
||||||
|
|
||||||
|
/** Removes the gutter spacing between `Col`s as well as any added negative margins. */
|
||||||
|
noGutters: PropTypes.bool.isRequired,
|
||||||
|
as: PropTypes.elementType,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of columns that will fit next to each other on extra small devices (<576px)
|
||||||
|
*
|
||||||
|
* @type {(number|{ cols: number })}
|
||||||
|
*/
|
||||||
|
xs: rowColumns,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of columns that will fit next to each other on small devices (≥576px)
|
||||||
|
*
|
||||||
|
* @type {(number|{ cols: number })}
|
||||||
|
*/
|
||||||
|
sm: rowColumns,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of columns that will fit next to each other on medium devices (≥768px)
|
||||||
|
*
|
||||||
|
* @type {(number|{ cols: number })}
|
||||||
|
*/
|
||||||
|
md: rowColumns,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of columns that will fit next to each other on large devices (≥992px)
|
||||||
|
*
|
||||||
|
* @type {(number|{ cols: number })}
|
||||||
|
*/
|
||||||
|
lg: rowColumns,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of columns that will fit next to each other on extra large devices (≥1200px)
|
||||||
|
*
|
||||||
|
* @type {(number|{ cols: number })}
|
||||||
|
*/
|
||||||
|
xl: rowColumns,
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
noGutters: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
function Row ({
|
||||||
|
bsPrefix,
|
||||||
|
className,
|
||||||
|
noGutters,
|
||||||
|
// Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
|
||||||
|
as: Component = 'div',
|
||||||
|
...props
|
||||||
|
}) {
|
||||||
|
const decoratedBsPrefix = 'row';
|
||||||
|
const sizePrefix = `${decoratedBsPrefix}-cols`;
|
||||||
|
const classes = [];
|
||||||
|
|
||||||
|
DEVICE_SIZES.forEach((brkPoint) => {
|
||||||
|
const propValue = props[brkPoint];
|
||||||
|
delete props[brkPoint];
|
||||||
|
|
||||||
|
let cols;
|
||||||
|
if (propValue != null && typeof propValue === 'object') {
|
||||||
|
({ cols } = propValue);
|
||||||
|
} else {
|
||||||
|
cols = propValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const infix = brkPoint !== 'xs' ? `-${brkPoint}` : '';
|
||||||
|
|
||||||
|
if (cols != null) classes.push(`${sizePrefix}${infix}-${cols}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Component
|
||||||
|
{...props}
|
||||||
|
className={classNames(
|
||||||
|
className,
|
||||||
|
decoratedBsPrefix,
|
||||||
|
noGutters && 'no-gutters',
|
||||||
|
...classes,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Row.displayName = 'Row';
|
||||||
|
Row.propTypes = propTypes;
|
||||||
|
Row.defaultProps = defaultProps;
|
||||||
|
|
||||||
|
export default Row;
|
||||||
@@ -26,6 +26,8 @@ import DialogContent from './Dialog/DialogContent';
|
|||||||
import DialogSuspense from './Dialog/DialogSuspense';
|
import DialogSuspense from './Dialog/DialogSuspense';
|
||||||
import InputPrependButton from './Forms/InputPrependButton';
|
import InputPrependButton from './Forms/InputPrependButton';
|
||||||
import CategoriesSelectList from './CategoriesSelectList';
|
import CategoriesSelectList from './CategoriesSelectList';
|
||||||
|
import Row from './Grid/Row';
|
||||||
|
import Col from './Grid/Col';
|
||||||
|
|
||||||
const Hint = FieldHint;
|
const Hint = FieldHint;
|
||||||
|
|
||||||
@@ -58,5 +60,7 @@ export {
|
|||||||
DialogContent,
|
DialogContent,
|
||||||
DialogSuspense,
|
DialogSuspense,
|
||||||
InputPrependButton,
|
InputPrependButton,
|
||||||
CategoriesSelectList
|
CategoriesSelectList,
|
||||||
|
Col,
|
||||||
|
Row,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -456,8 +456,8 @@ export default compose(
|
|||||||
withDashboardActions,
|
withDashboardActions,
|
||||||
withMediaActions,
|
withMediaActions,
|
||||||
withSettings(({ manualJournalsSettings }) => ({
|
withSettings(({ manualJournalsSettings }) => ({
|
||||||
journalNextNumber: manualJournalsSettings.next_number,
|
journalNextNumber: manualJournalsSettings.nextNumber,
|
||||||
journalNumberPrefix: manualJournalsSettings.number_prefix
|
journalNumberPrefix: manualJournalsSettings.numberPrefix
|
||||||
})),
|
})),
|
||||||
withManualJournalsActions,
|
withManualJournalsActions,
|
||||||
)(MakeJournalEntriesForm);
|
)(MakeJournalEntriesForm);
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ function AccountNameAccessor(row) {
|
|||||||
|
|
||||||
<If condition={!row.active}>
|
<If condition={!row.active}>
|
||||||
<InactiveSemafro />
|
<InactiveSemafro />
|
||||||
</If>
|
</If>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -270,7 +270,7 @@ function AccountsDataTable({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const selectionColumn = useMemo(
|
const selectionColumn = useMemo(
|
||||||
() => ({ minWidth: 45, width: 45, maxWidth: 45 }),
|
() => ({ minWidth: 40, width: 40, maxWidth: 40 }),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -342,10 +342,6 @@ function ExpenseForm({
|
|||||||
category.amount && category.index && category.expense_account_id,
|
category.amount && category.index && category.expense_account_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(categories, 'V');
|
|
||||||
|
|
||||||
console.log(formik.errors, 'Error');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'expense-form'}>
|
<div className={'expense-form'}>
|
||||||
<form onSubmit={formik.handleSubmit}>
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ import * as Yup from 'yup';
|
|||||||
import { useFormik } from 'formik';
|
import { useFormik } from 'formik';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { Intent, FormGroup, TextArea } from '@blueprintjs/core';
|
import { Intent, FormGroup, TextArea } from '@blueprintjs/core';
|
||||||
import { Row, Col } from 'react-grid-system';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
|
import { CLASSES } from 'common/classes';
|
||||||
import BillFormHeader from './BillFormHeader';
|
import BillFormHeader from './BillFormHeader';
|
||||||
import EstimatesItemsTable from 'containers/Sales/Estimate/EntriesItemsTable';
|
import EstimatesItemsTable from 'containers/Sales/Estimate/EntriesItemsTable';
|
||||||
import BillFormFooter from './BillFormFooter';
|
import BillFormFooter from './BillFormFooter';
|
||||||
@@ -25,7 +24,7 @@ import withBillActions from './withBillActions';
|
|||||||
import withBillDetail from './withBillDetail';
|
import withBillDetail from './withBillDetail';
|
||||||
import withSettings from 'containers/Settings/withSettings';
|
import withSettings from 'containers/Settings/withSettings';
|
||||||
|
|
||||||
import { AppToaster } from 'components';
|
import { AppToaster, Row, Col } from 'components';
|
||||||
import Dragzone from 'components/Dragzone';
|
import Dragzone from 'components/Dragzone';
|
||||||
import useMedia from 'hooks/useMedia';
|
import useMedia from 'hooks/useMedia';
|
||||||
|
|
||||||
@@ -306,34 +305,40 @@ function BillForm({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className={'bill-form'}>
|
<div className={classNames(
|
||||||
|
CLASSES.PAGE_FORM,
|
||||||
|
CLASSES.PAGE_FORM_BILL,
|
||||||
|
)}>
|
||||||
<form onSubmit={formik.handleSubmit}>
|
<form onSubmit={formik.handleSubmit}>
|
||||||
<BillFormHeader formik={formik} />
|
<BillFormHeader formik={formik} />
|
||||||
|
|
||||||
<EstimatesItemsTable
|
<EstimatesItemsTable
|
||||||
formik={formik}
|
formik={formik}
|
||||||
entries={formik.values.entries}
|
entries={formik.values.entries}
|
||||||
onClickAddNewRow={onClickAddNewRow}
|
onClickAddNewRow={onClickAddNewRow}
|
||||||
onClickClearAllLines={onClickCleanAllLines}
|
onClickClearAllLines={onClickCleanAllLines}
|
||||||
/>
|
/>
|
||||||
<Row>
|
<div class="page-form__footer">
|
||||||
<Col>
|
<Row>
|
||||||
<FormGroup label={<T id={'note'} />} className={'form-group--'}>
|
<Col md={8}>
|
||||||
<TextArea
|
<FormGroup label={<T id={'note'} />} className={'form-group--note'}>
|
||||||
growVertically={true}
|
<TextArea
|
||||||
{...formik.getFieldProps('note')}
|
growVertically={true}
|
||||||
/>
|
{...formik.getFieldProps('note')}
|
||||||
</FormGroup>
|
/>
|
||||||
</Col>
|
</FormGroup>
|
||||||
|
</Col>
|
||||||
|
|
||||||
<Col>
|
<Col md={4}>
|
||||||
<Dragzone
|
<Dragzone
|
||||||
initialFiles={initialAttachmentFiles}
|
initialFiles={initialAttachmentFiles}
|
||||||
onDrop={handleDropFiles}
|
onDrop={handleDropFiles}
|
||||||
onDeleteFile={handleDeleteFile}
|
onDeleteFile={handleDeleteFile}
|
||||||
hint={'Attachments: Maxiumum size: 20MB'}
|
hint={'Attachments: Maxiumum size: 20MB'}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<BillFormFooter
|
<BillFormFooter
|
||||||
formik={formik}
|
formik={formik}
|
||||||
|
|||||||
@@ -1,24 +1,23 @@
|
|||||||
import React, { useMemo, useCallback, useState } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import {
|
import {
|
||||||
FormGroup,
|
FormGroup,
|
||||||
InputGroup,
|
InputGroup,
|
||||||
Intent,
|
Intent,
|
||||||
Position,
|
Position,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Classes,
|
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { DateInput } from '@blueprintjs/datetime';
|
import { DateInput } from '@blueprintjs/datetime';
|
||||||
import { FormattedMessage as T } from 'react-intl';
|
import { FormattedMessage as T } from 'react-intl';
|
||||||
import { Row, Col } from 'react-grid-system';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { momentFormatter, compose, tansformDateValue } from 'utils';
|
import { momentFormatter, compose, tansformDateValue } from 'utils';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { CLASSES } from 'common/classes';
|
||||||
import {
|
import {
|
||||||
ListSelect,
|
ListSelect,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
FieldRequiredHint,
|
FieldRequiredHint,
|
||||||
Icon,
|
Row,
|
||||||
InputPrependButton,
|
Col,
|
||||||
} from 'components';
|
} from 'components';
|
||||||
|
|
||||||
// import withCustomers from 'containers/Customers/withCustomers';
|
// import withCustomers from 'containers/Customers/withCustomers';
|
||||||
@@ -30,13 +29,7 @@ function BillFormHeader({
|
|||||||
formik: { errors, touched, setFieldValue, getFieldProps, values },
|
formik: { errors, touched, setFieldValue, getFieldProps, values },
|
||||||
|
|
||||||
//#withVendors
|
//#withVendors
|
||||||
vendorsCurrentPage,
|
|
||||||
vendorItems,
|
vendorItems,
|
||||||
//#withAccouts
|
|
||||||
accountsList,
|
|
||||||
|
|
||||||
// #withDialog
|
|
||||||
openDialog,
|
|
||||||
}) {
|
}) {
|
||||||
const handleDateChange = useCallback(
|
const handleDateChange = useCallback(
|
||||||
(date_filed) => (date) => {
|
(date_filed) => (date) => {
|
||||||
@@ -80,18 +73,18 @@ function BillFormHeader({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBillNumberChange = useCallback(() => {
|
|
||||||
openDialog('bill-number-form', {});
|
|
||||||
}, [openDialog]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page-form page-form--bill">
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
||||||
<div className={'page-form__primary-section'}>
|
<div className={'page-form__primary-section'}>
|
||||||
{/* Vendor account name */}
|
{/* Vendor name */}
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'vendor_name'} />}
|
label={<T id={'vendor_name'} />}
|
||||||
inline={true}
|
inline={true}
|
||||||
className={classNames('form-group--select-list', Classes.FILL)}
|
className={classNames(
|
||||||
|
'form-group--select-list',
|
||||||
|
'form-group--vendor',
|
||||||
|
CLASSES.FILL,
|
||||||
|
)}
|
||||||
labelInfo={<FieldRequiredHint />}
|
labelInfo={<FieldRequiredHint />}
|
||||||
intent={errors.vendor_id && touched.vendor_id && Intent.DANGER}
|
intent={errors.vendor_id && touched.vendor_id && Intent.DANGER}
|
||||||
helperText={
|
helperText={
|
||||||
@@ -111,13 +104,15 @@ function BillFormHeader({
|
|||||||
labelProp={'display_name'}
|
labelProp={'display_name'}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<Row>
|
|
||||||
<Col>
|
<Row className={'row--bill-date'}>
|
||||||
|
<Col md={7}>
|
||||||
|
{/* Bill date */}
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'bill_date'} />}
|
label={<T id={'bill_date'} />}
|
||||||
inline={true}
|
inline={true}
|
||||||
labelInfo={<FieldRequiredHint />}
|
labelInfo={<FieldRequiredHint />}
|
||||||
className={classNames('form-group--select-list', Classes.FILL)}
|
className={classNames('form-group--select-list', CLASSES.FILL)}
|
||||||
intent={errors.bill_date && touched.bill_date && Intent.DANGER}
|
intent={errors.bill_date && touched.bill_date && Intent.DANGER}
|
||||||
helperText={
|
helperText={
|
||||||
<ErrorMessage name="bill_date" {...{ errors, touched }} />
|
<ErrorMessage name="bill_date" {...{ errors, touched }} />
|
||||||
@@ -131,11 +126,17 @@ function BillFormHeader({
|
|||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
<Col>
|
|
||||||
|
<Col md={5}>
|
||||||
|
{/* Due date */}
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'due_date'} />}
|
label={<T id={'due_date'} />}
|
||||||
inline={true}
|
inline={true}
|
||||||
className={classNames('form-group--select-list', Classes.FILL)}
|
className={classNames(
|
||||||
|
'form-group--due-date',
|
||||||
|
'form-group--select-list',
|
||||||
|
CLASSES.FILL
|
||||||
|
)}
|
||||||
intent={errors.due_date && touched.due_date && Intent.DANGER}
|
intent={errors.due_date && touched.due_date && Intent.DANGER}
|
||||||
helperText={
|
helperText={
|
||||||
<ErrorMessage name="due_date" {...{ errors, touched }} />
|
<ErrorMessage name="due_date" {...{ errors, touched }} />
|
||||||
@@ -150,12 +151,12 @@ function BillFormHeader({
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{/* bill number */}
|
|
||||||
|
{/* Bill number */}
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'bill_number'} />}
|
label={<T id={'bill_number'} />}
|
||||||
inline={true}
|
inline={true}
|
||||||
className={('form-group--bill_number', Classes.FILL)}
|
className={('form-group--bill_number', CLASSES.FILL)}
|
||||||
labelInfo={<FieldRequiredHint />}
|
|
||||||
intent={errors.bill_number && touched.bill_number && Intent.DANGER}
|
intent={errors.bill_number && touched.bill_number && Intent.DANGER}
|
||||||
helperText={
|
helperText={
|
||||||
<ErrorMessage name="bill_number" {...{ errors, touched }} />
|
<ErrorMessage name="bill_number" {...{ errors, touched }} />
|
||||||
@@ -164,43 +165,35 @@ function BillFormHeader({
|
|||||||
<InputGroup
|
<InputGroup
|
||||||
intent={errors.bill_number && touched.bill_number && Intent.DANGER}
|
intent={errors.bill_number && touched.bill_number && Intent.DANGER}
|
||||||
minimal={true}
|
minimal={true}
|
||||||
rightElement={
|
|
||||||
<InputPrependButton
|
|
||||||
buttonProps={{
|
|
||||||
onClick: handleBillNumberChange,
|
|
||||||
icon: <Icon icon={'settings-18'} />,
|
|
||||||
}}
|
|
||||||
tooltip={true}
|
|
||||||
tooltipProps={{
|
|
||||||
content: 'Setting your auto-generated bill number',
|
|
||||||
position: Position.BOTTOM_LEFT,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{...getFieldProps('bill_number')}
|
{...getFieldProps('bill_number')}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</div>
|
|
||||||
<FormGroup
|
{/* Reference */}
|
||||||
label={<T id={'reference'} />}
|
<FormGroup
|
||||||
inline={true}
|
label={<T id={'reference'} />}
|
||||||
className={classNames('form-group--reference', Classes.FILL)}
|
inline={true}
|
||||||
intent={errors.reference_no && touched.reference_no && Intent.DANGER}
|
className={classNames('form-group--reference', CLASSES.FILL)}
|
||||||
helperText={<ErrorMessage name="reference" {...{ errors, touched }} />}
|
|
||||||
>
|
|
||||||
<InputGroup
|
|
||||||
intent={errors.reference_no && touched.reference_no && Intent.DANGER}
|
intent={errors.reference_no && touched.reference_no && Intent.DANGER}
|
||||||
minimal={true}
|
helperText={
|
||||||
{...getFieldProps('reference_no')}
|
<ErrorMessage name="reference" {...{ errors, touched }} />
|
||||||
/>
|
}
|
||||||
</FormGroup>
|
>
|
||||||
|
<InputGroup
|
||||||
|
intent={
|
||||||
|
errors.reference_no && touched.reference_no && Intent.DANGER
|
||||||
|
}
|
||||||
|
minimal={true}
|
||||||
|
{...getFieldProps('reference_no')}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
withVendors(({ vendorsCurrentPage, vendorItems }) => ({
|
withVendors(({ vendorItems }) => ({
|
||||||
vendorsCurrentPage,
|
|
||||||
vendorItems,
|
vendorItems,
|
||||||
})),
|
})),
|
||||||
withAccounts(({ accountsList }) => ({
|
withAccounts(({ accountsList }) => ({
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { Button, Intent, Position, Tooltip } from '@blueprintjs/core';
|
|||||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { CLASSES } from 'common/classes';
|
import { CLASSES } from 'common/classes';
|
||||||
|
import { Hint, Icon } from 'components';
|
||||||
import DataTable from 'components/DataTable';
|
import DataTable from 'components/DataTable';
|
||||||
import Icon from 'components/Icon';
|
|
||||||
import {
|
import {
|
||||||
InputGroupCell,
|
InputGroupCell,
|
||||||
MoneyFieldCell,
|
MoneyFieldCell,
|
||||||
@@ -66,6 +66,15 @@ const CellRenderer = (content, type) => (props) => {
|
|||||||
return content(props);
|
return content(props);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ItemHeaderCell = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<T id={'product_and_service'} />
|
||||||
|
<Hint />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
function EstimateTable({
|
function EstimateTable({
|
||||||
//#withitems
|
//#withitems
|
||||||
itemsCurrentPage,
|
itemsCurrentPage,
|
||||||
@@ -96,13 +105,12 @@ function EstimateTable({
|
|||||||
className: 'index',
|
className: 'index',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: formatMessage({ id: 'product_and_service' }),
|
Header: ItemHeaderCell,
|
||||||
id: 'item_id',
|
id: 'item_id',
|
||||||
accessor: 'item_id',
|
accessor: 'item_id',
|
||||||
Cell: EstimatesListFieldCell,
|
Cell: EstimatesListFieldCell,
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
disableResizing: true,
|
width: 180,
|
||||||
width: 250,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: formatMessage({ id: 'description' }),
|
Header: formatMessage({ id: 'description' }),
|
||||||
@@ -110,7 +118,7 @@ function EstimateTable({
|
|||||||
Cell: InputGroupCell,
|
Cell: InputGroupCell,
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
className: 'description',
|
className: 'description',
|
||||||
width: 120,
|
width: 100,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -118,7 +126,7 @@ function EstimateTable({
|
|||||||
accessor: 'quantity',
|
accessor: 'quantity',
|
||||||
Cell: CellRenderer(InputGroupCell, 'quantity'),
|
Cell: CellRenderer(InputGroupCell, 'quantity'),
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
width: 100,
|
width: 80,
|
||||||
className: 'quantity',
|
className: 'quantity',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -126,7 +134,7 @@ function EstimateTable({
|
|||||||
accessor: 'rate',
|
accessor: 'rate',
|
||||||
Cell: TotalEstimateCellRederer(MoneyFieldCell, 'rate'),
|
Cell: TotalEstimateCellRederer(MoneyFieldCell, 'rate'),
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
width: 100,
|
width: 80,
|
||||||
className: 'rate',
|
className: 'rate',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -134,8 +142,7 @@ function EstimateTable({
|
|||||||
accessor: 'discount',
|
accessor: 'discount',
|
||||||
Cell: CellRenderer(PercentFieldCell, InputGroupCell),
|
Cell: CellRenderer(PercentFieldCell, InputGroupCell),
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
disableResizing: true,
|
width: 80,
|
||||||
width: 100,
|
|
||||||
className: 'discount',
|
className: 'discount',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -144,7 +151,7 @@ function EstimateTable({
|
|||||||
calculateDiscount(row.discount, row.quantity, row.rate),
|
calculateDiscount(row.discount, row.quantity, row.rate),
|
||||||
Cell: TotalEstimateCellRederer(DivFieldCell, 'total'),
|
Cell: TotalEstimateCellRederer(DivFieldCell, 'total'),
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
width: 150,
|
width: 120,
|
||||||
className: 'total',
|
className: 'total',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -222,7 +229,7 @@ function EstimateTable({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'estimate-form__table'}>
|
<div className={'estimate-form__table datatable-editor'}>
|
||||||
<DataTable
|
<DataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={rows}
|
data={rows}
|
||||||
@@ -235,7 +242,7 @@ function EstimateTable({
|
|||||||
}}
|
}}
|
||||||
className={CLASSES.DATATABLE_EDITOR}
|
className={CLASSES.DATATABLE_EDITOR}
|
||||||
/>
|
/>
|
||||||
<div className={'datatable-editor-actions mt1'}>
|
<div className={'datatable-editor__actions mt1'}>
|
||||||
<Button
|
<Button
|
||||||
small={true}
|
small={true}
|
||||||
className={'button--secondary button--new-line'}
|
className={'button--secondary button--new-line'}
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ import moment from 'moment';
|
|||||||
import { Intent, FormGroup, TextArea } from '@blueprintjs/core';
|
import { Intent, FormGroup, TextArea } from '@blueprintjs/core';
|
||||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
import { Row, Col } from 'react-grid-system';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { CLASSES } from 'common/classes';
|
||||||
import EstimateFormHeader from './EstimateFormHeader';
|
import EstimateFormHeader from './EstimateFormHeader';
|
||||||
import EstimatesItemsTable from './EntriesItemsTable';
|
import EstimatesItemsTable from './EntriesItemsTable';
|
||||||
import EstimateFormFooter from './EstimateFormFooter';
|
import EstimateFormFooter from './EstimateFormFooter';
|
||||||
@@ -23,7 +24,7 @@ import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
|||||||
import withMediaActions from 'containers/Media/withMediaActions';
|
import withMediaActions from 'containers/Media/withMediaActions';
|
||||||
import withSettings from 'containers/Settings/withSettings';
|
import withSettings from 'containers/Settings/withSettings';
|
||||||
|
|
||||||
import AppToaster from 'components/AppToaster';
|
import { AppToaster, Row, Col } from 'components';
|
||||||
import Dragzone from 'components/Dragzone';
|
import Dragzone from 'components/Dragzone';
|
||||||
import useMedia from 'hooks/useMedia';
|
import useMedia from 'hooks/useMedia';
|
||||||
|
|
||||||
@@ -301,7 +302,10 @@ const EstimateForm = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={classNames(
|
||||||
|
CLASSES.PAGE_FORM,
|
||||||
|
CLASSES.PAGE_FORM_ESTIMATE,
|
||||||
|
)}>
|
||||||
<form onSubmit={formik.handleSubmit}>
|
<form onSubmit={formik.handleSubmit}>
|
||||||
<EstimateFormHeader formik={formik} />
|
<EstimateFormHeader formik={formik} />
|
||||||
<EstimatesItemsTable
|
<EstimatesItemsTable
|
||||||
@@ -311,37 +315,39 @@ const EstimateForm = ({
|
|||||||
formik={formik}
|
formik={formik}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Row>
|
<div class={classNames(CLASSES.PAGE_FORM_FOOTER)}>
|
||||||
<Col>
|
<Row>
|
||||||
<FormGroup
|
<Col md={7}>
|
||||||
label={<T id={'customer_note'} />}
|
<FormGroup
|
||||||
className={'form-group--customer_note'}
|
label={<T id={'customer_note'} />}
|
||||||
>
|
className={'form-group--customer_note'}
|
||||||
<TextArea
|
>
|
||||||
growVertically={true}
|
<TextArea
|
||||||
{...formik.getFieldProps('note')}
|
growVertically={true}
|
||||||
|
{...formik.getFieldProps('note')}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={<T id={'terms_conditions'} />}
|
||||||
|
className={'form-group--terms_conditions'}
|
||||||
|
>
|
||||||
|
<TextArea
|
||||||
|
growVertically={true}
|
||||||
|
{...formik.getFieldProps('terms_conditions')}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col md={5}>
|
||||||
|
<Dragzone
|
||||||
|
initialFiles={initialAttachmentFiles}
|
||||||
|
onDrop={handleDropFiles}
|
||||||
|
onDeleteFile={handleDeleteFile}
|
||||||
|
hint={'Attachments: Maxiumum size: 20MB'}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</Col>
|
||||||
<FormGroup
|
</Row>
|
||||||
label={<T id={'terms_conditions'} />}
|
</div>
|
||||||
className={'form-group--terms_conditions'}
|
|
||||||
>
|
|
||||||
<TextArea
|
|
||||||
growVertically={true}
|
|
||||||
{...formik.getFieldProps('terms_conditions')}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
<Col>
|
|
||||||
<Dragzone
|
|
||||||
initialFiles={initialAttachmentFiles}
|
|
||||||
onDrop={handleDropFiles}
|
|
||||||
onDeleteFile={handleDeleteFile}
|
|
||||||
hint={'Attachments: Maxiumum size: 20MB'}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</form>
|
</form>
|
||||||
<EstimateFormFooter
|
<EstimateFormFooter
|
||||||
formik={formik}
|
formik={formik}
|
||||||
|
|||||||
@@ -9,16 +9,18 @@ import {
|
|||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { DateInput } from '@blueprintjs/datetime';
|
import { DateInput } from '@blueprintjs/datetime';
|
||||||
import { FormattedMessage as T } from 'react-intl';
|
import { FormattedMessage as T } from 'react-intl';
|
||||||
import { Row, Col } from 'react-grid-system';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { momentFormatter, compose, tansformDateValue } from 'utils';
|
import { momentFormatter, compose, tansformDateValue } from 'utils';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { CLASSES } from 'common/classes';
|
||||||
import {
|
import {
|
||||||
ListSelect,
|
ListSelect,
|
||||||
ErrorMessage,
|
ErrorMessage,
|
||||||
FieldRequiredHint,
|
FieldRequiredHint,
|
||||||
Icon,
|
Icon,
|
||||||
InputPrependButton,
|
InputPrependButton,
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
} from 'components';
|
} from 'components';
|
||||||
|
|
||||||
import withCustomers from 'containers/Customers/withCustomers';
|
import withCustomers from 'containers/Customers/withCustomers';
|
||||||
@@ -81,7 +83,7 @@ function EstimateFormHeader({
|
|||||||
}, [openDialog]);
|
}, [openDialog]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'page-form page-form--estimate'}>
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
||||||
<div className={'page-form__primary-section'}>
|
<div className={'page-form__primary-section'}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'customer_name'} />}
|
label={<T id={'customer_name'} />}
|
||||||
@@ -112,15 +114,15 @@ function EstimateFormHeader({
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col md={8} className={'col--estimate-date'}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'estimate_date'} />}
|
label={<T id={'estimate_date'} />}
|
||||||
inline={true}
|
inline={true}
|
||||||
labelInfo={<FieldRequiredHint />}
|
labelInfo={<FieldRequiredHint />}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'form-group--select-list',
|
'form-group--select-list',
|
||||||
Classes.FILL,
|
|
||||||
'form-group--estimate-date',
|
'form-group--estimate-date',
|
||||||
|
Classes.FILL,
|
||||||
)}
|
)}
|
||||||
intent={
|
intent={
|
||||||
errors.estimate_date && touched.estimate_date && Intent.DANGER
|
errors.estimate_date && touched.estimate_date && Intent.DANGER
|
||||||
@@ -137,7 +139,7 @@ function EstimateFormHeader({
|
|||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
<Col>
|
<Col md={4}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'expiration_date'} />}
|
label={<T id={'expiration_date'} />}
|
||||||
inline={true}
|
inline={true}
|
||||||
@@ -164,56 +166,58 @@ function EstimateFormHeader({
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/*- Estimate -*/}
|
{/*- Estimate -*/}
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'estimate'} />}
|
label={<T id={'estimate'} />}
|
||||||
inline={true}
|
inline={true}
|
||||||
className={('form-group--estimate-number', Classes.FILL)}
|
className={('form-group--estimate-number', Classes.FILL)}
|
||||||
labelInfo={<FieldRequiredHint />}
|
labelInfo={<FieldRequiredHint />}
|
||||||
intent={
|
|
||||||
errors.estimate_number && touched.estimate_number && Intent.DANGER
|
|
||||||
}
|
|
||||||
helperText={
|
|
||||||
<ErrorMessage name="estimate_number" {...{ errors, touched }} />
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<InputGroup
|
|
||||||
intent={
|
intent={
|
||||||
errors.estimate_number && touched.estimate_number && Intent.DANGER
|
errors.estimate_number && touched.estimate_number && Intent.DANGER
|
||||||
}
|
}
|
||||||
minimal={true}
|
helperText={
|
||||||
rightElement={
|
<ErrorMessage name="estimate_number" {...{ errors, touched }} />
|
||||||
<InputPrependButton
|
|
||||||
buttonProps={{
|
|
||||||
onClick: handleEstimateNumberChange,
|
|
||||||
icon: <Icon icon={'settings-18'} />,
|
|
||||||
}}
|
|
||||||
tooltip={true}
|
|
||||||
tooltipProps={{
|
|
||||||
content: 'Setting your auto-generated estimate number',
|
|
||||||
position: Position.BOTTOM_LEFT,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
{...getFieldProps('estimate_number')}
|
>
|
||||||
/>
|
<InputGroup
|
||||||
</FormGroup>
|
intent={
|
||||||
|
errors.estimate_number && touched.estimate_number && Intent.DANGER
|
||||||
|
}
|
||||||
|
minimal={true}
|
||||||
|
rightElement={
|
||||||
|
<InputPrependButton
|
||||||
|
buttonProps={{
|
||||||
|
onClick: handleEstimateNumberChange,
|
||||||
|
icon: <Icon icon={'settings-18'} />,
|
||||||
|
}}
|
||||||
|
tooltip={true}
|
||||||
|
tooltipProps={{
|
||||||
|
content: 'Setting your auto-generated estimate number',
|
||||||
|
position: Position.BOTTOM_LEFT,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{...getFieldProps('estimate_number')}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'reference'} />}
|
label={<T id={'reference'} />}
|
||||||
inline={true}
|
inline={true}
|
||||||
className={classNames('form-group--reference', Classes.FILL)}
|
className={classNames('form-group--reference', Classes.FILL)}
|
||||||
intent={errors.reference && touched.reference && Intent.DANGER}
|
|
||||||
helperText={<ErrorMessage name="reference" {...{ errors, touched }} />}
|
|
||||||
>
|
|
||||||
<InputGroup
|
|
||||||
intent={errors.reference && touched.reference && Intent.DANGER}
|
intent={errors.reference && touched.reference && Intent.DANGER}
|
||||||
minimal={true}
|
helperText={
|
||||||
{...getFieldProps('reference')}
|
<ErrorMessage name="reference" {...{ errors, touched }} />
|
||||||
/>
|
}
|
||||||
</FormGroup>
|
>
|
||||||
|
<InputGroup
|
||||||
|
intent={errors.reference && touched.reference && Intent.DANGER}
|
||||||
|
minimal={true}
|
||||||
|
{...getFieldProps('reference')}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,65 +94,66 @@ function InvoiceFormHeader({
|
|||||||
labelProp={'display_name'}
|
labelProp={'display_name'}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<Row>
|
|
||||||
<Col>
|
|
||||||
<FormGroup
|
|
||||||
label={<T id={'invoice_date'} />}
|
|
||||||
inline={true}
|
|
||||||
labelInfo={<FieldRequiredHint />}
|
|
||||||
className={classNames('form-group--select-list', Classes.FILL)}
|
|
||||||
intent={
|
|
||||||
errors.invoice_date && touched.invoice_date && Intent.DANGER
|
|
||||||
}
|
|
||||||
helperText={
|
|
||||||
<ErrorMessage name="invoice_date" {...{ errors, touched }} />
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DateInput
|
|
||||||
{...momentFormatter('YYYY/MM/DD')}
|
|
||||||
value={tansformDateValue(values.invoice_date)}
|
|
||||||
onChange={handleDateChange('invoice_date')}
|
|
||||||
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
</Col>
|
|
||||||
<Col>
|
|
||||||
<FormGroup
|
|
||||||
label={<T id={'due_date'} />}
|
|
||||||
inline={true}
|
|
||||||
className={classNames('form-group--select-list', Classes.FILL)}
|
|
||||||
intent={errors.due_date && touched.due_date && Intent.DANGER}
|
|
||||||
helperText={
|
|
||||||
<ErrorMessage name="due_date" {...{ errors, touched }} />
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DateInput
|
|
||||||
{...momentFormatter('YYYY/MM/DD')}
|
|
||||||
value={tansformDateValue(values.due_date)}
|
|
||||||
onChange={handleDateChange('due_date')}
|
|
||||||
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
{/* invoice */}
|
|
||||||
<FormGroup
|
|
||||||
label={<T id={'invoice_no'} />}
|
|
||||||
inline={true}
|
|
||||||
className={('form-group--estimate', Classes.FILL)}
|
|
||||||
labelInfo={<FieldRequiredHint />}
|
|
||||||
intent={errors.invoice_no && touched.invoice_no && Intent.DANGER}
|
|
||||||
helperText={
|
|
||||||
<ErrorMessage name="invoice_no" {...{ errors, touched }} />
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<InputGroup
|
|
||||||
intent={errors.invoice_no && touched.invoice_no && Intent.DANGER}
|
|
||||||
minimal={true}
|
|
||||||
{...getFieldProps('invoice_no')}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Row>
|
||||||
|
<Col>
|
||||||
|
<FormGroup
|
||||||
|
label={<T id={'invoice_date'} />}
|
||||||
|
inline={true}
|
||||||
|
labelInfo={<FieldRequiredHint />}
|
||||||
|
className={classNames('form-group--select-list', Classes.FILL)}
|
||||||
|
intent={
|
||||||
|
errors.invoice_date && touched.invoice_date && Intent.DANGER
|
||||||
|
}
|
||||||
|
helperText={
|
||||||
|
<ErrorMessage name="invoice_date" {...{ errors, touched }} />
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<DateInput
|
||||||
|
{...momentFormatter('YYYY/MM/DD')}
|
||||||
|
value={tansformDateValue(values.invoice_date)}
|
||||||
|
onChange={handleDateChange('invoice_date')}
|
||||||
|
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col>
|
||||||
|
<FormGroup
|
||||||
|
label={<T id={'due_date'} />}
|
||||||
|
inline={true}
|
||||||
|
className={classNames('form-group--select-list', Classes.FILL)}
|
||||||
|
intent={errors.due_date && touched.due_date && Intent.DANGER}
|
||||||
|
helperText={
|
||||||
|
<ErrorMessage name="due_date" {...{ errors, touched }} />
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<DateInput
|
||||||
|
{...momentFormatter('YYYY/MM/DD')}
|
||||||
|
value={tansformDateValue(values.due_date)}
|
||||||
|
onChange={handleDateChange('due_date')}
|
||||||
|
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{/* invoice */}
|
||||||
|
<FormGroup
|
||||||
|
label={<T id={'invoice_no'} />}
|
||||||
|
inline={true}
|
||||||
|
className={('form-group--estimate', Classes.FILL)}
|
||||||
|
labelInfo={<FieldRequiredHint />}
|
||||||
|
intent={errors.invoice_no && touched.invoice_no && Intent.DANGER}
|
||||||
|
helperText={<ErrorMessage name="invoice_no" {...{ errors, touched }} />}
|
||||||
|
>
|
||||||
|
<InputGroup
|
||||||
|
intent={errors.invoice_no && touched.invoice_no && Intent.DANGER}
|
||||||
|
minimal={true}
|
||||||
|
{...getFieldProps('invoice_no')}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'reference'} />}
|
label={<T id={'reference'} />}
|
||||||
inline={true}
|
inline={true}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ export default (mapState) => {
|
|||||||
const mapStateToProps = (state, props) => {
|
const mapStateToProps = (state, props) => {
|
||||||
const mapped = {
|
const mapped = {
|
||||||
organizationSettings: state.settings.data.organization,
|
organizationSettings: state.settings.data.organization,
|
||||||
manualJournalsSettings: state.settings.data.manual_journals,
|
manualJournalsSettings: state.settings.data.manualJournals,
|
||||||
billsettings: state.settings.data.bills,
|
billsettings: state.settings.data.bills,
|
||||||
billPaymentSettings: state.settings.data.bill_payments,
|
billPaymentSettings: state.settings.data.billPayments,
|
||||||
estimatesSettings: state.settings.data.sales_estimates,
|
estimatesSettings: state.settings.data.salesEstimates,
|
||||||
};
|
};
|
||||||
return mapState ? mapState(mapped, state, props) : mapped;
|
return mapState ? mapState(mapped, state, props) : mapped;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { camelCase } from 'lodash';
|
||||||
import { createReducer } from '@reduxjs/toolkit';
|
import { createReducer } from '@reduxjs/toolkit';
|
||||||
import t from 'store/types';
|
import t from 'store/types';
|
||||||
import { optionsArrayToMap } from 'utils';
|
import { optionsArrayToMap } from 'utils';
|
||||||
@@ -6,6 +7,10 @@ const initialState = {
|
|||||||
organization: {
|
organization: {
|
||||||
name: 'Bigcapital, Limited Liabilities',
|
name: 'Bigcapital, Limited Liabilities',
|
||||||
},
|
},
|
||||||
|
manualJournals: {},
|
||||||
|
bills: {},
|
||||||
|
billPayments: {},
|
||||||
|
salesEstimates: {},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -17,10 +22,13 @@ export default createReducer(initialState, {
|
|||||||
};
|
};
|
||||||
options.forEach((option) => {
|
options.forEach((option) => {
|
||||||
const { key, group, value } = option;
|
const { key, group, value } = option;
|
||||||
if (!_data[group]) {
|
const _group = camelCase(group);
|
||||||
_data[group] = {};
|
const _key = camelCase(key);
|
||||||
|
|
||||||
|
if (!_data[_group]) {
|
||||||
|
_data[_group] = {};
|
||||||
}
|
}
|
||||||
_data[group][key] = value;
|
_data[_group][_key] = value;
|
||||||
});
|
});
|
||||||
state.data = _data;
|
state.data = _data;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ $pt-font-family: Noto Sans, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
|
|||||||
@import 'components/pagination';
|
@import 'components/pagination';
|
||||||
@import 'components/resizer';
|
@import 'components/resizer';
|
||||||
|
|
||||||
|
// Pages
|
||||||
// Pages
|
// Pages
|
||||||
@import 'pages/dashboard';
|
@import 'pages/dashboard';
|
||||||
@import 'pages/accounts-chart';
|
@import 'pages/accounts-chart';
|
||||||
@@ -65,6 +66,8 @@ $pt-font-family: Noto Sans, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
|
|||||||
@import 'pages/billing';
|
@import 'pages/billing';
|
||||||
@import 'pages/register-wizard-page';
|
@import 'pages/register-wizard-page';
|
||||||
@import 'pages/register-organizaton';
|
@import 'pages/register-organizaton';
|
||||||
|
@import 'pages/bills';
|
||||||
|
@import 'pages/estimates';
|
||||||
|
|
||||||
// Views
|
// Views
|
||||||
@import 'views/filter-dropdown';
|
@import 'views/filter-dropdown';
|
||||||
@@ -195,4 +198,53 @@ body.authentication {
|
|||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.page-form{
|
||||||
|
|
||||||
|
&__header{
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__primary-section{
|
||||||
|
background-color: #fbfbfb;
|
||||||
|
padding: 30px 20px 20px;
|
||||||
|
margin: -20px;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
}
|
||||||
|
&__footer{
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.datatable-editor{
|
||||||
|
|
||||||
|
.table{
|
||||||
|
.tbody{
|
||||||
|
.tr .td.actions .bp3-button{
|
||||||
|
background-color: transparent;
|
||||||
|
color: #e66d6d;
|
||||||
|
|
||||||
|
svg{
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__actions{
|
||||||
|
|
||||||
|
.bp3-button{
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button--clear-lines{
|
||||||
|
|
||||||
|
&.bp3-button:not([class*="bp3-intent-"]):not(.bp3-minimal){
|
||||||
|
background-color: #fcefef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
67
client/src/style/pages/bills.scss
Normal file
67
client/src/style/pages/bills.scss
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
|
||||||
|
.page-form--bill{
|
||||||
|
$self: '.page-form';
|
||||||
|
|
||||||
|
#{$self}__header{
|
||||||
|
|
||||||
|
.bp3-form-group{
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
.bp3-label{
|
||||||
|
min-width: 140px;
|
||||||
|
}
|
||||||
|
.bp3-form-content{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bp3-form-group{
|
||||||
|
&.bp3-inline{
|
||||||
|
max-width: 450px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.form-group{
|
||||||
|
&--vendor{
|
||||||
|
max-width: 650px
|
||||||
|
}
|
||||||
|
|
||||||
|
&--due-date{
|
||||||
|
max-width: 300px;
|
||||||
|
|
||||||
|
.bp3-label{
|
||||||
|
min-width: 95px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--expiration-date{
|
||||||
|
max-width: 340px;
|
||||||
|
|
||||||
|
.bp3-label{
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.row--bill-date{
|
||||||
|
|
||||||
|
.col:first-of-type{
|
||||||
|
max-width: 465px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.col--estimate-date{
|
||||||
|
max-width: 530px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#{$self}__footer{
|
||||||
|
.form-group--note{
|
||||||
|
max-width: 450px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
textarea{
|
||||||
|
width: 100%;
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
client/src/style/pages/estimates.scss
Normal file
7
client/src/style/pages/estimates.scss
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.page-form--estimate{
|
||||||
|
$self: '.page-form';
|
||||||
|
|
||||||
|
#{$self}__header{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
0
client/src/style/pages/invoices.scss
Normal file
0
client/src/style/pages/invoices.scss
Normal file
Reference in New Issue
Block a user