From b6a1c9ab4b4ba618323e9b30f81678795d6b19d2 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Mon, 26 Jun 2023 20:57:52 +0200 Subject: [PATCH 1/9] fix(webapp): payment made form does not handle not unique number an error message --- .../Dialogs/QuickPaymentMadeFormDialog/utils.tsx | 7 ++++--- .../Purchases/PaymentMades/PaymentForm/utils.tsx | 5 +++-- .../src/containers/Purchases/PaymentMades/constants.ts | 5 +++++ 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 packages/webapp/src/containers/Purchases/PaymentMades/constants.ts diff --git a/packages/webapp/src/containers/Dialogs/QuickPaymentMadeFormDialog/utils.tsx b/packages/webapp/src/containers/Dialogs/QuickPaymentMadeFormDialog/utils.tsx index 1b659194d..b90e21da8 100644 --- a/packages/webapp/src/containers/Dialogs/QuickPaymentMadeFormDialog/utils.tsx +++ b/packages/webapp/src/containers/Dialogs/QuickPaymentMadeFormDialog/utils.tsx @@ -7,6 +7,7 @@ import { Intent } from '@blueprintjs/core'; import { AppToaster } from '@/components'; import { useFormikContext } from 'formik'; import { useQuickPaymentMadeContext } from './QuickPaymentMadeFormProvider'; +import { PAYMENT_MADE_ERRORS } from '@/containers/Purchases/PaymentMades/constants'; // Default initial values of payment made. export const defaultPaymentMade = { @@ -24,16 +25,16 @@ export const defaultPaymentMade = { export const transformErrors = (errors, { setFieldError }) => { const getError = (errorType) => errors.find((e) => e.type === errorType); - if (getError('PAYMENT.NUMBER.NOT.UNIQUE')) { + if (getError(PAYMENT_MADE_ERRORS.PAYMENT_NUMBER_NOT_UNIQUE)) { setFieldError('payment_number', intl.get('payment_number_is_not_unique')); } - if (getError('INVALID_BILL_PAYMENT_AMOUNT')) { + if (getError(PAYMENT_MADE_ERRORS.INVALID_BILL_PAYMENT_AMOUNT)) { setFieldError( 'payment_amount', intl.get('the_payment_amount_bigger_than_invoice_due_amount'), ); } - if (getError('WITHDRAWAL_ACCOUNT_CURRENCY_INVALID')) { + if (getError(PAYMENT_MADE_ERRORS.WITHDRAWAL_ACCOUNT_CURRENCY_INVALID)) { AppToaster.show({ message: intl.get( 'payment_made.error.withdrawal_account_currency_invalid', diff --git a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/utils.tsx b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/utils.tsx index 0714d1042..1b94ef4d6 100644 --- a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/utils.tsx +++ b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/utils.tsx @@ -15,6 +15,7 @@ import { formattedAmount, } from '@/utils'; import { useCurrentOrganization } from '@/hooks/state'; +import { PAYMENT_MADE_ERRORS } from '../constants'; export const ERRORS = { PAYMENT_NUMBER_NOT_UNIQUE: 'PAYMENT.NUMBER.NOT.UNIQUE', @@ -124,10 +125,10 @@ export const useSetPrimaryBranchToForm = () => { export const transformErrors = (errors, { setFieldError }) => { const getError = (errorType) => errors.find((e) => e.type === errorType); - if (getError('PAYMENT_NUMBER_NOT_UNIQUE')) { + if (getError(PAYMENT_MADE_ERRORS.PAYMENT_NUMBER_NOT_UNIQUE)) { setFieldError('payment_number', intl.get('payment_number_is_not_unique')); } - if (getError('WITHDRAWAL_ACCOUNT_CURRENCY_INVALID')) { + if (getError(PAYMENT_MADE_ERRORS.WITHDRAWAL_ACCOUNT_CURRENCY_INVALID)) { AppToaster.show({ message: intl.get( 'payment_made.error.withdrawal_account_currency_invalid', diff --git a/packages/webapp/src/containers/Purchases/PaymentMades/constants.ts b/packages/webapp/src/containers/Purchases/PaymentMades/constants.ts new file mode 100644 index 000000000..1813c867c --- /dev/null +++ b/packages/webapp/src/containers/Purchases/PaymentMades/constants.ts @@ -0,0 +1,5 @@ +export const PAYMENT_MADE_ERRORS = { + PAYMENT_NUMBER_NOT_UNIQUE: 'PAYMENT.NUMBER.NOT.UNIQUE', + WITHDRAWAL_ACCOUNT_CURRENCY_INVALID: 'WITHDRAWAL_ACCOUNT_CURRENCY_INVALID', + INVALID_BILL_PAYMENT_AMOUNT: 'INVALID_BILL_PAYMENT_AMOUNT' +}; From 6373862044932020f821cb281203d990145cb5ba Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Tue, 27 Jun 2023 21:32:04 +0200 Subject: [PATCH 2/9] fix(webapp): No currency in amount field on money in/out dialogs --- packages/webapp/src/constants/sidebarMenu.tsx | 8 +- .../MoneyInDialog/MoneyInContentFields.tsx | 26 ++-- .../MoneyInDialog/MoneyInDialogContent.tsx | 1 - .../MoneyInDialog/MoneyInDialogProvider.tsx | 25 +-- .../MoneyInExchangeRateField.tsx | 26 ++++ .../MoneyInDialog/MoneyInFieldsProvider.tsx | 34 ++++ .../CashFlow/MoneyInDialog/MoneyInForm.tsx | 18 +-- .../MoneyInDialog/MoneyInFormFields.tsx | 10 +- .../OtherIncome/OtherIncomeFormFields.tsx | 126 +++++---------- .../OwnerContributionFormFields.tsx | 112 +++++--------- .../MoneyInDialog/TransactionTypeFields.tsx | 61 +++----- .../TransferFromAccountFormFields.tsx | 135 +++++----------- .../CashFlow/MoneyInDialog/index.tsx | 1 - .../CashFlow/MoneyInDialog/utils.tsx | 3 +- .../MoneyOutDialog/MoneyOutContentFields.tsx | 25 ++- .../MoneyOutDialog/MoneyOutDialogProvider.tsx | 28 ++-- .../MoneyOutExchangeRateField.tsx | 31 ++++ .../MoneyOutDialog/MoneyOutFieldsProvider.tsx | 34 ++++ .../MoneyOutFloatingActions.tsx | 10 +- .../CashFlow/MoneyOutDialog/MoneyOutForm.tsx | 16 +- .../MoneyOutDialog/MoneyOutFormDialog.tsx | 1 + .../MoneyOutDialog/MoneyOutFormFields.tsx | 14 +- .../OtherExpense/OtherExpnseFormFields.tsx | 137 +++++----------- .../OwnerDrawings/OwnerDrawingsFormFields.tsx | 126 +++++---------- .../MoneyOutDialog/TransactionTypeFields.tsx | 72 ++++----- .../TransferToAccountFormFields.tsx | 146 ++++++------------ .../CashFlow/MoneyOutDialog/utils.tsx | 3 +- .../CashFlow/CashflowTransactionForm.scss | 30 +--- 28 files changed, 519 insertions(+), 740 deletions(-) create mode 100644 packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInExchangeRateField.tsx create mode 100644 packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInFieldsProvider.tsx create mode 100644 packages/webapp/src/containers/CashFlow/MoneyOutDialog/MoneyOutExchangeRateField.tsx create mode 100644 packages/webapp/src/containers/CashFlow/MoneyOutDialog/MoneyOutFieldsProvider.tsx diff --git a/packages/webapp/src/constants/sidebarMenu.tsx b/packages/webapp/src/constants/sidebarMenu.tsx index 9a60691d2..3f5c16cb1 100644 --- a/packages/webapp/src/constants/sidebarMenu.tsx +++ b/packages/webapp/src/constants/sidebarMenu.tsx @@ -25,6 +25,7 @@ import { CashflowAction, PreferencesAbility, } from '@/constants/abilityOption'; +import { DialogsName } from './dialogs'; export const SidebarMenu = [ // --------------- @@ -114,7 +115,7 @@ export const SidebarMenu = [ text: , href: '/items/categories/new', type: ISidebarMenuItemType.Dialog, - dialogName: 'item-category-form', + dialogName: DialogsName.ItemCategoryForm, permission: { subject: AbilitySubject.Item, ability: ItemAction.Create, @@ -458,7 +459,7 @@ export const SidebarMenu = [ text: , href: '/cashflow-accounts', type: ISidebarMenuItemType.Dialog, - dialogName: 'money-in', + dialogName: DialogsName.MoneyInForm, permission: { subject: AbilitySubject.Cashflow, ability: CashflowAction.Create, @@ -468,6 +469,7 @@ export const SidebarMenu = [ text: , href: '/cashflow-accounts', type: ISidebarMenuItemType.Dialog, + dialogName: DialogsName.MoneyOutForm, permission: { subject: AbilitySubject.Cashflow, ability: CashflowAction.Create, @@ -477,6 +479,7 @@ export const SidebarMenu = [ text: , href: '/cashflow-accounts', type: ISidebarMenuItemType.Dialog, + dialogName: DialogsName.AccountForm, permission: { subject: AbilitySubject.Cashflow, ability: CashflowAction.Create, @@ -486,6 +489,7 @@ export const SidebarMenu = [ text: , href: '/cashflow-accounts', type: ISidebarMenuItemType.Dialog, + dialogName: DialogsName.AccountForm, permission: { subject: AbilitySubject.Cashflow, ability: CashflowAction.Create, diff --git a/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInContentFields.tsx b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInContentFields.tsx index ee862b763..a5746c5f5 100644 --- a/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInContentFields.tsx +++ b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInContentFields.tsx @@ -1,18 +1,22 @@ // @ts-nocheck -import React from 'react'; +import React, { useMemo } from 'react'; +import { useFormikContext } from 'formik'; import OwnerContributionFormFields from './OwnerContribution/OwnerContributionFormFields'; import OtherIncomeFormFields from './OtherIncome/OtherIncomeFormFields'; import TransferFromAccountFormFields from './TransferFromAccount/TransferFromAccountFormFields'; +import { MoneyInFieldsProvider } from './MoneyInFieldsProvider'; /** - * - * @param param0 - * @returns + * Money-in dialog content. + * Switches between fields based on the given transaction type. + * @returns {JSX.Element} */ -export default function MoneyInContentFields({ accountType }) { - const handleTransactionType = () => { - switch (accountType) { +export default function MoneyInContentFields() { + const { values } = useFormikContext(); + + const transactionFields = useMemo(() => { + switch (values.transaction_type) { case 'owner_contribution': return ; @@ -24,6 +28,10 @@ export default function MoneyInContentFields({ accountType }) { default: break; } - }; - return {handleTransactionType()}; + }, [values.transaction_type]); + + // Cannot continue if transaction type or account is not selected. + if (!values.transaction_type || !values.cashflow_account_id) return null; + + return {transactionFields}; } diff --git a/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInDialogContent.tsx b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInDialogContent.tsx index 1674c4ab7..690d720ef 100644 --- a/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInDialogContent.tsx +++ b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInDialogContent.tsx @@ -1,6 +1,5 @@ // @ts-nocheck import React from 'react'; - import { MoneyInDialogProvider } from './MoneyInDialogProvider'; import MoneyInForm from './MoneyInForm'; diff --git a/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInDialogProvider.tsx b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInDialogProvider.tsx index 338bcf045..163f87119 100644 --- a/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInDialogProvider.tsx +++ b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInDialogProvider.tsx @@ -1,11 +1,10 @@ // @ts-nocheck -import React from 'react'; +import React, { useState } from 'react'; import { DialogContent } from '@/components'; import { Features } from '@/constants'; import { useFeatureCan } from '@/hooks/state'; import { useCreateCashflowTransaction, - useAccount, useAccounts, useBranches, useCashflowAccounts, @@ -18,22 +17,21 @@ const MoneyInDialogContent = React.createContext(); * Money in dialog provider. */ function MoneyInDialogProvider({ - accountId, + accountId: defaultAccountId, accountType, dialogName, ...props }) { + // Holds the selected account id. + const [accountId, setAccountId] = useState(defaultAccountId); + + // Detarmines whether the feature is enabled. const { featureCan } = useFeatureCan(); const isBranchFeatureCan = featureCan(Features.Branches); // Fetches accounts list. const { isLoading: isAccountsLoading, data: accounts } = useAccounts(); - // Fetches the specific account details. - const { data: account, isLoading: isAccountLoading } = useAccount(accountId, { - enabled: !!accountId, - }); - // Fetches the branches list. const { data: branches, @@ -41,10 +39,11 @@ function MoneyInDialogProvider({ isSuccess: isBranchesSuccess, } = useBranches({}, { enabled: isBranchFeatureCan }); - // Fetch cash flow list . + // Fetch cash flow list. const { data: cashflowAccounts, isLoading: isCashFlowAccountsLoading } = useCashflowAccounts({}, { keepPreviousData: true }); + // Mutation create cashflow transaction. const { mutateAsync: createCashflowTransactionMutate } = useCreateCashflowTransaction(); @@ -57,9 +56,12 @@ function MoneyInDialogProvider({ // Provider data. const provider = { accounts, - account, branches, + accountId, + defaultAccountId, + setAccountId, + accountType, isAccountsLoading, isBranchesSuccess, @@ -77,8 +79,7 @@ function MoneyInDialogProvider({ isAccountsLoading || isCashFlowAccountsLoading || isBranchesLoading || - isSettingsLoading || - isAccountLoading; + isSettingsLoading; return ( diff --git a/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInExchangeRateField.tsx b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInExchangeRateField.tsx new file mode 100644 index 000000000..9f5dc056b --- /dev/null +++ b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInExchangeRateField.tsx @@ -0,0 +1,26 @@ +// @ts-nocheck +import React from 'react'; +import { ExchangeRateMutedField } from '@/components'; +import { useForeignAccount } from './utils'; +import { useFormikContext } from 'formik'; +import { useMoneyInFieldsContext } from './MoneyInFieldsProvider'; + +export function MoneyInExchangeRateField() { + const { account } = useMoneyInFieldsContext(); + const { values } = useFormikContext(); + + const isForeigAccount = useForeignAccount(); + + if (!isForeigAccount) return null; + + return ( + + ); +} diff --git a/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInFieldsProvider.tsx b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInFieldsProvider.tsx new file mode 100644 index 000000000..22756d430 --- /dev/null +++ b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInFieldsProvider.tsx @@ -0,0 +1,34 @@ +// @ts-nocheck +import React from 'react'; +import { DialogContent } from '@/components'; +import { useAccount } from '@/hooks/query'; +import { useMoneyInDailogContext } from './MoneyInDialogProvider'; + +const MoneyInFieldsContext = React.createContext(); + +/** + * Money in dialog provider. + */ +function MoneyInFieldsProvider({ ...props }) { + const { accountId } = useMoneyInDailogContext(); + + // Fetches the specific account details. + const { data: account, isLoading: isAccountLoading } = useAccount(accountId, { + enabled: !!accountId, + }); + // Provider data. + const provider = { + account, + }; + const isLoading = isAccountLoading; + + return ( + + + + ); +} + +const useMoneyInFieldsContext = () => React.useContext(MoneyInFieldsContext); + +export { MoneyInFieldsProvider, useMoneyInFieldsContext }; diff --git a/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInForm.tsx b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInForm.tsx index e741e8ae5..9bdc1f9ed 100644 --- a/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInForm.tsx +++ b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInForm.tsx @@ -53,7 +53,6 @@ function MoneyInForm({ accountId, accountType, createCashflowTransactionMutate, - submitPayload, } = useMoneyInDailogContext(); // transaction number. @@ -61,7 +60,6 @@ function MoneyInForm({ transactionNumberPrefix, transactionNextNumber, ); - // Initial form values. const initialValues = { ...defaultInitialValues, @@ -95,15 +93,13 @@ function MoneyInForm({ }; return ( -
- - - -
+ + + ); } diff --git a/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInFormFields.tsx b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInFormFields.tsx index cd1e2a46d..ec6729dcc 100644 --- a/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInFormFields.tsx +++ b/packages/webapp/src/containers/CashFlow/MoneyInDialog/MoneyInFormFields.tsx @@ -12,17 +12,13 @@ import { useMoneyInDailogContext } from './MoneyInDialogProvider'; * Money in form fields. */ function MoneyInFormFields() { - const { values } = useFormikContext(); - // Money in dialog context. - const { accountId } = useMoneyInDailogContext(); + const { defaultAccountId } = useMoneyInDailogContext(); return (
- - - - + {!defaultAccountId && } +
); } diff --git a/packages/webapp/src/containers/CashFlow/MoneyInDialog/OtherIncome/OtherIncomeFormFields.tsx b/packages/webapp/src/containers/CashFlow/MoneyInDialog/OtherIncome/OtherIncomeFormFields.tsx index 06ccffea0..30ad76e9b 100644 --- a/packages/webapp/src/containers/CashFlow/MoneyInDialog/OtherIncome/OtherIncomeFormFields.tsx +++ b/packages/webapp/src/containers/CashFlow/MoneyInDialog/OtherIncome/OtherIncomeFormFields.tsx @@ -1,10 +1,9 @@ // @ts-nocheck import React from 'react'; -import { FastField, Field, ErrorMessage, useFormikContext } from 'formik'; +import { FastField, ErrorMessage } from 'formik'; import { Classes, FormGroup, - InputGroup, TextArea, Position, ControlGroup, @@ -18,14 +17,15 @@ import { FieldRequiredHint, Col, Row, - If, FeatureCan, BranchSelect, BranchSelectButton, - ExchangeRateMutedField, + FInputGroup, + FFormGroup, + FTextArea, + FMoneyInputGroup, } from '@/components'; import { DateInput } from '@blueprintjs/datetime'; -import { useAutofocus } from '@/hooks'; import { CLASSES, ACCOUNT_TYPE, Features } from '@/constants'; import { @@ -36,22 +36,18 @@ import { } from '@/utils'; import { useMoneyInDailogContext } from '../MoneyInDialogProvider'; -import { - useSetPrimaryBranchToForm, - useForeignAccount, - BranchRowDivider, -} from '../utils'; +import { useSetPrimaryBranchToForm, BranchRowDivider } from '../utils'; import { MoneyInOutTransactionNoField } from '../../_components'; +import { useMoneyInFieldsContext } from '../MoneyInFieldsProvider'; +import { MoneyInExchangeRateField } from '../MoneyInExchangeRateField'; /** * Other income form fields. */ export default function OtherIncomeFormFields() { // Money in dialog context. - const { accounts, account, branches } = useMoneyInDailogContext(); - const { values } = useFormikContext(); - const amountFieldRef = useAutofocus(); - const isForeigAccount = useForeignAccount(); + const { accounts, branches } = useMoneyInDailogContext(); + const { account } = useMoneyInFieldsContext(); // Sets the primary branch to form. useSetPrimaryBranchToForm(); @@ -61,17 +57,14 @@ export default function OtherIncomeFormFields() { - } - className={classNames('form-group--select-list', Classes.FILL)} - > + }> - + @@ -111,48 +104,26 @@ export default function OtherIncomeFormFields() { - {/*------------ 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 })} - /> + - - )} - + + + + + {/*------------ Exchange rate -----------*/} + - - {/*------------ exchange rate -----------*/} - - {/*------------ other income account -----------*/} @@ -182,43 +153,24 @@ export default function OtherIncomeFormFields() { )} + {/*------------ Reference -----------*/} - - {({ form, field, meta: { error, touched } }) => ( - } - intent={inputIntent({ error, touched })} - helperText={} - className={'form-group--reference-no'} - > - - - )} - + } name={'reference_no'}> + + - {/*------------ description -----------*/} - - {({ field, meta: { error, touched } }) => ( - } - className={'form-group--description'} - intent={inputIntent({ error, touched })} - helperText={} - > -