diff --git a/src/components/DialogsContainer.js b/src/components/DialogsContainer.js index 871e38a58..2a32b532d 100644 --- a/src/components/DialogsContainer.js +++ b/src/components/DialogsContainer.js @@ -26,6 +26,8 @@ import NotifyEstimateViaSMSDialog from '../containers/Dialogs/NotifyEstimateViaS import NotifyPaymentReceiveViaSMSDialog from '../containers/Dialogs/NotifyPaymentReceiveViaSMSDialog'; import SMSMessageDialog from '../containers/Dialogs/SMSMessageDialog'; import TransactionsLockingDialog from '../containers/Dialogs/TransactionsLockingDialog'; +import RefundCreditNoteDialog from '../containers/Dialogs/RefundCreditNoteDialog'; +import RefundVendorCreditDialog from '../containers/Dialogs/RefundVendorCreditDialog'; /** * Dialogs container. @@ -60,6 +62,8 @@ export default function DialogsContainer() { + + ); } diff --git a/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteDialogContent.js b/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteDialogContent.js new file mode 100644 index 000000000..4cc99ae85 --- /dev/null +++ b/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteDialogContent.js @@ -0,0 +1,23 @@ +import React from 'react'; + +import 'style/pages/RefundCreditNote/RefundCreditNote.scss'; +import { RefundCreditNoteFormProvider } from './RefundCreditNoteFormProvider'; +import RefundCreditNoteForm from './RefundCreditNoteForm'; + +/** + * Refund credit note dialog content. + */ +export default function RefundCreditNoteDialogContent({ + // #ownProps + dialogName, + creditNoteId, +}) { + return ( + + + + ); +} diff --git a/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteFloatingActions.js b/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteFloatingActions.js new file mode 100644 index 000000000..13bed0a71 --- /dev/null +++ b/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteFloatingActions.js @@ -0,0 +1,45 @@ +import React from 'react'; +import { Intent, Button, Classes } from '@blueprintjs/core'; +import { useFormikContext } from 'formik'; +import { FormattedMessage as T } from 'components'; + +import { useRefundCreditNoteContext } from './RefundCreditNoteFormProvider'; +import withDialogActions from 'containers/Dialog/withDialogActions'; +import { compose } from 'utils'; + +/** + * Refund credit note floating actions. + */ +function RefundCreditNoteFloatingActions({ + // #withDialogActions + closeDialog, +}) { + // Formik context. + const { isSubmitting, values, errors } = useFormikContext(); + + // refund credit note dialog context. + const { dialogName } = useRefundCreditNoteContext(); + + // Handle close button click. + const handleCancelBtnClick = () => { + closeDialog(dialogName); + }; + + return ( +
+
+ +
+
+ ); +} +export default compose(withDialogActions)(RefundCreditNoteFloatingActions); diff --git a/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteForm.js b/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteForm.js new file mode 100644 index 000000000..d717dc0d0 --- /dev/null +++ b/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteForm.js @@ -0,0 +1,77 @@ +import React from 'react'; +import { Formik } from 'formik'; +import { Intent } from '@blueprintjs/core'; +import intl from 'react-intl-universal'; +import moment from 'moment'; +import { omit, defaultTo } from 'lodash'; + +import { AppToaster } from 'components'; +import { useRefundCreditNoteContext } from './RefundCreditNoteFormProvider'; +import { CreateRefundCreditNoteFormSchema } from './RefundCreditNoteForm.schema'; +import RefundCreditNoteFormContent from './RefundCreditNoteFormContent'; + +import withSettings from 'containers/Settings/withSettings'; +import withDialogActions from 'containers/Dialog/withDialogActions'; +import { compose, transactionNumber } from 'utils'; + +const defaultInitialValues = { + from_account_id: '', + date: moment(new Date()).format('YYYY-MM-DD'), + reference_no: '', + description: '', + amount: '', +}; + +/** + * Refund credit note form. + */ +function RefundCreditNoteForm({ + // #withDialogActions + closeDialog, +}) { + const { dialogName, creditNote, createRefundCreditNoteMutate } = + useRefundCreditNoteContext(); + + // Initial form values + const initialValues = { + ...defaultInitialValues, + ...creditNote, + }; + + // Handles the form submit. + const handleFormSubmit = (values, { setSubmitting, setFieldError }) => { + const form = { + ...omit(values, ['currency_code', 'formatted_amount']), + }; + + // Handle request response success. + const onSaved = (response) => { + AppToaster.show({ + message: intl.get('refund_credit_note.dialog.success_message'), + intent: Intent.SUCCESS, + }); + closeDialog(dialogName); + }; + // Handle request response errors. + const onError = ({ + response: { + data: { errors }, + }, + }) => { + setSubmitting(false); + }; + createRefundCreditNoteMutate([creditNote.id, form]) + .then(onSaved) + .catch(onError); + }; + + return ( + + ); +} +export default compose(withDialogActions)(RefundCreditNoteForm); diff --git a/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteForm.schema.js b/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteForm.schema.js new file mode 100644 index 000000000..8ada6b557 --- /dev/null +++ b/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteForm.schema.js @@ -0,0 +1,12 @@ +import * as Yup from 'yup'; +import intl from 'react-intl-universal'; +import { DATATYPES_LENGTH } from 'common/dataTypes'; + +const Schema = Yup.object().shape({ + date: Yup.date().required().label(intl.get('date')), + amount: Yup.number().required(), + reference_no: Yup.string().min(1).max(DATATYPES_LENGTH.STRING).nullable(), + from_account_id: Yup.number().required().label(intl.get('deposit_account_')), + description: Yup.string().nullable().max(DATATYPES_LENGTH.TEXT), +}); +export const CreateRefundCreditNoteFormSchema = Schema; diff --git a/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteFormContent.js b/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteFormContent.js new file mode 100644 index 000000000..d763729bb --- /dev/null +++ b/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteFormContent.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { Form } from 'formik'; +import RefundCreditNoteFormFields from './RefundCreditNoteFormFields'; +import RefundCreditNoteFloatingActions from './RefundCreditNoteFloatingActions'; + +/** + * Refund credit note form content. + */ +export default function RefundCreditNoteFormContent() { + return ( +
+ + + + ); +} diff --git a/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteFormFields.js b/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteFormFields.js new file mode 100644 index 000000000..54e7f2730 --- /dev/null +++ b/src/containers/Dialogs/RefundCreditNoteDialog/RefundCreditNoteFormFields.js @@ -0,0 +1,160 @@ +import React from 'react'; +import intl from 'react-intl-universal'; +import { FastField, ErrorMessage } from 'formik'; +import { + Classes, + FormGroup, + InputGroup, + TextArea, + Position, + ControlGroup, +} from '@blueprintjs/core'; +import classNames from 'classnames'; +import { CLASSES } from 'common/classes'; +import { DateInput } from '@blueprintjs/datetime'; +import { + Icon, + FieldRequiredHint, + AccountsSuggestField, + InputPrependText, + MoneyInputGroup, + FormattedMessage as T, +} from 'components'; +import { + inputIntent, + momentFormatter, + tansformDateValue, + handleDateChange, + compose, +} from 'utils'; +import { useAutofocus } from 'hooks'; +import { useRefundCreditNoteContext } from './RefundCreditNoteFormProvider'; +import withSettings from 'containers/Settings/withSettings'; + +/** + * Refund credit note form fields. + */ +function RefundCreditNoteFormFields() { + const { accounts } = useRefundCreditNoteContext(); + const amountFieldRef = useAutofocus(); + return ( +
+ {/* ------------- Refund date ------------- */} + + {({ form, field: { value }, meta: { error, touched } }) => ( + } + labelInfo={} + className={classNames('form-group--select-list', CLASSES.FILL)} + intent={inputIntent({ error, touched })} + helperText={} + inline={true} + > + { + form.setFieldValue('date', formattedDate); + })} + popoverProps={{ position: Position.BOTTOM, minimal: true }} + inputProps={{ + leftIcon: , + }} + /> + + )} + + {/* ------------- Amount ------------- */} + + {({ + form: { values, setFieldValue }, + field: { value }, + meta: { error, touched }, + }) => ( + } + labelInfo={} + className={classNames('form-group--amount', CLASSES.FILL)} + intent={inputIntent({ error, touched })} + helperText={} + inline={true} + > + + + { + setFieldValue('amount', amount); + }} + intent={inputIntent({ error, touched })} + inputRef={(ref) => (amountFieldRef.current = ref)} + /> + + + )} + + {/* ------------ Reference No. ------------ */} + + {({ form, field, meta: { error, touched } }) => ( + } + className={classNames('form-group--reference', CLASSES.FILL)} + intent={inputIntent({ error, touched })} + helperText={} + inline={true} + > + + + )} + + + {/* ------------ Form account ------------ */} + + {({ form, field: { value }, meta: { error, touched } }) => ( + } + className={classNames( + 'form-group--from_account_id', + 'form-group--select-list', + CLASSES.FILL, + )} + labelInfo={} + intent={inputIntent({ error, touched })} + helperText={} + inline={true} + > + + form.setFieldValue('from_account_id', id) + } + inputProps={{ + placeholder: intl.get('select_account'), + }} + /> + + )} + + {/* --------- Statement --------- */} + + {({ form, field, meta: { error, touched } }) => ( + } + className={'form-group--description'} + inline={true} + > +