Skip to content

Commit

Permalink
UIORGS-390 Implement logic for banking information management
Browse files Browse the repository at this point in the history
  • Loading branch information
usavkov-epam committed Nov 13, 2023
1 parent 92d7a99 commit 924a07e
Show file tree
Hide file tree
Showing 14 changed files with 195 additions and 28 deletions.
34 changes: 21 additions & 13 deletions src/Organizations/OrganizationCreate/OrganizationCreate.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { useCallback, useMemo } from 'react';
import { useIntl } from 'react-intl';
import { withRouter } from 'react-router-dom';

import {
stripesConnect,
} from '@folio/stripes/core';
import { stripesConnect } from '@folio/stripes/core';
import { useShowCallout } from '@folio/stripes-acq-components';

import { VIEW_ORG_DETAILS } from '../../common/constants';
import { organizationsResource } from '../../common/resources';
import {
OrganizationForm,
} from '../OrganizationForm';
import { BANKING_INFORMATION_FIELD_NAME } from '../constants';
import { handleSaveErrorResponse } from '../handleSaveErrorResponse';
import { OrganizationForm } from '../OrganizationForm';
import { useBankingInformationManager } from '../useBankingInformationManager';

const INITIAL_VALUES = {
interfaces: [],
Expand All @@ -32,6 +30,8 @@ const INITIAL_VALUES = {
};

export const OrganizationCreate = ({ history, location, mutator }) => {
const { manageBankingInformation } = useBankingInformationManager();

const cancelForm = useCallback(
(id) => {
history.push({
Expand All @@ -45,12 +45,20 @@ export const OrganizationCreate = ({ history, location, mutator }) => {

const showCallout = useShowCallout();
const intl = useIntl();

const createOrganization = useCallback(
({ bankingInformation, ...data }) => {
// TODO: implement create banking info logic
console.log('bankingInformation on create', bankingInformation);
(values, { getFieldState }) => {
const { [BANKING_INFORMATION_FIELD_NAME]: bankingInformation, ...data } = values;

return mutator.createOrganizationOrg.POST(data)
.then(async organization => {
await manageBankingInformation({
initBankingInformation: getFieldState(BANKING_INFORMATION_FIELD_NAME).initial,
bankingInformation,
});

return organization;
})
.then(organization => {
setTimeout(() => cancelForm(organization.id));
showCallout({
Expand All @@ -63,12 +71,12 @@ export const OrganizationCreate = ({ history, location, mutator }) => {
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[cancelForm, intl, showCallout],
[cancelForm, intl, manageBankingInformation, showCallout],
);

// TODO: provide info without perms and setting?
const initialValues = useMemo(() => ({
bankingInformation: [],
[BANKING_INFORMATION_FIELD_NAME]: [],
...INITIAL_VALUES,
}), []);

Expand Down
23 changes: 15 additions & 8 deletions src/Organizations/OrganizationEdit/OrganizationEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import {
import { VIEW_ORG_DETAILS } from '../../common/constants';
import { useOrganizationBankingInformation } from '../../common/hooks';
import { organizationResourceByUrl } from '../../common/resources';
import {
OrganizationForm,
} from '../OrganizationForm';
import { BANKING_INFORMATION_FIELD_NAME } from '../constants';
import { OrganizationForm } from '../OrganizationForm';
import { handleSaveErrorResponse } from '../handleSaveErrorResponse';
import { useBankingInformationManager } from '../useBankingInformationManager';

export const OrganizationEdit = ({ match, history, location, mutator }) => {
const organizationId = match.params.id;
Expand All @@ -35,6 +35,8 @@ export const OrganizationEdit = ({ match, history, location, mutator }) => {
const showCallout = useShowCallout();
const intl = useIntl();

const { manageBankingInformation } = useBankingInformationManager();

const {
bankingInformation: bankingInformationData,
isLoading: isBankingInformationLoading,
Expand Down Expand Up @@ -65,11 +67,16 @@ export const OrganizationEdit = ({ match, history, location, mutator }) => {
);

const updateOrganization = useCallback(
({ bankingInformation, ...data }) => {
// TODO: implement create/update banking info logic
console.log('bankingInformation on update', bankingInformation);
(values, { getFieldState }) => {
const { [BANKING_INFORMATION_FIELD_NAME]: bankingInformation, ...data } = values;

return mutator.editOrganizationOrg.PUT(data)
.then(() => {
return manageBankingInformation({
initBankingInformation: getFieldState(BANKING_INFORMATION_FIELD_NAME).initial,
bankingInformation,
});
})
.then(() => {
setTimeout(cancelForm);
showCallout({
Expand All @@ -82,11 +89,11 @@ export const OrganizationEdit = ({ match, history, location, mutator }) => {
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[cancelForm, intl, showCallout],
[cancelForm, intl, manageBankingInformation, showCallout],
);

const initialValues = useMemo(() => ({
bankingInformation: bankingInformationData,
[BANKING_INFORMATION_FIELD_NAME]: bankingInformationData,
...organization,
}), [organization, bankingInformationData]);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import PropTypes from 'prop-types';
import { useMemo } from 'react';
import { FormattedMessage } from 'react-intl';
import { FieldArray } from 'react-final-form-arrays';
Expand All @@ -11,6 +12,7 @@ import {
removeItem,
} from '../../../common/utils';
import { validatePrimary } from '../../../common/validation';
import { BANKING_INFORMATION_FIELD_NAME } from '../../constants';
import { BankingInformationField } from './BankingInformationField';

const renderField = (props) => (name, index, fields) => (
Expand All @@ -22,7 +24,7 @@ const renderField = (props) => (name, index, fields) => (
/>
);

export const OrganizationBankingInfoForm = () => {
export const OrganizationBankingInfoForm = ({ organizationId }) => {
const {
bankingAccountTypes,
isFetching,
Expand All @@ -44,11 +46,15 @@ export const OrganizationBankingInfoForm = () => {
addLabel={<FormattedMessage id="ui-organizations.button.bankingInformation.add" />}
component={RepeatableFieldWithValidation}
id="bankingInformation"
name="bankingInformation"
onAdd={createAddNewItem()}
name={BANKING_INFORMATION_FIELD_NAME}
onAdd={createAddNewItem(null, { organizationId })}
onRemove={removeItem}
renderField={renderField({ bankingAccountTypeOptions })}
validate={validatePrimary}
/>
);
};

OrganizationBankingInfoForm.propTypes = {
organizationId: PropTypes.string.isRequired,
};
2 changes: 1 addition & 1 deletion src/Organizations/OrganizationForm/OrganizationForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ const OrganizationForm = ({
id={ORGANIZATION_SECTIONS.bankingInformationSection}
label={ORGANIZATION_SECTION_LABELS[ORGANIZATION_SECTIONS.bankingInformationSection]}
>
<OrganizationBankingInfoForm />
<OrganizationBankingInfoForm organizationId={initialValues.id} />
</Accordion>

<Accordion
Expand Down
2 changes: 2 additions & 0 deletions src/Organizations/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ export const MAP_FIELD_ACCORDION = {
agreements: ORGANIZATION_SECTIONS.vendorTermsSection,
accounts: ORGANIZATION_SECTIONS.accountsSection,
};

export const BANKING_INFORMATION_FIELD_NAME = 'bankingInformation';
49 changes: 49 additions & 0 deletions src/Organizations/useBankingInformationManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import chunk from 'lodash/chunk';
import { useCallback } from 'react';

import { useShowCallout } from '@folio/stripes-acq-components';

import { useBankingInformationMutation } from '../common/hooks';
import { getArrayItemsChanges } from '../common/utils';

const execute = (fn, arr) => chunk(arr, 5).reduce((acc, chunked) => {
return acc.then(() => Promise.all(chunked.map((bankingInformation) => fn({ bankingInformation }))));
}, Promise.resolve());

export const useBankingInformationManager = () => {
const showCallout = useShowCallout();

const {
createBankingInformation,
updateBankingInformation,
deleteBankingInformation,
isLoading,
} = useBankingInformationMutation();

const manageBankingInformation = useCallback(({
initBankingInformation,
bankingInformation,
}) => {
const {
created,
updated,
deleted,
} = getArrayItemsChanges(initBankingInformation, bankingInformation);

return Promise.all([
execute(createBankingInformation, created),
execute(updateBankingInformation, updated),
execute(deleteBankingInformation, deleted),
]).catch(() => {
showCallout({
type: 'error',
messageId: 'ui-organizations.bankingInformation.save.error',
});
});
}, [showCallout]);

Check warning on line 43 in src/Organizations/useBankingInformationManager.js

View workflow job for this annotation

GitHub Actions / github-actions-ci

React Hook useCallback has missing dependencies: 'createBankingInformation', 'deleteBankingInformation', and 'updateBankingInformation'. Either include them or remove the dependency array

return {
manageBankingInformation,
isLoading,
};
};
1 change: 1 addition & 0 deletions src/common/hooks/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './useAcqMethods';
export * from './useBankingAccountTypes';
export * from './useBankingInformationMutation';
export * from './useBankingInformationSettings';
export * from './useIntegrationConfig';
export * from './useIntegrationConfigMutation';
Expand Down
1 change: 1 addition & 0 deletions src/common/hooks/useBankingInformationMutation/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useBankingInformationMutation } from './useBankingInformationMutation';
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useMutation } from 'react-query';

import { useOkapiKy } from '@folio/stripes/core';

import { BANKING_INFORMATION_API } from '../../constants';

export const useBankingInformationMutation = () => {
const ky = useOkapiKy();

const {
mutateAsync: createBankingInformation,
isLoading: isBankingInformationCreateLoading,
} = useMutation({
mutationFn: ({ bankingInformation }) => {
return ky.post(BANKING_INFORMATION_API, { json: bankingInformation }).json();
},
});

const {
mutateAsync: updateBankingInformation,
isLoading: isBankingInformationUpdateLoading,
} = useMutation({
mutationFn: ({ bankingInformation }) => {
return ky.put(
`${BANKING_INFORMATION_API}/${bankingInformation.id}`,
{ json: bankingInformation },
).json();
},
});

const {
mutateAsync: deleteBankingInformation,
isLoading: isBankingInformationDeleteLoading,
} = useMutation({
mutationFn: ({ bankingInformation }) => {
return ky.delete(`${BANKING_INFORMATION_API}/${bankingInformation.id}`).json();
},
});

const isLoading = (
isBankingInformationCreateLoading
|| isBankingInformationDeleteLoading
|| isBankingInformationUpdateLoading
);

return {
createBankingInformation,
updateBankingInformation,
deleteBankingInformation,
isLoading,
};
};
5 changes: 2 additions & 3 deletions src/common/utils/createAddNewItem.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// eslint-disable-next-line import/prefer-default-export
export function createAddNewItem(defaultLanguage) {
export function createAddNewItem(defaultLanguage, initialData = {}) {
return fields => {
const newItem = {};
const newItem = { ...initialData };

if (defaultLanguage) newItem.language = defaultLanguage;
if (fields.length === 0) newItem.isPrimary = true;
Expand Down
39 changes: 39 additions & 0 deletions src/common/utils/getArrayItemsChanges/getArrayItemsChanges.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import isEqual from 'lodash/isEqual';
import keyBy from 'lodash/keyBy';

/**
* Detects added, modified and deleted items in an array.
* The function assumes that each element of the array is an object structure.
*/
export const getArrayItemsChanges = (initialValues = [], values = []) => {
const initialValuesMap = keyBy(initialValues, 'id');
const valuesMap = keyBy(values, 'id');

const { created, updated } = values.reduce((acc, item) => {
const initItem = initialValuesMap[item.id];

if (!initItem) {
acc.created.push(item);
} else if (!isEqual(initItem, item)) {
acc.updated.push(item);
}

return acc;
}, { created: [], updated: [] });

const deleted = initialValues.reduce((acc, initItem) => {
const item = valuesMap[initItem.id];

if (!item) {
acc.push(initItem);
}

return acc;
}, []);

return {
created,
updated,
deleted,
};
};
1 change: 1 addition & 0 deletions src/common/utils/getArrayItemsChanges/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { getArrayItemsChanges } from './getArrayItemsChanges';
1 change: 1 addition & 0 deletions src/common/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './category';
export * from './createItem';
export * from './getArrayItemsChanges';
export * from './getResourceData';
export * from './hydrateContactInfo';
export * from './createAddNewItem';
Expand Down
1 change: 1 addition & 0 deletions translations/ui-organizations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@

"summary": "Summary",
"bankingInformation": "Banking information",
"bankingInformation.save.error": "Failed to save banking information.",
"contactInformation": "Contact information",
"contactPeople": "Contact people",
"agreements": "Agreements",
Expand Down

0 comments on commit 924a07e

Please sign in to comment.