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
  • Loading branch information
OleksandrHladchenko1 committed May 10, 2024
1 parent 4a86d95 commit 89f6fc9
Show file tree
Hide file tree
Showing 8 changed files with 239 additions and 51 deletions.
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -889,7 +889,7 @@
"@babel/preset-react": "^7.9.0",
"@folio/eslint-config-stripes": "^7.0.0",
"@folio/jest-config-stripes": "^2.0.0",
"@folio/stripes": "^9.1.2",
"@folio/stripes": "^9.1.0",
"@folio/stripes-cli": "^3.1.0",
"@folio/stripes-components": "^12.1.2",
"@folio/stripes-connect": "^9.1.0",
Expand Down Expand Up @@ -936,7 +936,7 @@
"use-session-storage-state": "^18.2.0"
},
"peerDependencies": {
"@folio/stripes": "^9.1.2",
"@folio/stripes": "^9.1.0",
"@folio/stripes-marc-components": "^1.0.1",
"react": "^18.2.0",
"react-intl": "^6.4.4",
Expand Down
@@ -1,66 +1,86 @@
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 './TenantAcquisition.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 getTenantAccordionLabel = (tenants, id) => tenants?.find(tenant => tenant.id === id).name;

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) ? (
<>
<Accordion
id="active-tenant-acquisition-accordion"
label={getTenantAccordionLabel(stripes.user.user.tenants, activeTenant)}
className={css.tenantAcquisitionAccordion}
{...controlledActiveTenantAcqAccorion}
>
<TenantAcquisition
acquisitions={activeTenantAcquisition}
isLoading={isLoadingActiveTenantAcquisition}
tenantId={activeTenant}
/>
</Accordion>

{activeTenant !== centralTenant && (
<Accordion
id="central-tenant-acquisition-accordion"
label={getTenantAccordionLabel(stripes.user.user.tenants, centralTenant)}
className={css.tenantAcquisitionAccordion}
{...controlledCetralTenantAcqAccorion}
>
<TenantAcquisition
acquisitions={centralTenantAcquisition}
isLoading={isLoadingCentralTenantAcquisition}
tenantId={centralTenant}
/>
</Accordion>
)}
</>
) : (
<TenantAcquisition
acquisitions={activeTenantAcquisition}
isLoading={isLoadingActiveTenantAcquisition}
tenantId={activeTenant}
/>
)
}
</Accordion>
);
};
Expand Down
@@ -1,17 +1,30 @@
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('@folio/stripes/core', () => ({
...jest.requireActual('@folio/stripes/core'),
useStripes: jest.fn(),
}));
jest.mock('./useInstanceAcquisition', () => jest.fn());

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

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

Expand All @@ -29,9 +43,71 @@ 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 render central tenant subaccordion with 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(container.querySelector('#active-tenant-acquisition-accordion')).toBeInTheDocument();
expect(screen.getByText(line.poLineNumber)).toBeInTheDocument();
});
});

describe('when user is in member tenant', () => {
it('should render central and member tenant subaccordion 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-tenant-acquisition-accordion')).toBeInTheDocument();
expect(screen.getAllByText(line.poLineNumber)[0]).toBeInTheDocument();

expect(screen.getByText(line.poLineNumber)).toBeInTheDocument();
expect(container.querySelector('#central-tenant-acquisition-accordion')).toBeInTheDocument();
expect(screen.getAllByText(line.poLineNumber)[1]).toBeInTheDocument();
});
});
});
@@ -0,0 +1,3 @@
.tenantAcquisitionAccordion {
padding-left: 15px;
}
@@ -0,0 +1,58 @@
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';

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 />),
};

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;
@@ -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();
});
});
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
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

0 comments on commit 89f6fc9

Please sign in to comment.