From 2078b6bc99b1f657263f056910e6e41bb84e9bbc Mon Sep 17 00:00:00 2001 From: elforjani13 <39470382+elforjani13@users.noreply.github.com> Date: Wed, 13 Oct 2021 19:56:48 +0200 Subject: [PATCH] feat: Money in & out Dialog. --- src/common/cashflowOptions.js | 27 +++ src/components/DialogsContainer.js | 4 + src/config/sidebarMenu.js | 32 +++ .../MoneyInDialog/MoneyInDialogContent.js | 20 ++ .../MoneyInDialog/MoneyInDialogForm.js | 20 ++ .../MoneyInDialog/MoneyInDialogProvider.js | 42 ++++ .../MoneyInDialog/MoneyInFloatingActions.js | 76 +++++++ .../OtherIncome/OtherIncomeForm.js | 91 +++++++++ .../OtherIncome/OtherIncomeForm.schema.js | 22 ++ .../OtherIncome/OtherIncomeFormContent.js | 17 ++ .../OtherIncome/OtherIncomeFormFields.js | 186 +++++++++++++++++ .../OwnerContributionForm.js | 91 +++++++++ .../OwnerContributionForm.schema.js | 22 ++ .../OwnerContributionFormContent.js | 17 ++ .../OwnerContributionFormFields.js | 186 +++++++++++++++++ src/containers/Dialogs/MoneyInDialog/index.js | 36 ++++ .../MoneyOutDialog/MoneyOutDialogContent.js | 20 ++ .../MoneyOutDialog/MoneyOutProvider.js | 37 ++++ .../OwnerDrawingsFloatingActions.js | 76 +++++++ .../OwnerDrawings/OwnerDrawingsForm.js | 72 +++++++ .../OwnerDrawings/OwnerDrawingsForm.schema.js | 21 ++ .../OwnerDrawings/OwnerDrawingsFormContent.js | 17 ++ .../OwnerDrawings/OwnerDrawingsFormFields.js | 188 ++++++++++++++++++ .../Dialogs/MoneyOutDialog/index.js | 39 ++++ src/hooks/query/index.js | 1 + src/hooks/query/types.js | 9 +- src/lang/en/index.json | 32 ++- src/routes/dashboard.js | 38 +++- .../CashFlow/CashflowTransactionForm.scss | 30 +++ 29 files changed, 1458 insertions(+), 11 deletions(-) create mode 100644 src/common/cashflowOptions.js create mode 100644 src/containers/Dialogs/MoneyInDialog/MoneyInDialogContent.js create mode 100644 src/containers/Dialogs/MoneyInDialog/MoneyInDialogForm.js create mode 100644 src/containers/Dialogs/MoneyInDialog/MoneyInDialogProvider.js create mode 100644 src/containers/Dialogs/MoneyInDialog/MoneyInFloatingActions.js create mode 100644 src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeForm.js create mode 100644 src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeForm.schema.js create mode 100644 src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeFormContent.js create mode 100644 src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeFormFields.js create mode 100644 src/containers/Dialogs/MoneyInDialog/OwnerContribution/OwnerContributionForm.js create mode 100644 src/containers/Dialogs/MoneyInDialog/OwnerContribution/OwnerContributionForm.schema.js create mode 100644 src/containers/Dialogs/MoneyInDialog/OwnerContribution/OwnerContributionFormContent.js create mode 100644 src/containers/Dialogs/MoneyInDialog/OwnerContribution/OwnerContributionFormFields.js create mode 100644 src/containers/Dialogs/MoneyInDialog/index.js create mode 100644 src/containers/Dialogs/MoneyOutDialog/MoneyOutDialogContent.js create mode 100644 src/containers/Dialogs/MoneyOutDialog/MoneyOutProvider.js create mode 100644 src/containers/Dialogs/MoneyOutDialog/OwnerDrawings/OwnerDrawingsFloatingActions.js create mode 100644 src/containers/Dialogs/MoneyOutDialog/OwnerDrawings/OwnerDrawingsForm.js create mode 100644 src/containers/Dialogs/MoneyOutDialog/OwnerDrawings/OwnerDrawingsForm.schema.js create mode 100644 src/containers/Dialogs/MoneyOutDialog/OwnerDrawings/OwnerDrawingsFormContent.js create mode 100644 src/containers/Dialogs/MoneyOutDialog/OwnerDrawings/OwnerDrawingsFormFields.js create mode 100644 src/containers/Dialogs/MoneyOutDialog/index.js create mode 100644 src/style/pages/CashFlow/CashflowTransactionForm.scss diff --git a/src/common/cashflowOptions.js b/src/common/cashflowOptions.js new file mode 100644 index 000000000..86a6a8863 --- /dev/null +++ b/src/common/cashflowOptions.js @@ -0,0 +1,27 @@ +import intl from 'react-intl-universal'; + +export const addMoneyIn = [ + { + name: intl.get('cash_flow.option_owner_contribution'), + type: 'OWNERS', + }, + { + name: intl.get('cash_flow.option_other_income'), + type: 'EQUITY', + }, +]; + +export const addMoneyOut = [ + { + name: intl.get('cash_flow.option_owner_drawings'), + type: 'OWNERS', + }, + { + name: intl.get('cash_flow.option_expenses'), + type: 'EXPENSES', + }, + { + name: intl.get('cash_flow.option_vendor_payment'), + type: '', + }, +]; diff --git a/src/components/DialogsContainer.js b/src/components/DialogsContainer.js index 19d8e021b..07c00ca6f 100644 --- a/src/components/DialogsContainer.js +++ b/src/components/DialogsContainer.js @@ -17,6 +17,8 @@ import AllocateLandedCostDialog from 'containers/Dialogs/AllocateLandedCostDialo import InvoicePdfPreviewDialog from 'containers/Dialogs/InvoicePdfPreviewDialog'; import EstimatePdfPreviewDialog from 'containers/Dialogs/EstimatePdfPreviewDialog'; import ReceiptPdfPreviewDialog from '../containers/Dialogs/ReceiptPdfPreviewDialog'; +import MoneyInDialog from '../containers/Dialogs/MoneyInDialog'; +import MoneyOutDialog from '../containers/Dialogs/MoneyOutDialog'; /** * Dialogs container. @@ -40,6 +42,8 @@ export default function DialogsContainer() { + + ); } diff --git a/src/config/sidebarMenu.js b/src/config/sidebarMenu.js index 5a1149e44..b110bc863 100644 --- a/src/config/sidebarMenu.js +++ b/src/config/sidebarMenu.js @@ -193,6 +193,38 @@ export default [ text: , children: [], }, + { + text: , + children: [ + { + text: , + href: '/cashflow-accounts', + }, + { + text: , + label: true, + }, + { + divider: true, + }, + { + text: , + href: '/', + }, + { + text: , + href: '/', + }, + { + text: , + href: '/', + }, + { + text: , + href: '/', + }, + ], + }, { text: , children: [ diff --git a/src/containers/Dialogs/MoneyInDialog/MoneyInDialogContent.js b/src/containers/Dialogs/MoneyInDialog/MoneyInDialogContent.js new file mode 100644 index 000000000..959490ded --- /dev/null +++ b/src/containers/Dialogs/MoneyInDialog/MoneyInDialogContent.js @@ -0,0 +1,20 @@ +import React from 'react'; + +import { MoneyInDialogProvider } from './MoneyInDialogProvider'; +import MoneyInDialogForm from './MoneyInDialogForm'; + +/** + * Money in dialog content. + */ +export default function MoneyInDialogContent({ + // #ownProps + dialogName, + accountId, + accountType, +}) { + return ( + + + + ); +} diff --git a/src/containers/Dialogs/MoneyInDialog/MoneyInDialogForm.js b/src/containers/Dialogs/MoneyInDialog/MoneyInDialogForm.js new file mode 100644 index 000000000..6becf35d8 --- /dev/null +++ b/src/containers/Dialogs/MoneyInDialog/MoneyInDialogForm.js @@ -0,0 +1,20 @@ +import React from 'react'; +import OwnerContributionForm from './OwnerContribution/OwnerContributionForm'; +import OtherIncomeForm from './OtherIncome/OtherIncomeForm'; + +export default function MoneyInDialogForm({ accountType }) { + // Handle from transaction. + const handleFromTransaction = () => { + switch (accountType) { + case 'OWNERS': + return ; + + case 'EQUITY': + return ; + default: + break; + } + }; + + return
{handleFromTransaction()}
; +} diff --git a/src/containers/Dialogs/MoneyInDialog/MoneyInDialogProvider.js b/src/containers/Dialogs/MoneyInDialog/MoneyInDialogProvider.js new file mode 100644 index 000000000..0525c8edf --- /dev/null +++ b/src/containers/Dialogs/MoneyInDialog/MoneyInDialogProvider.js @@ -0,0 +1,42 @@ +import React from 'react'; +import { DialogContent } from 'components'; +import { useCreateCashflowTransaction, useAccounts } from 'hooks/query'; + +const MoneyInDialogContent = React.createContext(); + +/** + * Money in dialog provider. + */ +function MoneyInDialogProvider({ accountId, dialogName, ...props }) { + // Fetches accounts list. + const { isFetching: isAccountsLoading, data: accounts } = useAccounts(); + + const { mutateAsync: createCashflowTransactionMutate } = + useCreateCashflowTransaction(); + + // Submit payload. + const [submitPayload, setSubmitPayload] = React.useState({}); + + // provider. + const provider = { + accounts, + accountId, + isAccountsLoading, + + submitPayload, + dialogName, + + createCashflowTransactionMutate, + setSubmitPayload, + }; + + return ( + + + + ); +} + +const useMoneyInDailogContext = () => React.useContext(MoneyInDialogContent); + +export { MoneyInDialogProvider, useMoneyInDailogContext }; diff --git a/src/containers/Dialogs/MoneyInDialog/MoneyInFloatingActions.js b/src/containers/Dialogs/MoneyInDialog/MoneyInFloatingActions.js new file mode 100644 index 000000000..b33647f0f --- /dev/null +++ b/src/containers/Dialogs/MoneyInDialog/MoneyInFloatingActions.js @@ -0,0 +1,76 @@ +import React from 'react'; +import { Intent, Button, Classes } from '@blueprintjs/core'; +import { useFormikContext } from 'formik'; +import { FormattedMessage as T } from 'components'; + +import { useMoneyInDailogContext } from './MoneyInDialogProvider'; + +import withDialogActions from 'containers/Dialog/withDialogActions'; +import { compose } from 'utils'; + +/** + * Money in floating actions. + */ +function MoneyInFloatingActions({ + // #withDialogActions + closeDialog, +}) { + // Formik context. + const { isSubmitting, submitForm } = useFormikContext(); + // money in dialog context. + const { dialogName, setSubmitPayload, submitPayload } = + useMoneyInDailogContext(); + + // handle submit as draft button click. + const handleSubmitDraftBtnClick = (event) => { + setSubmitPayload({ publish: false }); + submitForm(); + }; + + // Handle submit button click. + const handleSubmittBtnClick = (event) => { + setSubmitPayload({ publish: true }); + submitForm(); + }; + + // Handle close button click. + const handleCloseBtnClick = (event) => { + closeDialog(dialogName); + }; + + return ( +
+
+ + + + +
+
+ ); +} + +export default compose(withDialogActions)(MoneyInFloatingActions); diff --git a/src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeForm.js b/src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeForm.js new file mode 100644 index 000000000..8ffcab15a --- /dev/null +++ b/src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeForm.js @@ -0,0 +1,91 @@ +import React from 'react'; +import moment from 'moment'; +import { Intent } from '@blueprintjs/core'; +import { Formik } from 'formik'; +import intl from 'react-intl-universal'; + +import 'style/pages/CashFlow/CashflowTransactionForm.scss'; + +import { AppToaster } from 'components'; +import { CreateOtherIncomeFormSchema } from './OtherIncomeForm.schema'; +import OtherIncomeFormContent from './OtherIncomeFormContent'; + +import { useMoneyInDailogContext } from '../MoneyInDialogProvider'; + +import withDialogActions from 'containers/Dialog/withDialogActions'; +import withCurrentOrganization from 'containers/Organization/withCurrentOrganization'; + +import { compose } from 'utils'; + +const defaultInitialValues = { + date: moment(new Date()).format('YYYY-MM-DD'), + amount: '', + transaction_number: '', + transaction_type: 'other_income', + reference_no: '', + cashflow_account_id: '', + credit_account_id: '', + description: '', + published: '', +}; + +/** + * Other income form. + */ +function OtherIncomeForm({ + // #withDialogActions + closeDialog, + + // #withCurrentOrganization + organization: { base_currency }, +}) { + const { + dialogName, + accountId, + createCashflowTransactionMutate, + submitPayload, + } = useMoneyInDailogContext(); + + // Initial form values. + const initialValues = { + ...defaultInitialValues, + currency_code: base_currency, + credit_account_id: accountId, + }; + + // Handles the form submit. + const handleFormSubmit = (values, { setSubmitting, setErrors }) => { + const form = { + ...values, + published: submitPayload.publish, + }; + setSubmitting(true); + createCashflowTransactionMutate(form) + .then(() => { + closeDialog(dialogName); + + AppToaster.show({ + message: intl.get('cash_flow_transaction_success_message'), + intent: Intent.SUCCESS, + }); + }) + .finally(() => { + setSubmitting(true); + }); + }; + + return ( + + + + ); +} + +export default compose( + withDialogActions, + withCurrentOrganization(), +)(OtherIncomeForm); diff --git a/src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeForm.schema.js b/src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeForm.schema.js new file mode 100644 index 000000000..f6178739d --- /dev/null +++ b/src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeForm.schema.js @@ -0,0 +1,22 @@ +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().label(intl.get('amount')), + transaction_number: Yup.string(), + transaction_type: Yup.string().required().label(intl.get('transaction_type')), + reference_no: Yup.string(), + credit_account_id: Yup.number().required(), + cashflow_account_id: Yup.string() + .required() + .label(intl.get('other_income_account')), + description: Yup.string() + .min(3) + .max(DATATYPES_LENGTH.TEXT) + .label(intl.get('description')), + published: Yup.boolean(), +}); + +export const CreateOtherIncomeFormSchema = Schema; diff --git a/src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeFormContent.js b/src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeFormContent.js new file mode 100644 index 000000000..e05f48788 --- /dev/null +++ b/src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeFormContent.js @@ -0,0 +1,17 @@ +import React from 'react'; +import { Form } from 'formik'; + +import OtherIncomeFormFields from './OtherIncomeFormFields'; +import MoneyInFloatingActions from '../MoneyInFloatingActions'; + +/** + * Other income form content. + */ +export default function OtherIncomeFormContent() { + return ( +
+ + + + ); +} diff --git a/src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeFormFields.js b/src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeFormFields.js new file mode 100644 index 000000000..a181ccd4a --- /dev/null +++ b/src/containers/Dialogs/MoneyInDialog/OtherIncome/OtherIncomeFormFields.js @@ -0,0 +1,186 @@ +import React from 'react'; +import { FastField, ErrorMessage } from 'formik'; +import { + Classes, + FormGroup, + InputGroup, + TextArea, + Position, + ControlGroup, +} from '@blueprintjs/core'; +import classNames from 'classnames'; +import { + FormattedMessage as T, + AccountsSuggestField, + InputPrependText, + MoneyInputGroup, +} from 'components'; +import { DateInput } from '@blueprintjs/datetime'; +import { useAutofocus } from 'hooks'; +import { FieldRequiredHint, Col, Row } from 'components'; +import { + inputIntent, + momentFormatter, + tansformDateValue, + handleDateChange, +} from 'utils'; +import { CLASSES } from 'common/classes'; +import { useMoneyInDailogContext } from '../MoneyInDialogProvider'; + +/** + * Other income form fiedls. + */ +function OtherIncomeFormFields() { + // Money in dialog context. + const { accounts } = useMoneyInDailogContext(); + + const amountFieldRef = useAutofocus(); + + return ( +
+ + + {/*------------ Date -----------*/} + + {({ form, field: { value }, meta: { error, touched } }) => ( + } + labelInfo={} + intent={inputIntent({ error, touched })} + helperText={} + minimal={true} + className={classNames(CLASSES.FILL, 'form-group--date')} + > + { + form.setFieldValue('date', formattedDate); + })} + value={tansformDateValue(value)} + popoverProps={{ + position: Position.BOTTOM, + minimal: true, + }} + intent={inputIntent({ error, touched })} + /> + + )} + + + + {/*------------ Transaction number -----------*/} + + {({ form, field, meta: { error, touched } }) => ( + } + intent={inputIntent({ error, touched })} + helperText={} + className={'form-group--transaction_number'} + > + + + )} + + + + {/*------------ amount -----------*/} + + {({ + form: { values, setFieldValue }, + field: { value }, + meta: { error, touched }, + }) => ( + } + labelInfo={} + intent={inputIntent({ error, touched })} + helperText={} + className={'form-group--amount'} + > + + + + { + setFieldValue('amount', amount); + }} + inputRef={(ref) => (amountFieldRef.current = ref)} + intent={inputIntent({ error, touched })} + /> + + + )} + + + + + {/*------------ other income account -----------*/} + + {({ form, field, meta: { error, touched } }) => ( + } + labelInfo={} + intent={inputIntent({ error, touched })} + helperText={} + className={'form-group--cashflow_account_id'} + > + + form.setFieldValue('cashflow_account_id', id) + } + inputProps={{ + intent: inputIntent({ error, touched }), + }} + /> + + )} + + + + {/*------------ Reference -----------*/} + + {({ form, field, meta: { error, touched } }) => ( + } + intent={inputIntent({ error, touched })} + helperText={} + className={'form-group--reference-no'} + > + + + )} + + + + {/*------------ description -----------*/} + + {({ field, meta: { error, touched } }) => ( + } + className={'form-group--description'} + intent={inputIntent({ error, touched })} + helperText={} + > +