refactoring: sales tables.

refacoring: purchases tables.
This commit is contained in:
a.bouhuolia
2021-02-11 20:45:06 +02:00
parent 3901c336df
commit d48532a7e6
210 changed files with 2799 additions and 5392 deletions

View File

@@ -0,0 +1,262 @@
import React, { useMemo, useCallback, useEffect } from 'react';
import { Formik, Form } from 'formik';
import moment from 'moment';
import { Intent } from '@blueprintjs/core';
import { useIntl } from 'react-intl';
import { pick, sumBy, isEmpty } from 'lodash';
import classNames from 'classnames';
import { useHistory } from 'react-router-dom';
import { CLASSES } from 'common/classes';
import { ERROR } from 'common/errors';
import {
EditReceiptFormSchema,
CreateReceiptFormSchema,
} from './ReceiptForm.schema';
import 'style/pages/SaleReceipt/PageForm.scss';
import { useReceiptFormContext } from './ReceiptFormProvider';
import ReceiptFromHeader from './ReceiptFormHeader';
import ReceiptFormBody from './ReceiptFormBody';
import ReceiptFormFloatingActions from './ReceiptFormFloatingActions';
import ReceiptFormFooter from './ReceiptFormFooter';
import ReceiptNumberWatcher from './ReceiptNumberWatcher';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withSettings from 'containers/Settings/withSettings';
import { AppToaster } from 'components';
import {
compose,
repeatValue,
orderingLinesIndexes,
defaultToTransform,
transactionNumber,
} from 'utils';
const MIN_LINES_NUMBER = 4;
const defaultReceipt = {
index: 0,
item_id: '',
rate: '',
discount: 0,
quantity: '',
description: '',
};
const defaultInitialValues = {
customer_id: '',
deposit_account_id: '',
receipt_number: '',
receipt_date: moment(new Date()).format('YYYY-MM-DD'),
reference_no: '',
receipt_message: '',
statement: '',
closed: '',
entries: [...repeatValue(defaultReceipt, MIN_LINES_NUMBER)],
};
/**
* Receipt form.
*/
function ReceiptForm({
// #withDashboard
changePageTitle,
changePageSubtitle,
// #withSettings
receiptNextNumber,
receiptNumberPrefix,
preferredDepositAccount,
}) {
const { formatMessage } = useIntl();
const history = useHistory();
// Receipt form context.
const {
receiptId,
receipt,
editReceiptMutate,
createReceiptMutate,
submitPayload
} = useReceiptFormContext();
const isNewMode = !receiptId;
// The next receipt number.
const receiptNumber = transactionNumber(
receiptNumberPrefix,
receiptNextNumber,
);
useEffect(() => {
const transactionNumber = !isNewMode
? receipt.receipt_number
: receiptNumber;
if (receipt && receipt.id) {
changePageTitle(formatMessage({ id: 'edit_receipt' }));
} else {
changePageTitle(formatMessage({ id: 'new_receipt' }));
}
changePageSubtitle(
defaultToTransform(transactionNumber, `No. ${transactionNumber}`, ''),
);
}, [
isNewMode,
changePageTitle,
changePageSubtitle,
receipt,
receiptNumber,
formatMessage,
]);
// Initial values in create and edit mode.
const initialValues = useMemo(
() => ({
...(!isEmpty(receipt)
? {
...pick(receipt, Object.keys(defaultInitialValues)),
entries: [
...receipt.entries.map((receipt) => ({
...pick(receipt, Object.keys(defaultReceipt)),
})),
...repeatValue(
defaultReceipt,
Math.max(MIN_LINES_NUMBER - receipt.entries.length, 0),
),
],
}
: {
...defaultInitialValues,
receipt_number: receiptNumber,
deposit_account_id: parseInt(preferredDepositAccount),
entries: orderingLinesIndexes(defaultInitialValues.entries),
}),
}),
[receipt, preferredDepositAccount, receiptNumber],
);
// Transform response error to fields.
const handleErrors = (errors, { setErrors }) => {
if (errors.some((e) => e.type === ERROR.SALE_RECEIPT_NUMBER_NOT_UNIQUE)) {
setErrors({
receipt_number: formatMessage({
id: 'sale_receipt_number_not_unique',
}),
});
}
};
// Handle the form submit.
const handleFormSubmit = (
values,
{ setErrors, setSubmitting, resetForm },
) => {
const entries = values.entries.filter(
(item) => item.item_id && item.quantity,
);
const totalQuantity = sumBy(entries, (entry) => parseInt(entry.quantity));
if (totalQuantity === 0) {
AppToaster.show({
message: formatMessage({
id: 'quantity_cannot_be_zero_or_empty',
}),
intent: Intent.DANGER,
});
setSubmitting(false);
return;
}
const form = {
...values,
closed: submitPayload.status,
entries: entries.map((entry) => ({
// Exclude all properties that out of request entries schema.
...pick(entry, Object.keys(defaultReceipt)),
})),
};
// Handle the request success.
const onSuccess = (response) => {
AppToaster.show({
message: formatMessage(
{
id: isNewMode
? 'the_receipt_has_been_created_successfully'
: 'the_receipt_has_been_edited_successfully',
},
{ number: values.receipt_number },
),
intent: Intent.SUCCESS,
});
setSubmitting(false);
if (submitPayload.redirect) {
history.push('/receipts');
}
if (submitPayload.resetForm) {
resetForm();
}
};
// Handle the request error.
const onError = (errors) => {
handleErrors(errors, { setErrors });
setSubmitting(false);
};
if (receipt && receipt.id) {
editReceiptMutate(receipt.id, form).then(onSuccess).catch(onError);
} else {
createReceiptMutate(form).then(onSuccess).catch(onError);
}
};
const handleReceiptNumberChanged = useCallback(
(receiptNumber) => {
changePageSubtitle(
defaultToTransform(receiptNumber, `No. ${receiptNumber}`, ''),
);
},
[changePageSubtitle],
);
return (
<div
className={classNames(
CLASSES.PAGE_FORM,
CLASSES.PAGE_FORM_STRIP_STYLE,
CLASSES.PAGE_FORM_RECEIPT,
)}
>
<Formik
validationSchema={
isNewMode ? CreateReceiptFormSchema : EditReceiptFormSchema
}
initialValues={initialValues}
onSubmit={handleFormSubmit}
>
<Form>
<ReceiptFromHeader
onReceiptNumberChanged={handleReceiptNumberChanged}
/>
<ReceiptNumberWatcher receiptNumber={receiptNumber} />
<ReceiptFormBody defaultReceipt={defaultReceipt} />
<ReceiptFormFooter />
<ReceiptFormFloatingActions />
</Form>
</Formik>
</div>
);
}
export default compose(
withDashboardActions,
withSettings(({ receiptSettings }) => ({
receiptNextNumber: receiptSettings?.nextNumber,
receiptNumberPrefix: receiptSettings?.numberPrefix,
preferredDepositAccount: receiptSettings?.preferredDepositAccount,
})),
)(ReceiptForm);

View File

@@ -0,0 +1,57 @@
import * as Yup from 'yup';
import { formatMessage } from 'services/intl';
import { DATATYPES_LENGTH } from 'common/dataTypes';
import { isBlank } from 'utils';
const Schema = Yup.object().shape({
customer_id: Yup.string()
.label(formatMessage({ id: 'customer_name_' }))
.required(),
receipt_date: Yup.date()
.required()
.label(formatMessage({ id: 'receipt_date_' })),
receipt_number: Yup.string()
.nullable()
.max(DATATYPES_LENGTH.STRING)
.label(formatMessage({ id: 'receipt_no_' })),
deposit_account_id: Yup.number()
.required()
.label(formatMessage({ id: 'deposit_account_' })),
reference_no: Yup.string().min(1).max(DATATYPES_LENGTH.STRING),
receipt_message: Yup.string()
.trim()
.min(1)
.max(DATATYPES_LENGTH.STRING)
.label(formatMessage({ id: 'receipt_message_' })),
statement: Yup.string()
.trim()
.min(1)
.max(DATATYPES_LENGTH.TEXT)
.label(formatMessage({ id: 'note' })),
closed: Yup.boolean(),
entries: Yup.array().of(
Yup.object().shape({
quantity: Yup.number()
.nullable()
.max(DATATYPES_LENGTH.INT_10)
.when(['rate'], {
is: (rate) => rate,
then: Yup.number().required(),
}),
rate: Yup.number().nullable().max(DATATYPES_LENGTH.INT_10),
item_id: Yup.number()
.nullable()
.when(['quantity', 'rate'], {
is: (quantity, rate) => !isBlank(quantity) && !isBlank(rate),
then: Yup.number().required(),
}),
discount: Yup.number().nullable().min(0).max(DATATYPES_LENGTH.INT_10),
description: Yup.string().nullable().max(DATATYPES_LENGTH.TEXT),
}),
),
});
const CreateReceiptFormSchema = Schema;
const EditReceiptFormSchema = Schema;
export { CreateReceiptFormSchema, EditReceiptFormSchema };

View File

@@ -0,0 +1,20 @@
import React from 'react';
import classNames from 'classnames';
import { CLASSES } from 'common/classes';
import EditableItemsEntriesTable from 'containers/Entries/EditableItemsEntriesTable';
import { useReceiptFormContext } from './ReceiptFormProvider';
export default function ExpenseFormBody({ defaultReceipt }) {
const { items } = useReceiptFormContext();
return (
<div className={classNames(CLASSES.PAGE_FORM_BODY)}>
<EditableItemsEntriesTable
items={items}
defaultEntry={defaultReceipt}
filterSellableItems={true}
/>
</div>
);
}

View File

@@ -0,0 +1,185 @@
import React from 'react';
import {
Intent,
Button,
ButtonGroup,
Popover,
PopoverInteractionKind,
Position,
Menu,
MenuItem,
} from '@blueprintjs/core';
import { FormattedMessage as T } from 'react-intl';
import { useFormikContext } from 'formik';
import classNames from 'classnames';
import { CLASSES } from 'common/classes';
import { If, Icon } from 'components';
import { useReceiptFormContext } from './ReceiptFormProvider';
/**
* Receipt floating actions bar.
*/
export default function ReceiptFormFloatingActions() {
// Formik context.
const { resetForm, submitForm, isSubmitting } = useFormikContext();
// Receipt form context.
const { receipt, setSubmitPayload } = useReceiptFormContext();
// Handle submit & close button click.
const handleSubmitCloseBtnClick = (event) => {
setSubmitPayload({ redirect: true, status: true });
submitForm();
};
// Handle submit, close & new button click.
const handleSubmitCloseAndNewBtnClick = (event) => {
setSubmitPayload({ redirect: false, status: true, resetForm: true });
submitForm();
};
// Handle submit, close & continue editing button click.
const handleSubmitCloseContinueEditingBtnClick = (event) => {
setSubmitPayload({ redirect: false, status: true });
submitForm();
};
// Handle submit & draft button click.
const handleSubmitDraftBtnClick = (event) => {
setSubmitPayload({ redirect: true, status: false });
submitForm();
};
// Handle submit, draft & new button click.
const handleSubmitDraftAndNewBtnClick = (event) => {
setSubmitPayload({ redirect: false, status: false, resetForm: true });
submitForm();
};
const handleSubmitDraftContinueEditingBtnClick = (event) => {
setSubmitPayload({ redirect: false, status: false });
submitForm();
};
// Handle cancel button click.
const handleCancelBtnClick = (event) => {
};
const handleClearBtnClick = (event) => {
resetForm();
};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
{/* ----------- Save And Close ----------- */}
<If condition={!receipt || !receipt?.is_closed}>
<ButtonGroup>
<Button
disabled={isSubmitting}
intent={Intent.PRIMARY}
onClick={handleSubmitCloseBtnClick}
text={<T id={'save_close'} />}
/>
<Popover
content={
<Menu>
<MenuItem
text={<T id={'close_and_new'} />}
onClick={handleSubmitCloseAndNewBtnClick}
/>
<MenuItem
text={<T id={'close_continue_editing'} />}
onClick={handleSubmitCloseContinueEditingBtnClick}
/>
</Menu>
}
minimal={true}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
disabled={isSubmitting}
intent={Intent.PRIMARY}
rightIcon={<Icon icon="arrow-drop-up-16" iconSize={20} />}
/>
</Popover>
</ButtonGroup>
{/* ----------- Save As Draft ----------- */}
<ButtonGroup>
<Button
disabled={isSubmitting}
className={'ml1'}
onClick={handleSubmitDraftBtnClick}
text={<T id={'save_as_draft'} />}
/>
<Popover
content={
<Menu>
<MenuItem
text={<T id={'save_and_new'} />}
onClick={handleSubmitDraftAndNewBtnClick}
/>
<MenuItem
text={<T id={'save_continue_editing'} />}
onClick={handleSubmitDraftContinueEditingBtnClick}
/>
</Menu>
}
minimal={true}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
disabled={isSubmitting}
rightIcon={<Icon icon="arrow-drop-up-16" iconSize={20} />}
/>
</Popover>
</ButtonGroup>
</If>
{/* ----------- Save and New ----------- */}
<If condition={receipt && receipt?.is_closed}>
<ButtonGroup>
<Button
disabled={isSubmitting}
intent={Intent.PRIMARY}
onClick={handleSubmitCloseBtnClick}
text={<T id={'save'} />}
/>
<Popover
content={
<Menu>
<MenuItem
text={<T id={'save_and_new'} />}
onClick={handleSubmitCloseAndNewBtnClick}
/>
</Menu>
}
minimal={true}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
disabled={isSubmitting}
intent={Intent.PRIMARY}
rightIcon={<Icon icon="arrow-drop-up-16" iconSize={20} />}
/>
</Popover>
</ButtonGroup>
</If>
{/* ----------- Clear & Reset----------- */}
<Button
className={'ml1'}
disabled={isSubmitting}
onClick={handleClearBtnClick}
text={receipt ? <T id={'reset'} /> : <T id={'clear'} />}
/>
{/* ----------- Cancel ----------- */}
<Button
className={'ml1'}
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
);
}

View File

@@ -0,0 +1,53 @@
import React from 'react';
import { FormGroup, TextArea } from '@blueprintjs/core';
import { FastField } from 'formik';
import classNames from 'classnames';
import { FormattedMessage as T } from 'react-intl';
import { Dragzone, Row, Col } from 'components';
import { CLASSES } from 'common/classes';
import { inputIntent } from 'utils';
export default function ReceiptFormFooter({}) {
return (
<div className={classNames(CLASSES.PAGE_FORM_FOOTER)}>
<Row>
<Col md={8}>
{/* --------- Receipt message --------- */}
<FastField name={'receipt_message'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'receipt_message'} />}
className={'form-group--receipt_message'}
intent={inputIntent({ error, touched })}
>
<TextArea growVertically={true} {...field} />
</FormGroup>
)}
</FastField>
{/* --------- Statement--------- */}
<FastField name={'statement'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'statement'} />}
className={'form-group--statement'}
intent={inputIntent({ error, touched })}
>
<TextArea growVertically={true} {...field} />
</FormGroup>
)}
</FastField>
</Col>
<Col md={4}>
<Dragzone
initialFiles={[]}
// onDrop={handleDropFiles}
// onDeleteFile={handleDeleteFile}
hint={'Attachments: Maxiumum size: 20MB'}
/>
</Col>
</Row>
</div>
);
}

View File

@@ -0,0 +1,47 @@
import React, { useMemo } from 'react';
import classNames from 'classnames';
import { sumBy } from 'lodash';
import { useFormikContext } from 'formik';
import { CLASSES } from 'common/classes';
import ReceiptFormHeaderFields from './ReceiptFormHeaderFields';
import { PageFormBigNumber } from 'components';
import withSettings from 'containers/Settings/withSettings';
import { compose } from 'redux';
/**
* Receipt form header section.
*/
function ReceiptFormHeader({
// #ownProps
onReceiptNumberChanged,
// #withSettings
baseCurrency,
}) {
const { values } = useFormikContext();
// Calculate the total due amount of bill entries.
const totalDueAmount = useMemo(() => sumBy(values.entries, 'total'), [
values.entries,
]);
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
<ReceiptFormHeaderFields
onReceiptNumberChanged={onReceiptNumberChanged}
/>
<PageFormBigNumber
label={'Due Amount'}
amount={totalDueAmount}
currencyCode={baseCurrency}
/>
</div>
);
}
export default compose(
withSettings(({ organizationSettings }) => ({
baseCurrency: organizationSettings?.baseCurrency,
})),
)(ReceiptFormHeader);

View File

@@ -0,0 +1,186 @@
import React, { useCallback } from 'react';
import {
FormGroup,
InputGroup,
Position,
ControlGroup,
} from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime';
import { FormattedMessage as T } from 'react-intl';
import classNames from 'classnames';
import { FastField, ErrorMessage } from 'formik';
import { CLASSES } from 'common/classes';
import {
AccountsSelectList,
ContactSelecetList,
FieldRequiredHint,
Icon,
InputPrependButton,
} from 'components';
import withDialogActions from 'containers/Dialog/withDialogActions';
import {
momentFormatter,
compose,
tansformDateValue,
saveInvoke,
handleDateChange,
inputIntent,
} from 'utils';
import { useReceiptFormContext } from './ReceiptFormProvider';
/**
* Receipt form header fields.
*/
function ReceiptFormHeader({
//#withDialogActions
openDialog,
// #ownProps
onReceiptNumberChanged,
}) {
const { accounts, customers } = useReceiptFormContext();
const handleReceiptNumberChange = useCallback(() => {
openDialog('receipt-number-form', {});
}, [openDialog]);
const handleReceiptNumberChanged = (event) => {
saveInvoke(onReceiptNumberChanged, event.currentTarget.value);
};
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Customer name ----------- */}
<FastField name={'customer_id'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'customer_name'} />}
inline={true}
className={classNames(CLASSES.FILL, 'form-group--customer')}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'customer_id'} />}
>
<ContactSelecetList
contactsList={customers}
selectedContactId={value}
defaultSelectText={<T id={'select_customer_account'} />}
onContactSelected={(contact) => {
form.setFieldValue('customer_id', contact.id);
}}
popoverFill={true}
/>
</FormGroup>
)}
</FastField>
{/* ----------- Deposit account ----------- */}
<FastField name={'deposit_account_id'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'deposit_account'} />}
className={classNames('form-group--deposit-account', CLASSES.FILL)}
inline={true}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'deposit_account_id'} />}
>
<AccountsSelectList
accounts={accounts}
onAccountSelected={(account) => {
form.setFieldValue('deposit_account_id', account.id);
}}
defaultSelectText={<T id={'select_deposit_account'} />}
selectedAccountId={value}
// filterByTypes={['current_asset']}
popoverFill={true}
/>
</FormGroup>
)}
</FastField>
{/* ----------- Receipt date ----------- */}
<FastField name={'receipt_date'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'receipt_date'} />}
inline={true}
className={classNames(CLASSES.FILL)}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="receipt_date" />}
>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
value={tansformDateValue(value)}
onChange={handleDateChange((formattedDate) => {
form.setFieldValue('receipt_date', formattedDate);
})}
popoverProps={{ position: Position.BOTTOM, minimal: true }}
inputProps={{
leftIcon: <Icon icon={'date-range'} />,
}}
/>
</FormGroup>
)}
</FastField>
{/* ----------- Receipt number ----------- */}
<FastField name={'receipt_number'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'receipt'} />}
inline={true}
className={('form-group--receipt_number', CLASSES.FILL)}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="receipt_number" />}
>
<ControlGroup fill={true}>
<InputGroup
minimal={true}
{...field}
onBlur={handleReceiptNumberChanged}
/>
<InputPrependButton
buttonProps={{
onClick: handleReceiptNumberChange,
icon: <Icon icon={'settings-18'} />,
}}
tooltip={true}
tooltipProps={{
content: 'Setting your auto-generated receipt number',
position: Position.BOTTOM_LEFT,
}}
inputProps={{
leftIcon: <Icon icon={'date-range'} />,
}}
/>
</ControlGroup>
</FormGroup>
)}
</FastField>
{/* ----------- Reference ----------- */}
<FastField name={'reference'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'reference'} />}
inline={true}
className={classNames('form-group--reference', CLASSES.FILL)}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="reference" />}
>
<InputGroup minimal={true} {...field} />
</FormGroup>
)}
</FastField>
</div>
);
}
export default compose(
withDialogActions,
)(ReceiptFormHeader);

View File

@@ -0,0 +1,57 @@
import React, { useEffect } from 'react';
import { useParams, useHistory } from 'react-router-dom';
import ReceiptFrom from './ReceiptForm';
import { ReceiptFormProvider } from './ReceiptFormProvider';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import { compose } from 'utils';
/**
* Receipt form page.
*/
function ReceiptFormPage({
// #withDashboardActions
setSidebarShrink,
resetSidebarPreviousExpand,
setDashboardBackLink,
}) {
const { id } = useParams();
useEffect(() => {
// Shrink the sidebar by foce.
setSidebarShrink();
// Show the back link on dashboard topbar.
setDashboardBackLink(true);
return () => {
// Reset the sidebar to the previous status.
resetSidebarPreviousExpand();
// Hide the back link on dashboard topbar.
setDashboardBackLink(false);
};
}, [resetSidebarPreviousExpand, setSidebarShrink, setDashboardBackLink]);
// const handleFormSubmit = useCallback(
// (payload) => {
// payload.redirect && history.push('/receipts');
// },
// [history],
// );
// const handleCancel = useCallback(() => {
// history.goBack();
// }, [history]);
return (
<ReceiptFormProvider receiptId={id}>
<ReceiptFrom />
</ReceiptFormProvider>
);
}
export default compose(
withDashboardActions,
)(ReceiptFormPage);

View File

@@ -0,0 +1,85 @@
import React, { createContext, useState } from 'react';
import DashboardInsider from 'components/Dashboard/DashboardInsider';
import {
useReceipt,
useAccounts,
useSettings,
useCustomers,
useItems,
useCreateReceipt,
useEditReceipt
} from 'hooks/query';
const ReceiptFormContext = createContext();
/**
* Receipt form provider.
*/
function ReceiptFormProvider({ receiptId, ...props }) {
// Fetch sale receipt details.
const { data: receipt, isFetching: isReceiptLoading } = useReceipt(
receiptId,
{
enabled: !!receiptId,
},
);
// Fetch accounts list.
const { data: accounts, isFetching: isAccountsLoading } = useAccounts();
// Fetch customers list.
const {
data: { customers },
isFetching: isCustomersLoading,
} = useCustomers();
// Handle fetch Items data table or list
const {
data: { items },
isFetching: isItemsLoading,
} = useItems();
// Fetch receipt settings.
const { isFetching: isSettingLoading } = useSettings();
const { mutateAsync: createReceiptMutate } = useCreateReceipt();
const { mutateAsync: editReceiptMutate } = useEditReceipt();
const [submitPayload, setSubmitPayload] = useState({});
const provider = {
receiptId,
receipt,
accounts,
customers,
items,
submitPayload,
isReceiptLoading,
isAccountsLoading,
isCustomersLoading,
isItemsLoading,
isSettingLoading,
createReceiptMutate,
editReceiptMutate,
setSubmitPayload
};
return (
<DashboardInsider
loading={
isReceiptLoading ||
isAccountsLoading ||
isCustomersLoading ||
isItemsLoading ||
isSettingLoading
}
name={'receipt-form'}
>
<ReceiptFormContext.Provider value={provider} {...props} />
</DashboardInsider>
);
}
const useReceiptFormContext = () => React.useContext(ReceiptFormContext);
export { ReceiptFormProvider, useReceiptFormContext };

View File

@@ -0,0 +1,45 @@
import { useEffect } from 'react';
import { useFormikContext } from 'formik';
import withDashboardActions from "containers/Dashboard/withDashboardActions";
import withReceipts from './withReceipts';
import withReceiptActions from './withReceiptActions';
import { compose } from 'utils';
function ReceiptNumberWatcher({
receiptNumber,
// #withDashboardActions
changePageSubtitle,
// #withReceipts
receiptNumberChanged,
//#withReceiptActions
setReceiptNumberChanged,
}) {
const { setFieldValue } = useFormikContext();
useEffect(() => {
if (receiptNumberChanged) {
setFieldValue('receipt_number', receiptNumber);
changePageSubtitle(`No. ${receiptNumber}`);
setReceiptNumberChanged(false);
}
}, [
receiptNumber,
receiptNumberChanged,
setReceiptNumberChanged,
setFieldValue,
changePageSubtitle,
]);
return null
}
export default compose(
withReceipts(({ receiptNumberChanged }) => ({ receiptNumberChanged })),
withReceiptActions,
withDashboardActions
)(ReceiptNumberWatcher);