Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UIORGS-390 Implement organization's banking information form #580

Merged
merged 17 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

* Designate Organization as donor. Refs UIORGS-383.
* Settings for banking information. Refs UIORGS-391.
* Implement organization's banking information form. Refs UIORGS-390.

## [5.0.0](https://github.com/folio-org/ui-organizations/tree/v5.0.0) (2023-10-12)
[Full Changelog](https://github.com/folio-org/ui-organizations/compare/v4.0.0...v5.0.0)
Expand Down
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"home": "/organizations",
"okapiInterfaces": {
"acquisition-methods": "1.0",
"banking-information": "1.0",
"data-export-spring": "1.0",
"configuration": "2.0",
"organizations.organizations": "1.0",
Expand Down Expand Up @@ -80,6 +81,8 @@
"data-export.config.item.get",
"orders.acquisition-methods.collection.get",
"orders.acquisition-method.item.get",
"organizations.banking-information.collection.get",
"organizations.banking-information.item.get",
"organizations.organizations.collection.get",
"organizations.organizations.item.get",
"organizations-storage.addresses.collection.get",
Expand Down Expand Up @@ -108,6 +111,7 @@
"data-export.config.item.delete",
"data-export.config.item.post",
"data-export.config.item.put",
"organizations.banking-information.item.put",
"organizations.organizations.item.put",
"organizations-storage.addresses.item.put",
"organizations-storage.emails.item.put",
Expand All @@ -127,6 +131,7 @@
"displayName": "Organizations: View, edit, create",
"visible": true,
"subPermissions": [
"organizations.banking-information.item.post",
"organizations.organizations.item.post",
"organizations-storage.addresses.item.post",
"organizations-storage.emails.item.post",
Expand All @@ -140,6 +145,7 @@
"displayName": "Organizations: View, edit, delete",
"visible": true,
"subPermissions": [
"organizations.banking-information.item.delete",
"organizations.organizations.item.delete",
"organizations-storage.addresses.item.delete",
"organizations-storage.emails.item.delete",
Expand Down
39 changes: 28 additions & 11 deletions src/Organizations/OrganizationCreate/OrganizationCreate.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import React, { useCallback } 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,9 +45,21 @@ export const OrganizationCreate = ({ history, location, mutator }) => {

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

const createOrganization = useCallback(
(data) => {
(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,
organization,
});

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

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

return (
<OrganizationForm
initialValues={INITIAL_VALUES}
initialValues={initialValues}
onSubmit={createOrganization}
cancelForm={cancelForm}
/>
Expand Down
42 changes: 38 additions & 4 deletions src/Organizations/OrganizationCreate/OrganizationCreate.test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import React from 'react';
import { QueryClient, QueryClientProvider } from 'react-query';
import { render, screen } from '@folio/jest-config-stripes/testing-library/react';

import { OrganizationForm } from '../OrganizationForm';

import { useBankingInformationManager } from '../useBankingInformationManager';
import { OrganizationCreate } from './OrganizationCreate';

jest.mock('../OrganizationForm', () => ({
OrganizationForm: jest.fn().mockReturnValue('OrganizationForm'),
}));
jest.mock('../useBankingInformationManager', () => ({
useBankingInformationManager: jest.fn(),
}));

const mutatorMock = {
createOrganizationOrg: {
Expand All @@ -17,21 +20,40 @@ const mutatorMock = {
const historyMock = {
push: jest.fn(),
};

const getFieldState = jest.fn();
const manageBankingInformation = jest.fn();

const queryClient = new QueryClient();

const wrapper = ({ children }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);

const renderOrganizationCreate = (props) => render(
<OrganizationCreate
location={{}}
history={historyMock}
mutator={mutatorMock}
{...props}
/>,
{ wrapper },
);

describe('OrganizationCreate', () => {
beforeEach(() => {
OrganizationForm.mockClear();

getFieldState.mockClear();
historyMock.push.mockClear();
manageBankingInformation.mockClear();
mutatorMock.createOrganizationOrg.POST.mockClear();

useBankingInformationManager
.mockClear()
.mockReturnValue({ manageBankingInformation });
});

it('should display organization form', () => {
Expand All @@ -56,11 +78,23 @@ describe('OrganizationCreate', () => {
expect(historyMock.push.mock.calls[0][0].pathname).toBe('/organizations/view/orgUid');
});

it('should save organization', () => {
it('should save organization', async () => {
mutatorMock.createOrganizationOrg.POST.mockReturnValue(Promise.resolve({ id: 'orgUid' }));

renderOrganizationCreate();

OrganizationForm.mock.calls[0][0].onSubmit({});
await OrganizationForm.mock.calls[0][0].onSubmit({}, { getFieldState });

expect(mutatorMock.createOrganizationOrg.POST).toHaveBeenCalled();
});

it('should handle banking information on form submit', async () => {
mutatorMock.createOrganizationOrg.POST.mockReturnValue(Promise.resolve({ id: 'orgUid' }));

renderOrganizationCreate();

await OrganizationForm.mock.calls[0][0].onSubmit({}, { getFieldState });

expect(manageBankingInformation).toHaveBeenCalled();
});
});
43 changes: 34 additions & 9 deletions src/Organizations/OrganizationEdit/OrganizationEdit.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {
import {
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
Expand All @@ -19,27 +20,35 @@ import {
} from '@folio/stripes-acq-components';

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;

const [organization, setOrganization] = useState({});
const [isLoading, setIsLoading] = useState(true);
const [isOrganizationLoading, setIsOrganizationLoading] = useState(true);
const showCallout = useShowCallout();
const intl = useIntl();

const { manageBankingInformation } = useBankingInformationManager();

const {
bankingInformation: bankingInformationData,
isLoading: isBankingInformationLoading,
} = useOrganizationBankingInformation(organizationId);

useEffect(
() => {
mutator.editOrganizationOrg.GET()
.then(organizationsResponse => {
setOrganization(organizationsResponse);
})
.finally(() => setIsLoading(false));
.finally(() => setIsOrganizationLoading(false));
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[],
Expand All @@ -58,8 +67,17 @@ export const OrganizationEdit = ({ match, history, location, mutator }) => {
);

const updateOrganization = useCallback(
(data) => {
(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,
organization: values,
});
})
.then(() => {
setTimeout(cancelForm);
showCallout({
Expand All @@ -72,9 +90,16 @@ 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(() => ({
[BANKING_INFORMATION_FIELD_NAME]: bankingInformationData,
...organization,
}), [organization, bankingInformationData]);

const isLoading = isOrganizationLoading || isBankingInformationLoading;

if (isLoading) {
return (
<Paneset>
Expand All @@ -85,7 +110,7 @@ export const OrganizationEdit = ({ match, history, location, mutator }) => {

return (
<OrganizationForm
initialValues={organization}
initialValues={initialValues}
onSubmit={updateOrganization}
cancelForm={cancelForm}
paneTitle={<FormattedMessage id="ui-organizations.editOrg.title" values={{ name: organization.name }} />}
Expand Down
Loading
Loading