From 40a886bf598a5a3d5752c4e68760c11ec47cd5d5 Mon Sep 17 00:00:00 2001 From: Yury Saukou Date: Mon, 25 Nov 2024 20:33:50 +0400 Subject: [PATCH] UIORGS-356 Show in version history record view, which fields have been edited --- CHANGELOG.md | 2 + src/ContactPeople/ContactPerson/index.js | 1 + .../OrganizationVersion.js | 17 +- .../OrganizationVersionView.js | 149 ++++++++++++++++++ .../OrganizationVersionView/index.js | 1 + .../OrganizationAccountsVersionView.js | 119 ++++++++++++++ .../OrganizationAccountsVersionView/index.js | 1 + .../OrganizationContactInfoVersionView.js | 104 ++++++++++++ .../components/ContactAddressesVersionView.js | 102 ++++++++++++ .../ContactPersonEmailsVersionView.js | 86 ++++++++++ .../ContactPersonPhonesVersionView.js | 88 +++++++++++ .../ContactPersonURLsVersionView.js | 94 +++++++++++ .../components/index.js | 4 + .../index.js | 1 + .../OrganizationContactPeopleVersionView.js | 79 ++++++++++ .../index.js | 1 + .../OrganizationInterfacesVersionView.js | 63 ++++++++ .../index.js | 1 + .../OrganizationSummaryVersionView.js | 130 +++++++++++++++ .../OrganizationSummaryVersionView/index.js | 1 + .../OrganizationVendorInfoVersionView.js | 135 ++++++++++++++++ .../index.js | 1 + .../OrganizationVendorTermsVersionView.js | 63 ++++++++ .../index.js | 1 + .../OrganizationVersion/components/index.js | 7 + .../getOrganizationFieldsLabelMap.js | 25 +-- .../OrganizationVersion/hooks/index.js | 1 + .../useSelectedOrganizationVersion/index.js | 1 + .../useSelectedOrganizationVersion.js | 147 +++++++++++++++++ src/common/constants/vendorCategories.js | 1 + src/common/hooks/index.js | 3 + .../hooks/useCategories/useCategories.js | 9 +- src/common/hooks/useContactsByIds/index.js | 1 + .../useContactsByIds/useContactsByIds.js | 46 ++++++ src/common/hooks/useInterfacesByIds/index.js | 1 + .../useInterfacesByIds/useInterfacesByIds.js | 46 ++++++ .../useVersionWrappedRowFormatter/index.js | 1 + .../useVersionWrappedRowFormatter/styles.css | 6 + .../useVersionWrappedRowFormatter.js | 55 +++++++ 39 files changed, 1576 insertions(+), 18 deletions(-) create mode 100644 src/Organizations/OrganizationVersion/OrganizationVersionView/OrganizationVersionView.js create mode 100644 src/Organizations/OrganizationVersion/OrganizationVersionView/index.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationAccountsVersionView/OrganizationAccountsVersionView.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationAccountsVersionView/index.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/OrganizationContactInfoVersionView.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactAddressesVersionView.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactPersonEmailsVersionView.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactPersonPhonesVersionView.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactPersonURLsVersionView.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/index.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/index.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationContactPeopleVersionView/OrganizationContactPeopleVersionView.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationContactPeopleVersionView/index.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationInterfacesVersionView/OrganizationInterfacesVersionView.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationInterfacesVersionView/index.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationSummaryVersionView/OrganizationSummaryVersionView.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationSummaryVersionView/index.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationVendorInfoVersionView/OrganizationVendorInfoVersionView.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationVendorInfoVersionView/index.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationVendorTermsVersionView/OrganizationVendorTermsVersionView.js create mode 100644 src/Organizations/OrganizationVersion/components/OrganizationVendorTermsVersionView/index.js create mode 100644 src/Organizations/OrganizationVersion/components/index.js create mode 100644 src/Organizations/OrganizationVersion/hooks/useSelectedOrganizationVersion/index.js create mode 100644 src/Organizations/OrganizationVersion/hooks/useSelectedOrganizationVersion/useSelectedOrganizationVersion.js create mode 100644 src/common/hooks/useContactsByIds/index.js create mode 100644 src/common/hooks/useContactsByIds/useContactsByIds.js create mode 100644 src/common/hooks/useInterfacesByIds/index.js create mode 100644 src/common/hooks/useInterfacesByIds/useInterfacesByIds.js create mode 100644 src/common/hooks/useVersionWrappedRowFormatter/index.js create mode 100644 src/common/hooks/useVersionWrappedRowFormatter/styles.css create mode 100644 src/common/hooks/useVersionWrappedRowFormatter/useVersionWrappedRowFormatter.js diff --git a/CHANGELOG.md b/CHANGELOG.md index bc14612d..b26a0a90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## 6.0.0 (IN PROGRESS) * *BREAKING* Display all versions in change log in fourth pane. Refs UIORGS-355. +* Show in version history record view, which fields have been edited. Refs UIORGS-356. +* Adapt organization metadata fields to version history mechanism. Refs UIORGS-359. ## [5.2.0](https://github.com/folio-org/ui-organizations/tree/v5.2.0) (2024-10-31) [Full Changelog](https://github.com/folio-org/ui-organizations/compare/v5.1.1...v5.2.0) diff --git a/src/ContactPeople/ContactPerson/index.js b/src/ContactPeople/ContactPerson/index.js index 01188197..1ea57a2f 100644 --- a/src/ContactPeople/ContactPerson/index.js +++ b/src/ContactPeople/ContactPerson/index.js @@ -1 +1,2 @@ export { default } from './ContactPerson'; +export { default as ContactPersonSection } from './ContactPersonSection'; diff --git a/src/Organizations/OrganizationVersion/OrganizationVersion.js b/src/Organizations/OrganizationVersion/OrganizationVersion.js index 2f52d21f..c6551cf6 100644 --- a/src/Organizations/OrganizationVersion/OrganizationVersion.js +++ b/src/Organizations/OrganizationVersion/OrganizationVersion.js @@ -21,7 +21,11 @@ import { } from '../../common/constants'; import { HIDDEN_FIELDS_FOR_ORGANIZATION_VERSION_HISTORY } from '../constants'; import { getOrganizationFieldsLabelMap } from './getOrganizationFieldsLabelMap'; -import { useOrganizationVersions } from './hooks'; +import { + useOrganizationVersions, + useSelectedOrganizationVersion, +} from './hooks'; +import { OrganizationVersionView } from './OrganizationVersionView'; const OrganizationVersion = ({ history, @@ -62,8 +66,15 @@ const OrganizationVersion = ({ }, }); + const { + isLoading: isOrganizationVersionLoading, + selectedVersion, + } = useSelectedOrganizationVersion({ versionId, versions, snapshotPath }); + const isVersionLoading = ( - isOrganizationLoading || isHistoryLoading + isOrganizationLoading + || isHistoryLoading + || isOrganizationVersionLoading ); const labelsMap = useMemo(() => getOrganizationFieldsLabelMap(), []); @@ -84,7 +95,7 @@ const OrganizationVersion = ({ tags={get(organization, 'tags.tagList', [])} versionId={versionId} > - {/* TODO: https://folio-org.atlassian.net/browse/UIORGS-356 */} + { + const accordionStatusRef = useRef(); + + const shortcuts = [ + { + name: 'expandAllSections', + handler: (e) => expandAllSections(e, accordionStatusRef), + }, + { + name: 'collapseAllSections', + handler: (e) => collapseAllSections(e, accordionStatusRef), + }, + ]; + + console.log('version', version); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + { + version?.isVendor && ( + <> + + + + + + + + + + + + + ) + } + + + + ); +}; + +OrganizationVersionView.propTypes = { + version: PropTypes.object, +}; diff --git a/src/Organizations/OrganizationVersion/OrganizationVersionView/index.js b/src/Organizations/OrganizationVersion/OrganizationVersionView/index.js new file mode 100644 index 00000000..90186b5f --- /dev/null +++ b/src/Organizations/OrganizationVersion/OrganizationVersionView/index.js @@ -0,0 +1 @@ +export { OrganizationVersionView } from './OrganizationVersionView'; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationAccountsVersionView/OrganizationAccountsVersionView.js b/src/Organizations/OrganizationVersion/components/OrganizationAccountsVersionView/OrganizationAccountsVersionView.js new file mode 100644 index 00000000..f93ad5a0 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationAccountsVersionView/OrganizationAccountsVersionView.js @@ -0,0 +1,119 @@ +import PropTypes from 'prop-types'; +import { FormattedMessage } from 'react-intl'; + +import { + Col, + Row, +} from '@folio/stripes/components'; +import { + PAYMENT_METHOD_LABELS, + VersionKeyValue, +} from '@folio/stripes-acq-components'; + +import css from '../../../OrganizationDetails/OrganizationAccounts/OrganizationAccount/OrganizationAccount.css'; + +export const OrganizationAccountsVersionView = ({ name, version }) => { + if (!version?.accounts?.length) { + return ( +

+ +

+ ); + } + + return ( + <> + {version?.accounts?.map((account, indx) => { + return ( + + + } + value={account?.name} + /> + + + + } + value={account?.accountNo} + /> + + + + } + value={account?.description} + /> + + + + } + value={account?.appSystemNo} + /> + + + + } + value={PAYMENT_METHOD_LABELS[account?.paymentMethod]} + /> + + + + } + value={account?.contactInfo} + /> + + + + } + value={account?.libraryCode} + /> + + + + } + value={account?.libraryEdiCode} + /> + + + + } + value={account?.notes} + /> + + + + } + value={account?.acqUnits} + multiple + /> + + + ); + })} + + ); +}; + +OrganizationAccountsVersionView.propTypes = { + name: PropTypes.string.isRequired, + version: PropTypes.object, +}; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationAccountsVersionView/index.js b/src/Organizations/OrganizationVersion/components/OrganizationAccountsVersionView/index.js new file mode 100644 index 00000000..8b3dfc55 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationAccountsVersionView/index.js @@ -0,0 +1 @@ +export { OrganizationAccountsVersionView } from './OrganizationAccountsVersionView'; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/OrganizationContactInfoVersionView.js b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/OrganizationContactInfoVersionView.js new file mode 100644 index 00000000..b9b2d71f --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/OrganizationContactInfoVersionView.js @@ -0,0 +1,104 @@ +import cloneDeep from 'lodash/cloneDeep'; +import get from 'lodash/get'; +import PropTypes from 'prop-types'; +import { useMemo } from 'react'; + +import { + Accordion, + Layout, +} from '@folio/stripes/components'; +import { useCategories } from '@folio/stripes-acq-components'; + +import { + UNCATEGORIZED_ID, + UNCATEGORIZED_VALUE, +} from '../../../../common/constants'; +import { + hydrateAddresses, + mixCategories, +} from '../../../../common/utils'; +import { + ContactAddressesVersionView, + ContactPersonEmailsVersionView, + ContactPersonPhonesVersionView, + ContactPersonURLsVersionView, +} from './components'; + +const setInitialArrayFieldPaths = (obj, paths) => { + return paths.reduce((result, path) => { + const target = get(result, path); + + target.forEach((item, indx) => { + item._initialFieldPath = `${path}[${indx}]`; + }); + + return result; + }, cloneDeep(obj ?? {})); +}; + +export const OrganizationContactInfoVersionView = ({ version: currentVersion }) => { + /* + Entities are grouped by categories, so the order in the arrays is not guaranteed. + So we need to keep the initial field paths + */ + const version = setInitialArrayFieldPaths(currentVersion, ['addresses', 'emails', 'phoneNumbers', 'urls']); + + const { categories } = useCategories(); + + const groups = useMemo(() => [ + ...(categories ?? []), + { + id: UNCATEGORIZED_ID, + value: UNCATEGORIZED_VALUE, + }, + ], [categories]); + + const data = useMemo(() => groups.reduce((acc, { id }) => { + const filterCb = ({ categories: entityCategories = [] }) => { + return id === UNCATEGORIZED_ID ? entityCategories.length === 0 : entityCategories.includes(id); + }; + + const addresses = (version?.addresses || []).filter(filterCb); + const emails = (version?.emails || []).filter(filterCb); + const phoneNumbers = (version?.phoneNumbers || []).filter(filterCb); + const urls = (version?.urls || []).filter(filterCb); + + if (addresses.length || emails.length || phoneNumbers.length || urls.length) { + acc[id] = { + addresses: hydrateAddresses(categories, addresses), + emails: mixCategories(categories, emails), + phoneNumbers: mixCategories(categories, phoneNumbers), + urls: mixCategories(categories, urls), + }; + } + + return acc; + }, {}), [categories, groups, version]); + + return ( + + {groups.map((category) => data[category.id] && ( + + + + + + + ))} + + ); +}; + +OrganizationContactInfoVersionView.propTypes = { + version: PropTypes.object, +}; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactAddressesVersionView.js b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactAddressesVersionView.js new file mode 100644 index 00000000..72abba41 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactAddressesVersionView.js @@ -0,0 +1,102 @@ +import PropTypes from 'prop-types'; +import { useContext } from 'react'; +import { FormattedMessage } from 'react-intl'; + +import { + Card, + Col, + Row, +} from '@folio/stripes/components'; +import { + VersionKeyValue, + VersionViewContext, +} from '@folio/stripes-acq-components'; + +export const ContactAddressesVersionView = ({ addresses }) => { + const versionContext = useContext(VersionViewContext); + + return ( + + + {addresses?.map((address) => { + const isPrimaryValue = ( +

+ +

+ ); + const headerStart = versionContext?.paths?.includes(`${address?._initialFieldPath}.isPrimary`) + ? {isPrimaryValue} + : isPrimaryValue; + + return ( + + + + } + value={address?.addressLine1} + /> + + + } + value={address?.addressLine2} + /> + + + } + value={address?.city} + /> + + + } + value={address?.stateRegion} + /> + + + } + value={address?.zipCode} + /> + + + } + value={address?.country} + /> + + + } + value={address?.language} + /> + + + } + value={address?.categories} + multiple + /> + + + + ); + })} + +
+ ); +}; + +ContactAddressesVersionView.propTypes = { + addresses: PropTypes.arrayOf(PropTypes.object), +}; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactPersonEmailsVersionView.js b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactPersonEmailsVersionView.js new file mode 100644 index 00000000..65b6d1b3 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactPersonEmailsVersionView.js @@ -0,0 +1,86 @@ +import PropTypes from 'prop-types'; +import { useContext } from 'react'; +import { FormattedMessage } from 'react-intl'; + +import { + Card, + Col, + Row, +} from '@folio/stripes/components'; +import { + LANG_LABEL_BY_CODE, + VersionKeyValue, + VersionViewContext, +} from '@folio/stripes-acq-components'; + +import { ContactPersonSection } from '../../../../../ContactPeople/ContactPerson'; + +export const ContactPersonEmailsVersionView = ({ emails }) => { + const versionContext = useContext(VersionViewContext); + + if (!emails?.length) return null; + + const renderBody = () => ( + + + {emails?.map((email) => { + const isPrimaryValue = ( +

+ +

+ ); + const headerStart = versionContext?.paths?.includes(`${email?._initialFieldPath}.isPrimary`) + ? {isPrimaryValue} + : isPrimaryValue; + + return ( + + + + } + value={email?.value} + /> + + + } + value={email?.description} + /> + + + } + value={LANG_LABEL_BY_CODE[email?.language] || email?.language} + /> + + + } + value={email.categories} + multiple + /> + + + + ); + })} + +
+ ); + + return ( + } + renderBody={renderBody} + /> + ); +}; + +ContactPersonEmailsVersionView.propTypes = { + emails: PropTypes.arrayOf(PropTypes.object), +}; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactPersonPhonesVersionView.js b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactPersonPhonesVersionView.js new file mode 100644 index 00000000..7b4766a3 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactPersonPhonesVersionView.js @@ -0,0 +1,88 @@ +import PropTypes from 'prop-types'; +import { useContext } from 'react'; +import { FormattedMessage } from 'react-intl'; + +import { + Card, + Col, + Row, +} from '@folio/stripes/components'; +import { + LANG_LABEL_BY_CODE, + VersionKeyValue, + VersionViewContext, +} from '@folio/stripes-acq-components'; + +import { ContactPersonSection } from '../../../../../ContactPeople/ContactPerson'; + +export const ContactPersonPhonesVersionView = ({ phones }) => { + const versionContext = useContext(VersionViewContext); + + if (!phones?.length) return null; + + const renderBody = () => ( + ( + + + {phones?.map((phone) => { + const isPrimaryValue = ( +

+ +

+ ); + const headerStart = versionContext?.paths?.includes(`${phone?._initialFieldPath}.isPrimary`) + ? {isPrimaryValue} + : isPrimaryValue; + + return ( + + + + } + value={phone?.phoneNumber} + /> + + + } + value={phone?.type} + /> + + + } + value={LANG_LABEL_BY_CODE[phone?.language] || phone?.language} + /> + + + } + value={phone.categories} + multiple + /> + + + + ); + })} + +
+ ) + ); + + return ( + } + renderBody={renderBody} + /> + ); +}; + +ContactPersonPhonesVersionView.propTypes = { + phones: PropTypes.arrayOf(PropTypes.object), +}; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactPersonURLsVersionView.js b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactPersonURLsVersionView.js new file mode 100644 index 00000000..45477cf9 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/ContactPersonURLsVersionView.js @@ -0,0 +1,94 @@ +import PropTypes from 'prop-types'; +import { useContext } from 'react'; +import { FormattedMessage } from 'react-intl'; + +import { + Card, + Col, + Row, + TextLink, +} from '@folio/stripes/components'; +import { + LANG_LABEL_BY_CODE, + VersionKeyValue, + VersionViewContext, +} from '@folio/stripes-acq-components'; + +import { ContactPersonSection } from '../../../../../ContactPeople/ContactPerson'; + +export const ContactPersonURLsVersionView = ({ urls }) => { + const versionContext = useContext(VersionViewContext); + + if (!urls?.length) return null; + + const renderBody = () => ( + + + {urls?.map((url) => { + const isPrimaryValue = ( +

+ +

+ ); + const headerStart = versionContext?.paths?.includes(`${url?._initialFieldPath}.isPrimary`) + ? {isPrimaryValue} + : isPrimaryValue; + + return ( + + + + } + > + + {url.value} + + + + + } + value={url?.description} + /> + + + } + value={LANG_LABEL_BY_CODE[url?.language] || url?.language} + /> + + + } + value={url.categories} + multiple + /> + + + + ); + })} + +
+ ); + + return ( + } + renderBody={renderBody} + /> + ); +}; + +ContactPersonURLsVersionView.propTypes = { + urls: PropTypes.arrayOf(PropTypes.object), +}; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/index.js b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/index.js new file mode 100644 index 00000000..6810bca3 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/components/index.js @@ -0,0 +1,4 @@ +export { ContactAddressesVersionView } from './ContactAddressesVersionView'; +export { ContactPersonEmailsVersionView } from './ContactPersonEmailsVersionView'; +export { ContactPersonPhonesVersionView } from './ContactPersonPhonesVersionView'; +export { ContactPersonURLsVersionView } from './ContactPersonURLsVersionView'; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/index.js b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/index.js new file mode 100644 index 00000000..bc291929 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationContactInfoVersionView/index.js @@ -0,0 +1 @@ +export { OrganizationContactInfoVersionView } from './OrganizationContactInfoVersionView'; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationContactPeopleVersionView/OrganizationContactPeopleVersionView.js b/src/Organizations/OrganizationVersion/components/OrganizationContactPeopleVersionView/OrganizationContactPeopleVersionView.js new file mode 100644 index 00000000..34ce850c --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationContactPeopleVersionView/OrganizationContactPeopleVersionView.js @@ -0,0 +1,79 @@ +import get from 'lodash/get'; +import find from 'lodash/find'; +import PropTypes from 'prop-types'; +import { useMemo } from 'react'; +import { + FormattedMessage, + useIntl, +} from 'react-intl'; + +import { + MultiColumnList, + NoValue, +} from '@folio/stripes/components'; +import { useCategories } from '@folio/stripes-acq-components'; + +import { Ellipsis } from '../../../../common/components'; +import { useVersionWrappedRowFormatter } from '../../../../common/hooks'; +import { transformCategoryIdsToLables } from '../../../../common/utils'; + +const visibleColumns = [ + 'name', + 'categories', + 'email', + 'phone', + 'status', + 'notes', +]; + +const columnMapping = { + name: , + categories: , + email: , + phone: , + status: , + notes: , +}; + +const getResultsFormatter = ({ intl, categories }) => ({ + name: ({ isDeleted, firstName, lastName }) => ( + isDeleted + ? intl.formatMessage({ id: 'ui-organizations.contactPeople.removedContact' }) + : `${lastName}, ${firstName}` + ), + categories: ({ categories: vendorCategories = [] }) => { + return transformCategoryIdsToLables(categories, vendorCategories) || ; + }, + email: c => get(find(c.emails, 'isPrimary'), 'value', '') || , + phone: c => get(find(c.phoneNumbers, 'isPrimary'), 'phoneNumber', '') || , + status: c => , + notes: c => {c.notes}, +}); + +export const OrganizationContactPeopleVersionView = ({ name, version }) => { + const intl = useIntl(); + + const { categories } = useCategories(); + + const rowFormatter = useVersionWrappedRowFormatter({ name }); + + const resultsFormatter = useMemo(() => { + return getResultsFormatter({ intl, categories }); + }, [intl, categories]); + + return ( + + ); +}; + +OrganizationContactPeopleVersionView.propTypes = { + name: PropTypes.string.isRequired, + version: PropTypes.object, +}; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationContactPeopleVersionView/index.js b/src/Organizations/OrganizationVersion/components/OrganizationContactPeopleVersionView/index.js new file mode 100644 index 00000000..72ff74a1 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationContactPeopleVersionView/index.js @@ -0,0 +1 @@ +export { OrganizationContactPeopleVersionView } from './OrganizationContactPeopleVersionView'; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationInterfacesVersionView/OrganizationInterfacesVersionView.js b/src/Organizations/OrganizationVersion/components/OrganizationInterfacesVersionView/OrganizationInterfacesVersionView.js new file mode 100644 index 00000000..b7a2570a --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationInterfacesVersionView/OrganizationInterfacesVersionView.js @@ -0,0 +1,63 @@ +import PropTypes from 'prop-types'; +import { FormattedMessage } from 'react-intl'; + +import { + Col, + MultiColumnList, + NoValue, + Row, + TextLink, +} from '@folio/stripes/components'; + +import { useVersionWrappedRowFormatter } from '../../../../common/hooks'; + +const columnMapping = { + interfaceName: , + interfaceUrl: , +}; + +const visibleColumns = ['interfaceName', 'interfaceUrl']; + +const resultsFormatter = { + interfaceName: ({ name }) => name, + interfaceUrl: (item) => ( + item.uri + ? ( + + {item.uri} + + ) + : + ), +}; + +export const OrganizationInterfacesVersionView = ({ + name, + version, +}) => { + const rowFormatter = useVersionWrappedRowFormatter({ name }); + + return ( + + + + + + ); +}; + +OrganizationInterfacesVersionView.propTypes = { + name: PropTypes.string.isRequired, + version: PropTypes.object, +}; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationInterfacesVersionView/index.js b/src/Organizations/OrganizationVersion/components/OrganizationInterfacesVersionView/index.js new file mode 100644 index 00000000..06da8449 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationInterfacesVersionView/index.js @@ -0,0 +1 @@ +export { OrganizationInterfacesVersionView } from './OrganizationInterfacesVersionView'; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationSummaryVersionView/OrganizationSummaryVersionView.js b/src/Organizations/OrganizationVersion/components/OrganizationSummaryVersionView/OrganizationSummaryVersionView.js new file mode 100644 index 00000000..2385fd1a --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationSummaryVersionView/OrganizationSummaryVersionView.js @@ -0,0 +1,130 @@ +import PropTypes from 'prop-types'; +import { FormattedMessage } from 'react-intl'; + +import { + Col, + NoValue, + Row, +} from '@folio/stripes/components'; +import { ViewMetaData } from '@folio/stripes/smart-components'; +import { + LANG_LABEL_BY_CODE, + VersionCheckbox, + VersionKeyValue, +} from '@folio/stripes-acq-components'; + +import { ORGANIZATION_SECTIONS } from '../../../constants'; + +export const OrganizationSummaryVersionView = ({ version }) => { + return ( + <> + + + {version?.metadata && ( + + )} + + + + + + } + value={version?.name} + /> + + + + } + value={version?.code} + /> + + + + } + value={version?.erpCode || } + /> + + + + } + value={version?.status && } + /> + + + + } + value={LANG_LABEL_BY_CODE[version?.language] || version?.language || } + /> + + + + } + value={version?.organizationTypes?.join(', ') || } + multiple + /> + + + + } + value={version?.acqUnits} + multiple + /> + + + + } + value={version?.description || } + /> + + + + } + /> + + + + } + /> + + + + } + value={version?.alternativeNames || } + multiple + /> + + + + ); +}; + +OrganizationSummaryVersionView.propTypes = { + version: PropTypes.object, +}; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationSummaryVersionView/index.js b/src/Organizations/OrganizationVersion/components/OrganizationSummaryVersionView/index.js new file mode 100644 index 00000000..bb3ea69e --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationSummaryVersionView/index.js @@ -0,0 +1 @@ +export { OrganizationSummaryVersionView } from './OrganizationSummaryVersionView'; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationVendorInfoVersionView/OrganizationVendorInfoVersionView.js b/src/Organizations/OrganizationVersion/components/OrganizationVendorInfoVersionView/OrganizationVendorInfoVersionView.js new file mode 100644 index 00000000..dfe40ec7 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationVendorInfoVersionView/OrganizationVendorInfoVersionView.js @@ -0,0 +1,135 @@ +import PropTypes from 'prop-types'; +import { FormattedMessage } from 'react-intl'; + +import { + PAYMENT_METHOD_LABELS, + VersionCheckbox, + VersionKeyValue, +} from '@folio/stripes-acq-components'; +import { + Col, + Row, +} from '@folio/stripes/components'; + +export const OrganizationVendorInfoVersionView = ({ version }) => { + return ( + + + } + value={PAYMENT_METHOD_LABELS[version?.paymentMethod]} + /> + + + + } + value={version?.vendorCurrenciesValue} + multiple + /> + + + +
+ + + + } + value={version?.claimingInterval} + /> + + + + } + value={version?.discountPercent} + /> + + + + } + value={version?.expectedActivationInterval} + /> + + + + } + value={version?.expectedInvoiceInterval} + /> + + + + } + value={version?.expectedReceiptInterval} + /> + + + + } + value={version?.renewalActivationInterval} + /> + + + + } + value={version?.subscriptionInterval} + /> + + + + } + /> + + + +
+ + + + } + value={version?.taxId} + /> + + + + } + value={version?.taxPercentage} + /> + + + + } + /> + +
+ ); +}; + +OrganizationVendorInfoVersionView.propTypes = { + version: PropTypes.object, +}; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationVendorInfoVersionView/index.js b/src/Organizations/OrganizationVersion/components/OrganizationVendorInfoVersionView/index.js new file mode 100644 index 00000000..745e857b --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationVendorInfoVersionView/index.js @@ -0,0 +1 @@ +export { OrganizationVendorInfoVersionView } from './OrganizationVendorInfoVersionView'; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationVendorTermsVersionView/OrganizationVendorTermsVersionView.js b/src/Organizations/OrganizationVersion/components/OrganizationVendorTermsVersionView/OrganizationVendorTermsVersionView.js new file mode 100644 index 00000000..5c4abddd --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationVendorTermsVersionView/OrganizationVendorTermsVersionView.js @@ -0,0 +1,63 @@ +import PropTypes from 'prop-types'; +import { FormattedMessage } from 'react-intl'; + +import { + Col, + NoValue, + Row, +} from '@folio/stripes/components'; +import { VersionKeyValue } from '@folio/stripes-acq-components'; + +export const OrganizationVendorTermsVersionView = ({ name, version }) => { + if (!version?.agreements?.length) { + return ( +

+ +

+ ); + } + + return ( + <> + {version?.agreements?.map((agreement, indx) => { + return ( + + + } + value={agreement?.name} + /> + + + } + value={agreement?.discount !== undefined ? `${agreement?.discount}%` : } + /> + + + } + value={agreement?.referenceUrl} + /> + + + } + value={agreement?.notes} + /> + + + ); + })} + + ); +}; + +OrganizationVendorTermsVersionView.propTypes = { + name: PropTypes.string.isRequired, + version: PropTypes.object, +}; diff --git a/src/Organizations/OrganizationVersion/components/OrganizationVendorTermsVersionView/index.js b/src/Organizations/OrganizationVersion/components/OrganizationVendorTermsVersionView/index.js new file mode 100644 index 00000000..057611e4 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/OrganizationVendorTermsVersionView/index.js @@ -0,0 +1 @@ +export { OrganizationVendorTermsVersionView } from './OrganizationVendorTermsVersionView'; diff --git a/src/Organizations/OrganizationVersion/components/index.js b/src/Organizations/OrganizationVersion/components/index.js new file mode 100644 index 00000000..de2d6fa9 --- /dev/null +++ b/src/Organizations/OrganizationVersion/components/index.js @@ -0,0 +1,7 @@ +export { OrganizationAccountsVersionView } from './OrganizationAccountsVersionView'; +export { OrganizationContactInfoVersionView } from './OrganizationContactInfoVersionView'; +export { OrganizationContactPeopleVersionView } from './OrganizationContactPeopleVersionView'; +export { OrganizationInterfacesVersionView } from './OrganizationInterfacesVersionView'; +export { OrganizationSummaryVersionView } from './OrganizationSummaryVersionView'; +export { OrganizationVendorInfoVersionView } from './OrganizationVendorInfoVersionView'; +export { OrganizationVendorTermsVersionView } from './OrganizationVendorTermsVersionView'; diff --git a/src/Organizations/OrganizationVersion/getOrganizationFieldsLabelMap.js b/src/Organizations/OrganizationVersion/getOrganizationFieldsLabelMap.js index f2073cca..4b52c133 100644 --- a/src/Organizations/OrganizationVersion/getOrganizationFieldsLabelMap.js +++ b/src/Organizations/OrganizationVersion/getOrganizationFieldsLabelMap.js @@ -130,18 +130,19 @@ export const getOrganizationFieldsLabelMap = () => { 'edi.ediJob.schedulingNotes': 'ui-organizations.versionHistory.field.edi.ediJob.schedulingNotes', 'accounts': 'ui-organizations.accounts', - 'accounts.name': 'ui-organizations.accounts.name', - 'accounts.accountNo': 'ui-organizations.accounts.accountNumber', - 'accounts.description': 'ui-organizations.accounts.description', - 'accounts.appSystemNo': 'ui-organizations.accounts.payable', - 'accounts.paymentMethod': 'ui-organizations.accounts.paymentMethod', - 'accounts.accountStatus': 'ui-organizations.accounts.account.accountStatus', - 'accounts.contactInfo': 'ui-organizations.accounts.account.contactInfo', - 'accounts.libraryCode': 'ui-organizations.accounts.libraryCode', - 'accounts.libraryEdiCode': 'ui-organizations.accounts.libraryEDICode', - 'accounts.notes': 'ui-organizations.accounts.notes', - 'accounts.acqUnitIds': 'ui-organizations.versionHistory.field.accounts.acqUnitsIds', - 'accounts.acqUnitIds[\\d]': 'ui-organizations.versionHistory.field.accounts.acqUnitsIds', + 'accounts[\\d]': 'ui-organizations.accounts', + 'accounts[\\d].name': 'ui-organizations.accounts.name', + 'accounts[\\d].accountNo': 'ui-organizations.accounts.accountNumber', + 'accounts[\\d].description': 'ui-organizations.accounts.description', + 'accounts[\\d].appSystemNo': 'ui-organizations.accounts.payable', + 'accounts[\\d].paymentMethod': 'ui-organizations.accounts.paymentMethod', + 'accounts[\\d].accountStatus': 'ui-organizations.accounts.account.accountStatus', + 'accounts[\\d].contactInfo': 'ui-organizations.accounts.account.contactInfo', + 'accounts[\\d].libraryCode': 'ui-organizations.accounts.libraryCode', + 'accounts[\\d].libraryEdiCode': 'ui-organizations.accounts.libraryEDICode', + 'accounts[\\d].notes': 'ui-organizations.accounts.notes', + 'accounts[\\d].acqUnitIds': 'ui-organizations.versionHistory.field.accounts.acqUnitsIds', + 'accounts[\\d].acqUnitIds[\\d]': 'ui-organizations.versionHistory.field.accounts.acqUnitsIds', 'isVendor': 'ui-organizations.summary.isVendor', 'isDonor': 'ui-organizations.summary.isDonor', diff --git a/src/Organizations/OrganizationVersion/hooks/index.js b/src/Organizations/OrganizationVersion/hooks/index.js index ecff7cfd..98d80689 100644 --- a/src/Organizations/OrganizationVersion/hooks/index.js +++ b/src/Organizations/OrganizationVersion/hooks/index.js @@ -1 +1,2 @@ export { useOrganizationVersions } from './useOrganizationVersions'; +export { useSelectedOrganizationVersion } from './useSelectedOrganizationVersion'; diff --git a/src/Organizations/OrganizationVersion/hooks/useSelectedOrganizationVersion/index.js b/src/Organizations/OrganizationVersion/hooks/useSelectedOrganizationVersion/index.js new file mode 100644 index 00000000..ebb54868 --- /dev/null +++ b/src/Organizations/OrganizationVersion/hooks/useSelectedOrganizationVersion/index.js @@ -0,0 +1 @@ +export { useSelectedOrganizationVersion } from './useSelectedOrganizationVersion'; diff --git a/src/Organizations/OrganizationVersion/hooks/useSelectedOrganizationVersion/useSelectedOrganizationVersion.js b/src/Organizations/OrganizationVersion/hooks/useSelectedOrganizationVersion/useSelectedOrganizationVersion.js new file mode 100644 index 00000000..e9ec136d --- /dev/null +++ b/src/Organizations/OrganizationVersion/hooks/useSelectedOrganizationVersion/useSelectedOrganizationVersion.js @@ -0,0 +1,147 @@ +import get from 'lodash/fp/get'; +import filter from 'lodash/fp/filter'; +import flatMap from 'lodash/fp/flatMap'; +import flow from 'lodash/fp/flow'; +import keyBy from 'lodash/fp/keyBy'; +import uniq from 'lodash/fp/uniq'; +import { useMemo } from 'react'; +import { useIntl } from 'react-intl'; +import { useQuery } from 'react-query'; + +import { + useNamespace, + useOkapiKy, +} from '@folio/stripes/core'; +import { getFullName } from '@folio/stripes/util'; +import { + fetchAcqUnitsByIds, + getVersionMetadata, + useOrganization, + useUsersBatch, +} from '@folio/stripes-acq-components'; +import { currenciesByCode } from '@folio/stripes/components'; + +import { + useContactsByIds, + useInterfacesByIds, +} from '../../../../common/hooks'; + +const getUniqItems = (arr) => ( + flow( + uniq, + filter(Boolean), + )(arr) +); + +export const useSelectedOrganizationVersion = ({ versionId, versions, snapshotPath }, options = {}) => { + const intl = useIntl(); + const ky = useOkapiKy(); + const [namespace] = useNamespace({ key: 'organization-version-data' }); + + const deletedRecordLabel = intl.formatMessage({ id: 'stripes-acq-components.versionHistory.deletedRecord' }); + + const currentVersion = useMemo(() => ( + versions?.find(({ id }) => id === versionId) + ), [versionId, versions]); + + const versionSnapshot = useMemo(() => ( + get(snapshotPath, currentVersion) + ), [snapshotPath, currentVersion]); + + const { + organization, + isLoading: isOrganizationLoading, + } = useOrganization(currentVersion?.organizationId); + + const metadata = useMemo(() => getVersionMetadata(currentVersion, organization), [currentVersion, organization]); + const createdByUserId = metadata?.createdByUserId; + + const versionUserIds = useMemo(() => getUniqItems([createdByUserId]), [createdByUserId]); + const { + users, + isLoading: isUsersLoading, + } = useUsersBatch(versionUserIds); + + const { + contacts, + isLoading: isContactsLoading, + } = useContactsByIds(versionSnapshot?.contacts); + + const { + interfaces, + isLoading: isInterfacesLoading, + } = useInterfacesByIds(versionSnapshot?.interfaces); + + const { + isLoading: isVersionDataLoading, + data = {}, + } = useQuery( + [namespace, versionId, versionSnapshot?.id], + async () => { + const acqUnitsIds = [ + ...get('acqUnitIds', versionSnapshot, []), + ...flow( + get('accounts'), + flatMap('acqUnitIds'), + uniq, + )(versionSnapshot), + ]; + + const [ + acqUnitsMap, + ] = await Promise.all([ + fetchAcqUnitsByIds(ky)(acqUnitsIds).then(keyBy('id')), + ]); + + const vendorCurrenciesValue = versionSnapshot?.vendorCurrencies?.map(currency => { + const currencyInfo = currenciesByCode[currency]; + + return currencyInfo ? `${currencyInfo.currency} (${currencyInfo.code})` : currency; + }).join(', '); + + return { + ...versionSnapshot, + accounts: versionSnapshot?.accounts?.map((account) => ({ + ...account, + acqUnits: account?.acqUnitIds?.map((acqUnitId) => acqUnitsMap[acqUnitId]?.name || deletedRecordLabel), + })), + acqUnits: acqUnitsIds.map(acqUnitsId => acqUnitsMap[acqUnitsId]?.name || deletedRecordLabel).join(', '), + alternativeNames: versionSnapshot?.aliases?.map(({ value }) => value).join(', '), + vendorCurrenciesValue, + metadata, + }; + }, + { + enabled: Boolean(versionId && organization?.id), + ...options, + }, + ); + + const selectedVersion = useMemo(() => { + const versionUsersMap = keyBy('id', users); + + const createdByUser = versionUsersMap[createdByUserId] + ? getFullName(versionUsersMap[createdByUserId]) + : deletedRecordLabel; + + return { + ...data, + createdByUser: createdByUserId && createdByUser, + contactsList: contacts, + interfacesList: interfaces, + }; + }, [users, createdByUserId, deletedRecordLabel, data, contacts, interfaces]); + + const isLoading = ( + isOrganizationLoading + || isUsersLoading + || isVersionDataLoading + || isContactsLoading + || isInterfacesLoading + ); + + return { + isLoading, + selectedVersion, + }; +}; diff --git a/src/common/constants/vendorCategories.js b/src/common/constants/vendorCategories.js index 33812d25..c9d26ab0 100644 --- a/src/common/constants/vendorCategories.js +++ b/src/common/constants/vendorCategories.js @@ -1,3 +1,4 @@ +export const UNCATEGORIZED_ID = 'uncategorized'; export const UNCATEGORIZED_VALUE = 'Uncategorized'; export const VENDOR_DEFAULT_CATEGORIES = { diff --git a/src/common/hooks/index.js b/src/common/hooks/index.js index 9b6c0fd4..d866e888 100644 --- a/src/common/hooks/index.js +++ b/src/common/hooks/index.js @@ -3,10 +3,13 @@ export * from './useBankingAccountTypes'; export * from './useBankingInformationMutation'; export * from './useBankingInformationSettings'; export * from './useCategories'; +export * from './useContactsByIds'; export * from './useEventEmitter'; export * from './useIntegrationConfig'; export * from './useIntegrationConfigMutation'; +export * from './useInterfacesByIds'; export * from './useLinkedAgreements'; export * from './useOrganizationBankingInformation'; export * from './useTranslatedCategories'; export * from './useTypes'; +export * from './useVersionWrappedRowFormatter'; diff --git a/src/common/hooks/useCategories/useCategories.js b/src/common/hooks/useCategories/useCategories.js index 8cd3878b..a4349b2f 100644 --- a/src/common/hooks/useCategories/useCategories.js +++ b/src/common/hooks/useCategories/useCategories.js @@ -4,7 +4,10 @@ import { useNamespace, useOkapiKy, } from '@folio/stripes/core'; -import { LIMIT_MAX } from '@folio/stripes-acq-components'; +import { + ALL_RECORDS_CQL, + LIMIT_MAX, +} from '@folio/stripes-acq-components'; import { CATEGORIES_API } from '../../constants'; import { useTranslatedCategories } from '../useTranslatedCategories'; @@ -17,7 +20,7 @@ export const useCategories = (options = {}) => { const searchParams = { limit: LIMIT_MAX, - query: 'cql.allRecords=1', + query: ALL_RECORDS_CQL, }; const { @@ -26,7 +29,7 @@ export const useCategories = (options = {}) => { isLoading, } = useQuery( [namespace], - () => ky.get(CATEGORIES_API, { searchParams }).json(), + ({ signal }) => ky.get(CATEGORIES_API, { searchParams, signal }).json(), options, ); diff --git a/src/common/hooks/useContactsByIds/index.js b/src/common/hooks/useContactsByIds/index.js new file mode 100644 index 00000000..b8a06c06 --- /dev/null +++ b/src/common/hooks/useContactsByIds/index.js @@ -0,0 +1 @@ +export { useContactsByIds } from './useContactsByIds'; diff --git a/src/common/hooks/useContactsByIds/useContactsByIds.js b/src/common/hooks/useContactsByIds/useContactsByIds.js new file mode 100644 index 00000000..d8f57d25 --- /dev/null +++ b/src/common/hooks/useContactsByIds/useContactsByIds.js @@ -0,0 +1,46 @@ +import { useQuery } from 'react-query'; + +import { + useNamespace, + useOkapiKy, +} from '@folio/stripes/core'; +import { batchFetch } from '@folio/stripes-acq-components'; + +import { CONTACTS_API } from '../../constants'; + +const DEFAULT_DATA = []; + +export const useContactsByIds = (contactIds, options = {}) => { + const { + enabled = true, + ...queryOptions + } = options; + + const ky = useOkapiKy(); + const [namespace] = useNamespace('contacts'); + + const { + data, + isFetching, + isLoading, + } = useQuery({ + queryKey: [namespace, contactIds], + queryFn: ({ signal }) => batchFetch( + { + GET: ({ params: searchParams }) => { + return ky.get(CONTACTS_API, { searchParams, signal }).json().then(({ contacts }) => contacts); + }, + }, + contactIds, + ), + enabled: Boolean(enabled && contactIds?.length), + ...queryOptions, + }); + + return ({ + contacts: data || DEFAULT_DATA, + totalRecords: data?.length, + isFetching, + isLoading, + }); +}; diff --git a/src/common/hooks/useInterfacesByIds/index.js b/src/common/hooks/useInterfacesByIds/index.js new file mode 100644 index 00000000..e389bcf9 --- /dev/null +++ b/src/common/hooks/useInterfacesByIds/index.js @@ -0,0 +1 @@ +export { useInterfacesByIds } from './useInterfacesByIds'; diff --git a/src/common/hooks/useInterfacesByIds/useInterfacesByIds.js b/src/common/hooks/useInterfacesByIds/useInterfacesByIds.js new file mode 100644 index 00000000..c89e8861 --- /dev/null +++ b/src/common/hooks/useInterfacesByIds/useInterfacesByIds.js @@ -0,0 +1,46 @@ +import { useQuery } from 'react-query'; + +import { + useNamespace, + useOkapiKy, +} from '@folio/stripes/core'; +import { batchFetch } from '@folio/stripes-acq-components'; + +import { INTERFACES_API } from '../../constants'; + +const DEFAULT_DATA = []; + +export const useInterfacesByIds = (interfaceIds, options = {}) => { + const { + enabled = true, + ...queryOptions + } = options; + + const ky = useOkapiKy(); + const [namespace] = useNamespace('interfaces'); + + const { + data, + isFetching, + isLoading, + } = useQuery({ + queryKey: [namespace, interfaceIds], + queryFn: ({ signal }) => batchFetch( + { + GET: ({ params: searchParams }) => { + return ky.get(INTERFACES_API, { searchParams, signal }).json().then(({ interfaces }) => interfaces); + }, + }, + interfaceIds, + ), + enabled: Boolean(enabled && interfaceIds?.length), + ...queryOptions, + }); + + return { + interfaces: data || DEFAULT_DATA, + totalRecords: data?.length, + isFetching, + isLoading, + }; +}; diff --git a/src/common/hooks/useVersionWrappedRowFormatter/index.js b/src/common/hooks/useVersionWrappedRowFormatter/index.js new file mode 100644 index 00000000..dcc8b135 --- /dev/null +++ b/src/common/hooks/useVersionWrappedRowFormatter/index.js @@ -0,0 +1 @@ +export { useVersionWrappedRowFormatter } from './useVersionWrappedRowFormatter'; diff --git a/src/common/hooks/useVersionWrappedRowFormatter/styles.css b/src/common/hooks/useVersionWrappedRowFormatter/styles.css new file mode 100644 index 00000000..32c37302 --- /dev/null +++ b/src/common/hooks/useVersionWrappedRowFormatter/styles.css @@ -0,0 +1,6 @@ +.mark { + &.version-wrapped.version-row-formatted { + background-color: mark; + margin: 0.15rem 0; + } +} \ No newline at end of file diff --git a/src/common/hooks/useVersionWrappedRowFormatter/useVersionWrappedRowFormatter.js b/src/common/hooks/useVersionWrappedRowFormatter/useVersionWrappedRowFormatter.js new file mode 100644 index 00000000..d997e92a --- /dev/null +++ b/src/common/hooks/useVersionWrappedRowFormatter/useVersionWrappedRowFormatter.js @@ -0,0 +1,55 @@ +import { + useCallback, + useContext, +} from 'react'; + +import { DefaultMCLRowFormatter } from '@folio/stripes/components'; +import { VersionViewContext } from '@folio/stripes-acq-components'; + +import css from './styles.css'; + +const getVersionWrappedRowFormatter = ({ + baseRowFormatter = DefaultMCLRowFormatter, + row, + name, + paths, +}) => { + const { + rowClass, + rowIndex, + ...props + } = row; + + const isUpdated = paths?.includes(`${name}[${rowIndex}]`); + + return baseRowFormatter({ + ...props, + rowClass: [ + css['version-wrapped'], + css['version-row-formatted'], + rowClass, + isUpdated ? css.mark : '', + ].join(' '), + rowIndex, + }); +}; + +export const useVersionWrappedRowFormatter = ({ + baseRowFormatter, + name, +}) => { + const versionContext = useContext(VersionViewContext); + + const rowFormatter = useCallback((row) => { + if (!versionContext || !name) return baseRowFormatter; + + return getVersionWrappedRowFormatter({ + baseRowFormatter, + row, + name, + paths: versionContext.paths, + }); + }, [baseRowFormatter, name, versionContext]); + + return rowFormatter; +};