diff --git a/CHANGELOG.md b/CHANGELOG.md index f7e5b9f8..24aef053 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Designate Organization as donor. Refs UIORGS-383. * Settings for banking information. Refs UIORGS-391. * Implement organization's banking information form. Refs UIORGS-390. +* Implement organization's banking information details view. Refs UIORGS-389. ## [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) diff --git a/src/Organizations/OrganizationDetails/OrganizationBankingInfo/BankingInformationCard/BankingInformationCard.js b/src/Organizations/OrganizationDetails/OrganizationBankingInfo/BankingInformationCard/BankingInformationCard.js new file mode 100644 index 00000000..49b74a93 --- /dev/null +++ b/src/Organizations/OrganizationDetails/OrganizationBankingInfo/BankingInformationCard/BankingInformationCard.js @@ -0,0 +1,94 @@ +import PropTypes from 'prop-types'; +import { useCallback } from 'react'; +import { FormattedMessage } from 'react-intl'; + +import { + Card, + Col, + KeyValue, + LayoutHeader, + Row, +} from '@folio/stripes/components'; + +const invalidReference = ; + +export const BankingInformationCard = ({ + bankingAccountTypesMap, + bankingInformation, + categoriesMap, +}) => { + const { + isPrimary, + bankName, + bankAccountNumber, + transitNumber, + categoryId, + accountTypeId, + notes, + } = bankingInformation; + + const renderHeader = useCallback(() => ( + } + noActions + /> + ), [isPrimary]); + + return ( + + + + } + value={bankName} + /> + + + } + value={bankAccountNumber} + /> + + + } + value={transitNumber} + /> + + + } + value={categoryId && (categoriesMap[categoryId]?.value ?? invalidReference)} + /> + + + } + value={accountTypeId && (bankingAccountTypesMap[accountTypeId]?.name ?? invalidReference)} + /> + + + } + value={notes} + /> + + + + ); +}; + +BankingInformationCard.propTypes = { + bankingAccountTypesMap: PropTypes.object.isRequired, + bankingInformation: PropTypes.shape({ + isPrimary: PropTypes.bool, + bankName: PropTypes.string, + bankAccountNumber: PropTypes.string, + transitNumber: PropTypes.string, + categoryId: PropTypes.string, + accountTypeId: PropTypes.string, + notes: PropTypes.string, + }).isRequired, + categoriesMap: PropTypes.object.isRequired, +}; diff --git a/src/Organizations/OrganizationDetails/OrganizationBankingInfo/BankingInformationCard/index.js b/src/Organizations/OrganizationDetails/OrganizationBankingInfo/BankingInformationCard/index.js new file mode 100644 index 00000000..56f2d8cb --- /dev/null +++ b/src/Organizations/OrganizationDetails/OrganizationBankingInfo/BankingInformationCard/index.js @@ -0,0 +1 @@ +export { BankingInformationCard } from './BankingInformationCard'; diff --git a/src/Organizations/OrganizationDetails/OrganizationBankingInfo/OrganizationBankingInfo.js b/src/Organizations/OrganizationDetails/OrganizationBankingInfo/OrganizationBankingInfo.js new file mode 100644 index 00000000..c34e93b6 --- /dev/null +++ b/src/Organizations/OrganizationDetails/OrganizationBankingInfo/OrganizationBankingInfo.js @@ -0,0 +1,53 @@ +import keyBy from 'lodash/keyBy'; +import PropTypes from 'prop-types'; +import { useMemo } from 'react'; + +import { Loading } from '@folio/stripes/components'; + +import { + useBankingAccountTypes, + useCategories, + useOrganizationBankingInformation, +} from '../../../common/hooks'; +import { BankingInformationCard } from './BankingInformationCard'; + +export const OrganizationBankingInfo = ({ organization }) => { + const { + bankingInformation, + isFetching: isBankingInformationFetching, + } = useOrganizationBankingInformation(organization.id); + + const { + categories, + isFetching: isCategoriesFetching, + } = useCategories(); + + const { + bankingAccountTypes, + isFetching: isBankingAccountTypesFetching, + } = useBankingAccountTypes(); + + const categoriesMap = useMemo(() => keyBy(categories, 'id'), [categories]); + const bankingAccountTypesMap = useMemo(() => keyBy(bankingAccountTypes, 'id'), [bankingAccountTypes]); + + const isFetching = ( + isBankingInformationFetching + || isCategoriesFetching + || isBankingAccountTypesFetching + ); + + if (isFetching) return ; + + return bankingInformation.map(info => ( + + )); +}; + +OrganizationBankingInfo.propTypes = { + organization: PropTypes.object.isRequired, +}; diff --git a/src/Organizations/OrganizationDetails/OrganizationBankingInfo/index.js b/src/Organizations/OrganizationDetails/OrganizationBankingInfo/index.js new file mode 100644 index 00000000..27b08a52 --- /dev/null +++ b/src/Organizations/OrganizationDetails/OrganizationBankingInfo/index.js @@ -0,0 +1 @@ +export { OrganizationBankingInfo } from './OrganizationBankingInfo'; diff --git a/src/Organizations/OrganizationDetails/OrganizationDetails.js b/src/Organizations/OrganizationDetails/OrganizationDetails.js index 6c6a71d1..e3d368d4 100644 --- a/src/Organizations/OrganizationDetails/OrganizationDetails.js +++ b/src/Organizations/OrganizationDetails/OrganizationDetails.js @@ -59,6 +59,7 @@ import { OrganizationInterfacesContainer } from './OrganizationInterfaces'; import { OrganizationVendorInfo } from './OrganizationVendorInfo'; import { OrganizationAgreements } from './OrganizationAgreements'; import { OrganizationAccounts } from './OrganizationAccounts'; +import { OrganizationBankingInfo } from './OrganizationBankingInfo'; import { IntegrationDetails } from './IntegrationDetails'; const OrganizationDetails = ({ @@ -70,6 +71,7 @@ const OrganizationDetails = ({ organization, organizationCategories, integrationConfigs, + isBankingInformationEnabled, organizationTypes, }) => { const stripes = useStripes(); @@ -83,6 +85,7 @@ const OrganizationDetails = ({ [ORGANIZATION_SECTIONS.vendorTermsSection]: false, [ORGANIZATION_SECTIONS.integrationDetailsSection]: false, [ORGANIZATION_SECTIONS.accountsSection]: false, + [ORGANIZATION_SECTIONS.bankingInformationSection]: false, [ORGANIZATION_SECTIONS.notesSection]: false, [ORGANIZATION_SECTIONS.agreements]: false, }; @@ -95,6 +98,7 @@ const OrganizationDetails = ({ const { restrictions, isLoading: isRestrictionsLoading } = useAcqRestrictions( organization.id, organization.acqUnitIds, ); + const accountNumbers = (organization.isVendor && organization.accounts?.map(({ accountNo }) => accountNo)) || []; const hasDuplicateAccountNumbers = [...new Set(accountNumbers)].length !== accountNumbers.length; @@ -370,6 +374,15 @@ const OrganizationDetails = ({ accounts={organization.accounts} /> + + {isBankingInformationEnabled && ( + + + + )} ) } @@ -420,11 +433,13 @@ OrganizationDetails.propTypes = { value: PropTypes.string, })), integrationConfigs: PropTypes.arrayOf(PropTypes.object), + isBankingInformationEnabled: PropTypes.bool, organizationTypes: PropTypes.arrayOf(PropTypes.object), }; OrganizationDetails.defaultProps = { organizationCategories: [], + isBankingInformationEnabled: false, }; export default OrganizationDetails; diff --git a/src/Organizations/OrganizationDetails/OrganizationDetailsContainer.js b/src/Organizations/OrganizationDetails/OrganizationDetailsContainer.js index 26f451a8..bc081148 100644 --- a/src/Organizations/OrganizationDetails/OrganizationDetailsContainer.js +++ b/src/Organizations/OrganizationDetails/OrganizationDetailsContainer.js @@ -1,12 +1,12 @@ -import React, { +import PropTypes from 'prop-types'; +import { useCallback, useEffect, useState, } from 'react'; -import PropTypes from 'prop-types'; -import ReactRouterPropTypes from 'react-router-prop-types'; -import { withRouter } from 'react-router-dom'; import { useIntl } from 'react-intl'; +import { withRouter } from 'react-router-dom'; +import ReactRouterPropTypes from 'react-router-prop-types'; import { stripesConnect } from '@folio/stripes/core'; import { @@ -20,6 +20,7 @@ import { categoriesResource, } from '../../common/resources'; import { + useBankingInformationSettings, useTranslatedCategories, useTypes, } from '../../common/hooks'; @@ -35,14 +36,19 @@ export const OrganizationDetailsContainer = ({ }) => { const organizationId = match.params.id; + const intl = useIntl(); const showCallout = useShowCallout(); + const [organization, setOrganization] = useState({}); - const [isLoading, setIsLoading] = useState(true); + const [isOrganizationLoading, setIsOrganizationLoading] = useState(true); const [organizationCategories, setOrganizationCategories] = useState([]); const [translatedCategories] = useTranslatedCategories(organizationCategories); const { organizationTypes, isLoading: isOrgTypesLoading } = useTypes(); - const intl = useIntl(); const { integrationConfigs } = useIntegrationConfigs({ organizationId }); + const { + enabled: isBankingInformationEnabled, + isLoading: isBankingInformationSettingsLoading, + } = useBankingInformationSettings(); useEffect( () => { @@ -57,14 +63,14 @@ export const OrganizationDetailsContainer = ({ useEffect( () => { - setIsLoading(true); + setIsOrganizationLoading(true); setOrganization({}); mutator.organizationDetailsOrg.GET() .then(organizationResponse => { setOrganization(organizationResponse); }) - .finally(() => setIsLoading(false)); + .finally(() => setIsOrganizationLoading(false)); }, // eslint-disable-next-line react-hooks/exhaustive-deps [organizationId], @@ -133,7 +139,13 @@ export const OrganizationDetailsContainer = ({ [intl, showCallout, organizationId], ); - if (isLoading || isOrgTypesLoading) { + const isLoading = ( + isOrganizationLoading + || isOrgTypesLoading + || isBankingInformationSettingsLoading + ); + + if (isLoading) { return ( );