Skip to content

Commit

Permalink
UIIN-2793: Populate Acquisitions accordion on instance when central o…
Browse files Browse the repository at this point in the history
…rdering is active (#2482)

* UIIN-2793: Populate Acquisitions accordion on instance when central ordering is active

* Update package.json

* UIIN-2793: Rename file for styles

* UIIN-2793: Display sub accordions when user is in consortium mode AND the user is on non-central tenant

* UIIN-2793: Fix tests

* UIIN-2793: Changes after review

* UIIN-2793: Fix tests

* UIIN-2793: Change naming & mock useStripes

* UIIN-2793: Update CHANGELOG.md

* UIIN-2793: Fix typo in constants.js
  • Loading branch information
OleksandrHladchenko1 committed May 15, 2024
1 parent e0bc47e commit 6aa7b8b
Show file tree
Hide file tree
Showing 10 changed files with 256 additions and 50 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* Jest/RTL: Cover ModalContent components with unit tests. Refs UIIN-2669.
* Add callout noting user's active affiliation when it changes after selecting holding or item. Refs UIIN-2831, UIIN-2872.
* Jest/RTL: Cover LocationSelectionWithCheck components with unit tests. Refs UIIN-2670.
* Populate Acquisitions accordion on instance when central ordering is active. Refs UIIN-2793.

## [11.0.4](https://github.com/folio-org/ui-inventory/tree/v11.0.4) (2024-04-30)
[Full Changelog](https://github.com/folio-org/ui-inventory/compare/v11.0.3...v11.0.4)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.tenantAcquisitionAccordion {
padding-left: 15px;
}
Original file line number Diff line number Diff line change
@@ -1,66 +1,90 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';

import { useStripes } from '@folio/stripes/core';
import {
Accordion,
MultiColumnList,
NoValue,
} from '@folio/stripes/components';
import { Accordion } from '@folio/stripes/components';

import { getDateWithTime } from '../../../utils';
import { useControlledAccordion } from '../../../common';
import { isUserInConsortiumMode } from '../../../utils';
import useInstanceAcquisition from './useInstanceAcquisition';

const visibleColumns = ['poLineNumber', 'orderStatus', 'polReceiptStatus', 'dateOrdered', 'acqUnit', 'orderType'];
const columnMapping = {
poLineNumber: <FormattedMessage id="ui-inventory.acq.polNumber" />,
orderStatus: <FormattedMessage id="ui-inventory.acq.orderStatus" />,
polReceiptStatus: <FormattedMessage id="ui-inventory.acq.receiptStatus" />,
dateOrdered: <FormattedMessage id="ui-inventory.acq.dateOpened" />,
acqUnit: <FormattedMessage id="ui-inventory.acq.acqUnit" />,
orderType: <FormattedMessage id="ui-inventory.acq.orderType" />,
};
const formatter = {
poLineNumber: i => <Link to={`/orders/lines/view/${i.id}`}>{i.poLineNumber}</Link>,
orderStatus: i => (
<>
{i.order?.workflowStatus ? <FormattedMessage id={`ui-inventory.acq.orderStatus.${i.order.workflowStatus}`} /> : <NoValue />}
{i.order?.orderCloseReason?.reason && ` - ${i.order.orderCloseReason.reason}`}
</>
),
polReceiptStatus: i => <FormattedMessage id={`ui-inventory.acq.receiptStatus.${i.receiptStatus}`} />,
dateOrdered: i => getDateWithTime(i.order?.dateOrdered),
acqUnit: i => i.order?.acqUnits?.map(u => u.name)?.join(', ') || <NoValue />,
orderType: i => (i.order?.orderType ? <FormattedMessage id={`ui-inventory.acq.orderType.${i.order.orderType}`} /> : <NoValue />),
};
import TenantAcquisition from './TenantAcquisition';

import css from './InstanceAcquisition.css';

const InstanceAcquisition = ({ accordionId, instanceId }) => {
const stripes = useStripes();
const { isLoading, instanceAcquisition } = useInstanceAcquisition(instanceId);
const controlledAccorion = useControlledAccordion(Boolean(instanceAcquisition?.length));
const activeTenant = stripes.okapi.tenant;
const centralTenant = stripes.user.user?.consortium?.centralTenantId;

const {
isLoading: isLoadingActiveTenantAcquisition,
instanceAcquisition: activeTenantAcquisition,
} = useInstanceAcquisition(instanceId, activeTenant);
const {
isLoading: isLoadingCentralTenantAcquisition,
instanceAcquisition: centralTenantAcquisition,
} = useInstanceAcquisition(instanceId, centralTenant);

const controlledAcqAccorion = useControlledAccordion(Boolean(activeTenantAcquisition?.length || centralTenantAcquisition?.length));
const controlledActiveTenantAcqAccorion = useControlledAccordion(Boolean(activeTenantAcquisition?.length));
const controlledCetralTenantAcqAccorion = useControlledAccordion(Boolean(centralTenantAcquisition?.length));

if (!(stripes.hasInterface('order-lines') &&
stripes.hasInterface('orders') &&
stripes.hasInterface('acquisitions-units'))) return null;

const renderTenantAcquisitionAccordion = (accId, tenantId, tenantAcquisitions, isLoading, controlledAccorionProps) => {
const getTenantAccordionLabel = (tenants, id) => tenants?.find(tenant => tenant.id === id).name;

return (
<Accordion
id={accId}
label={getTenantAccordionLabel(stripes.user.user.tenants, tenantId)}
className={css.tenantAcquisitionAccordion}
{...controlledAccorionProps}
>
<TenantAcquisition
acquisitions={tenantAcquisitions}
isLoading={isLoading}
tenantId={tenantId}
/>
</Accordion>
);
};

return (
<Accordion
id={accordionId}
label={<FormattedMessage id="ui-inventory.acquisition" />}
{...controlledAccorion}
{...controlledAcqAccorion}
>
<MultiColumnList
id="list-instance-acquisitions"
loading={isLoading}
contentData={instanceAcquisition}
visibleColumns={visibleColumns}
columnMapping={columnMapping}
formatter={formatter}
interactive={false}
/>
{(isUserInConsortiumMode(stripes) && activeTenant !== centralTenant) ? (
<>
{renderTenantAcquisitionAccordion(
'active-acquisition-accordion',
activeTenant,
activeTenantAcquisition,
isLoadingActiveTenantAcquisition,
controlledActiveTenantAcqAccorion,
)}
{renderTenantAcquisitionAccordion(
'central-acquisition-accordion',
centralTenant,
centralTenantAcquisition,
isLoadingCentralTenantAcquisition,
controlledCetralTenantAcqAccorion,
)}
</>
) : (
<TenantAcquisition
acquisitions={activeTenantAcquisition}
isLoading={isLoadingActiveTenantAcquisition}
tenantId={activeTenant}
/>
)
}
</Accordion>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';

import { useStripes } from '@folio/stripes/core';
import { screen } from '@folio/jest-config-stripes/testing-library/react';

import '../../../../test/jest/__mock__';
import renderWithIntl from '../../../../test/jest/helpers/renderWithIntl';
import {
renderWithIntl,
translationsProperties,
} from '../../../../test/jest/helpers';

import { resultData, line } from './fixtures';
import InstanceAcquisition from './InstanceAcquisition';
import useInstanceAcquisition from './useInstanceAcquisition';

import * as utils from '../../../utils';

jest.mock('./useInstanceAcquisition', () => jest.fn());

const spyOnIsUserInConsortiumMode = jest.spyOn(utils, 'isUserInConsortiumMode');

const renderInstanceAcquisition = (props = {}) => (
renderWithIntl(
<Router>
Expand All @@ -20,7 +28,8 @@ const renderInstanceAcquisition = (props = {}) => (
accordionId="accordionId"
{...props}
/>
</Router>
</Router>,
translationsProperties
)
);

Expand All @@ -29,9 +38,70 @@ describe('InstanceAcquisition', () => {
useInstanceAcquisition.mockClear().mockReturnValue({ instanceAcquisition: resultData });
});

it('should display fetched instance acquisition data', () => {
renderInstanceAcquisition({ instanceId: 'instanceId' });
describe('when user is non-consortial tenant', () => {
it('should display acquisition accordion and fetched instance acquisition data', () => {
spyOnIsUserInConsortiumMode.mockReturnValue(false);
useStripes.mockClear().mockReturnValue({
hasInterface: () => true,
okapi: { tenant: 'diku' },
user: { user: {} },
});

const { container } = renderInstanceAcquisition({ instanceId: 'instanceId' });

expect(container.querySelector('#accordionId')).toBeInTheDocument();
expect(screen.getByText(line.poLineNumber)).toBeInTheDocument();
});
});

describe('when user is in central tenant', () => {
it('should display acquisition accordion and fetched instance acquisition data', () => {
spyOnIsUserInConsortiumMode.mockReturnValue(true);
useStripes.mockClear().mockReturnValue({
hasInterface: () => true,
okapi: { tenant: 'consortium' },
user: { user: {
consortium: { centralTenantId: 'consortium' },
tenants: [{
id: 'consortium',
name: 'Consortium',
}],
} },
});

const { container } = renderInstanceAcquisition({ instanceId: 'instanceId' });

expect(container.querySelector('#accordionId')).toBeInTheDocument();
expect(screen.getByText(line.poLineNumber)).toBeInTheDocument();
});
});

describe('when user is in member tenant', () => {
it('should display central and member tenant subaccordions with fetched instance acquisition data', () => {
spyOnIsUserInConsortiumMode.mockReturnValue(true);
useStripes.mockClear().mockReturnValue({
hasInterface: () => true,
okapi: { tenant: 'college' },
user: { user: {
consortium: { centralTenantId: 'consortium' },
tenants: [{
id: 'consortium',
name: 'Consortium',
}, {
id: 'college',
name: 'College',
}],
} },
});

const { container } = renderInstanceAcquisition({ instanceId: 'instanceId' });

expect(container.querySelector('#accordionId')).toBeInTheDocument();
expect(container.querySelector('#active-acquisition-accordion')).toBeInTheDocument();
expect(screen.getAllByText(line.poLineNumber)[0]).toBeInTheDocument();

expect(screen.getByText(line.poLineNumber)).toBeInTheDocument();
expect(container.querySelector('#central-acquisition-accordion')).toBeInTheDocument();
expect(screen.getAllByText(line.poLineNumber)[1]).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';

import {
MultiColumnList,
NoValue,
} from '@folio/stripes/components';

import { getDateWithTime } from '../../../utils';
import { ACQUISITION_COLUMN_NAMES } from '../../../constants';

const visibleColumns = [
ACQUISITION_COLUMN_NAMES.poLineNumber,
ACQUISITION_COLUMN_NAMES.orderStatus,
ACQUISITION_COLUMN_NAMES.polReceiptStatus,
ACQUISITION_COLUMN_NAMES.dateOrdered,
ACQUISITION_COLUMN_NAMES.acqUnit,
ACQUISITION_COLUMN_NAMES.orderType,
];

const columnMapping = {
[ACQUISITION_COLUMN_NAMES.poLineNumber]: <FormattedMessage id="ui-inventory.acq.polNumber" />,
[ACQUISITION_COLUMN_NAMES.orderStatus]: <FormattedMessage id="ui-inventory.acq.orderStatus" />,
[ACQUISITION_COLUMN_NAMES.polReceiptStatus]: <FormattedMessage id="ui-inventory.acq.receiptStatus" />,
[ACQUISITION_COLUMN_NAMES.dateOrdered]: <FormattedMessage id="ui-inventory.acq.dateOpened" />,
[ACQUISITION_COLUMN_NAMES.acqUnit]: <FormattedMessage id="ui-inventory.acq.acqUnit" />,
[ACQUISITION_COLUMN_NAMES.orderType]: <FormattedMessage id="ui-inventory.acq.orderType" />,
};

const formatter = {
[ACQUISITION_COLUMN_NAMES.poLineNumber]: i => <Link to={`/orders/lines/view/${i.id}`}>{i.poLineNumber}</Link>,
[ACQUISITION_COLUMN_NAMES.orderStatus]: i => (
<>
{i.order?.workflowStatus ? <FormattedMessage id={`ui-inventory.acq.orderStatus.${i.order.workflowStatus}`} /> : <NoValue />}
{i.order?.orderCloseReason?.reason && ` - ${i.order.orderCloseReason.reason}`}
</>
),
[ACQUISITION_COLUMN_NAMES.polReceiptStatus]: i => <FormattedMessage id={`ui-inventory.acq.receiptStatus.${i.receiptStatus}`} />,
[ACQUISITION_COLUMN_NAMES.dateOrdered]: i => getDateWithTime(i.order?.dateOrdered),
[ACQUISITION_COLUMN_NAMES.acqUnit]: i => i.order?.acqUnits?.map(u => u.name)?.join(', ') || <NoValue />,
[ACQUISITION_COLUMN_NAMES.orderType]: i => (i.order?.orderType ? <FormattedMessage id={`ui-inventory.acq.orderType.${i.order.orderType}`} /> : <NoValue />),
};

const TenantAcquisition = ({
acquisitions,
isLoading,
tenantId,
}) => (
<MultiColumnList
id={`${tenantId}list-instance-acquisitions`}
loading={isLoading}
contentData={acquisitions}
visibleColumns={visibleColumns}
columnMapping={columnMapping}
formatter={formatter}
interactive={false}
/>
);

TenantAcquisition.propTypes = {
acquisitions: PropTypes.arrayOf(PropTypes.object).isRequired,
isLoading: PropTypes.bool.isRequired,
tenantId: PropTypes.string.isRequired,
};

export default TenantAcquisition;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';

import { screen } from '@folio/jest-config-stripes/testing-library/react';

import '../../../../test/jest/__mock__';
import { renderWithIntl } from '../../../../test/jest/helpers';

import { resultData, line } from './fixtures';
import TenantAcquisition from './TenantAcquisition';

const renderTenantAcquisition = () => (
renderWithIntl(
<Router>
<TenantAcquisition
acquisitions={resultData}
isLoading={false}
tenantId="diku"
/>
</Router>
)
);

describe('TenantAcquisition', () => {
it('should display instance acquisition data', () => {
renderTenantAcquisition();

expect(screen.getByText(line.poLineNumber)).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export const line = {
id: 'lineId',
purchaseOrderId: 'orderId',
poLineNumber: '1000',
receiptStatus: 'Ongoing',
};
export const order = {
id: line.purchaseOrderId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { useOkapiKy, useNamespace, useStripes } from '@folio/stripes/core';
import { LIMIT_MAX } from '../../../constants';
import { batchRequest } from '../../../utils';

const useInstanceAcquisition = (id) => {
const ky = useOkapiKy();
const useInstanceAcquisition = (id, tenant) => {
const ky = useOkapiKy({ tenant });
const [namespace] = useNamespace({ key: 'instance-acquisition' });
const stripes = useStripes();

const { data = [], isLoading } = useQuery(
[namespace, 'instance-acquisition', id],
[namespace, 'instance-acquisition', id, tenant],
async () => {
const { titles = [] } = await ky.get('orders/titles', {
searchParams: {
Expand Down
9 changes: 9 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -724,3 +724,12 @@ export const LEADER_RECORD_STATUSES = {
};

export const USER_TOUCHED_STAFF_SUPPRESS_STORAGE_KEY = 'folio_user_touched_staff_suppress';

export const ACQUISITION_COLUMN_NAMES = {
poLineNumber: 'poLineNumber',
orderStatus: 'orderStatus',
polReceiptStatus: 'polReceiptStatus',
dateOrdered: 'dateOrdered',
acqUnit: 'acqUnit',
orderType: 'orderType',
};
Loading

0 comments on commit 6aa7b8b

Please sign in to comment.