diff --git a/doc/release/RELEASE-NOTES.md b/doc/release/RELEASE-NOTES.md
index 0699f0abc..c10625569 100644
--- a/doc/release/RELEASE-NOTES.md
+++ b/doc/release/RELEASE-NOTES.md
@@ -54,7 +54,7 @@ Also was added sanitization on the server side by using the `Django-Bleach` libr
### Bugfix
* [OSDEV-1806](https://opensupplyhub.atlassian.net/browse/OSDEV-1806) - Refactored the Parent Company field validation. The field is now validated as a regular character field.
-* [OSDEV-1787](https://opensupplyhub.atlassian.net/browse/OSDEV-1787) - The tooltip messages for the Claim button have been removed for all statuses of moderation events on the `Contribution Record` page and changed according to the design on `Thanks for adding data for this production location` pop-up.
+* [OSDEV-1787](https://opensupplyhub.atlassian.net/browse/OSDEV-1787) - The tooltip messages for the Claim button have been removed for all statuses of moderation events on the `Contribution Record` page and changed according to the design on `Thanks for adding data for this production location` pop-up. Changed tooltip text for pending badge if existing production location has pending claim status or has been claimed already.
* [OSDEV-1789](https://opensupplyhub.atlassian.net/browse/OSDEV-1789) - Fixed an issue where the scroll position was not resetting to the top when navigating through SLC workflow pages.
* [OSDEV-1795](https://opensupplyhub.atlassian.net/browse/OSDEV-1795) - Resolved database connection issue after PostgreSQL 16.3 upgrade by upgrading pg8000 module version.
* [OSDEV-1803](https://opensupplyhub.atlassian.net/browse/OSDEV-1803) - Updated text from `Facility Type` to `Location Type` and `Facility Name` to `Location Name` on the SLC `Thank You for Your Submission` page.
diff --git a/src/react/src/__tests__/components/ProductionLocationDialog.test.js b/src/react/src/__tests__/components/ProductionLocationDialog.test.js
index 09b0f62b7..a5d351de4 100644
--- a/src/react/src/__tests__/components/ProductionLocationDialog.test.js
+++ b/src/react/src/__tests__/components/ProductionLocationDialog.test.js
@@ -1,8 +1,12 @@
import React from 'react';
-import { render, screen, fireEvent } from '@testing-library/react';
+import { render, fireEvent } from '@testing-library/react';
import { BrowserRouter as Router, useHistory } from 'react-router-dom';
import ProductionLocationDialog from '../../components/Contribute/ProductionLocationDialog';
import ProductionLocationDialogCloseButton from '../../components/Contribute/ProductionLocationDialogCloseButton';
+import {
+ MODERATION_STATUSES_ENUM,
+ PRODUCTION_LOCATION_CLAIM_STATUSES_ENUM,
+} from '../../util/constants';
jest.mock('react-router-dom', () => ({
@@ -10,6 +14,34 @@ jest.mock('react-router-dom', () => ({
useHistory: jest.fn(),
}));
+jest.mock("../../components/Contribute/DialogTooltip", () => {
+ // eslint-disable-next-line no-shadow, global-require
+ const React = require('react');
+ return function MockDialogTooltip({ text, childComponent }) {
+ const [open, setOpen] = React.useState(false);
+
+ const handleMouseOver = () => {
+ setOpen(true);
+ };
+
+ const handleMouseOut = () => {
+ setOpen(false);
+ };
+
+ return (
+
+ {childComponent}
+ {open &&
{text}
}
+
+ );
+ };
+});
+
const mockHistoryPush = jest.fn();
describe('ProductionLocationDialog', () => {
@@ -66,7 +98,7 @@ describe('ProductionLocationDialog', () => {
});
test('renders dialog content', () => {
- render(
+ const { getAllByText, getByText } = render(
{
);
- expect(screen.getByText(/Thanks for adding data for this production location!/i)).toBeInTheDocument();
+ expect(getByText(/Thanks for adding data for this production location!/i)).toBeInTheDocument();
- expect(screen.getAllByText(/Location name/i)).toHaveLength(2);
- expect(screen.getByText(/Production Location Name/i)).toBeInTheDocument();
+ expect(getAllByText(/Location name/i)).toHaveLength(2);
+ expect(getByText(/Production Location Name/i)).toBeInTheDocument();
- expect(screen.getByText(/Address/i)).toBeInTheDocument();
- expect(screen.getByText(/1234 Production Location St, City, State, 12345/i)).toBeInTheDocument();
+ expect(getByText(/Address/i)).toBeInTheDocument();
+ expect(getByText(/1234 Production Location St, City, State, 12345/i)).toBeInTheDocument();
- expect(screen.getByText(/OS ID/i)).toBeInTheDocument();
- expect(screen.getByText(/US2021250D1DTN7/i)).toBeInTheDocument();
+ expect(getByText(/OS ID/i)).toBeInTheDocument();
+ expect(getByText(/US2021250D1DTN7/i)).toBeInTheDocument();
- expect(screen.getByText(/Pending/i)).toBeInTheDocument();
- expect(screen.getByText(/Location Type/i)).toBeInTheDocument();
+ expect(getByText(/Pending/i)).toBeInTheDocument();
+ expect(getByText(/Location Type/i)).toBeInTheDocument();
- expect(screen.getByText(/Number of workers/i)).toBeInTheDocument();
- expect(screen.getByText(/35 - 60/i)).toBeInTheDocument();
+ expect(getByText(/Number of workers/i)).toBeInTheDocument();
+ expect(getByText(/35 - 60/i)).toBeInTheDocument();
- expect(screen.getByText(/Processing Type/i)).toBeInTheDocument();
- expect(screen.getByText(/Assembly, Printing/i)).toBeInTheDocument();
+ expect(getByText(/Processing Type/i)).toBeInTheDocument();
+ expect(getByText(/Assembly, Printing/i)).toBeInTheDocument();
- expect(screen.getByText(/Parent Company/i)).toBeInTheDocument();
- expect(screen.getByText(/ParentCompany1, ParentCompany2/i)).toBeInTheDocument();
+ expect(getByText(/Parent Company/i)).toBeInTheDocument();
+ expect(getByText(/ParentCompany1, ParentCompany2/i)).toBeInTheDocument();
- expect(screen.getByText(/Country/i)).toBeInTheDocument();
- expect(screen.getByText(/BD/i)).toBeInTheDocument();
+ expect(getByText(/Country/i)).toBeInTheDocument();
+ expect(getByText(/BD/i)).toBeInTheDocument();
- expect(screen.getByText(/Product Type/i)).toBeInTheDocument();
- expect(screen.getByText(/Shirts, Pants/i)).toBeInTheDocument();
+ expect(getByText(/Product Type/i)).toBeInTheDocument();
+ expect(getByText(/Shirts, Pants/i)).toBeInTheDocument();
});
test.each([
@@ -191,7 +223,7 @@ describe('ProductionLocationDialog', () => {
});
test('redirect to the main page when clicking close button', () => {
- render(
+ const { getByText, getByRole } = render(
{
);
- expect(screen.getByText(/Continue to Claim/i)).toBeInTheDocument();
+ expect(getByText(/Continue to Claim/i)).toBeInTheDocument();
- const closeButton = screen.getByRole('button', { name: /close/i });
+ const closeButton = getByRole('button', { name: /close/i });
fireEvent.click(closeButton);
expect(mockHistoryPush).toHaveBeenCalledWith('/');
});
});
+
+describe('ProductionLocationDialog tooltip messages for PENDING, CLAIMED and UNCLAIMED production locations', () => {
+ const defaultProps = {
+ osID: 'US2021250D1DTN7',
+ data: {
+ raw_json: {
+ name: 'Production Location Name',
+ address: '1234 Production Location St, City, State, 12345',
+ },
+ fields: {
+ country: "BD"
+ }
+ }
+ };
+
+ beforeEach(() => {
+ useHistory.mockReturnValue({
+ push: mockHistoryPush,
+ listen: jest.fn(() => jest.fn()),
+ });
+ });
+
+ test.each([
+ [PRODUCTION_LOCATION_CLAIM_STATUSES_ENUM.CLAIMED,
+ 'Your submission is being reviewed. You will receive an email confirming your OS ID once the review is complete.',
+ 'This location has already been claimed and therefore cannot be claimed again.'],
+ [PRODUCTION_LOCATION_CLAIM_STATUSES_ENUM.PENDING,
+ 'Your submission is being reviewed. You will receive an email confirming your OS ID once the review is complete.',
+ 'This location cannot be claimed because a pending claim already exists.']
+ ])(
+ 'renders claim button and pending badge tooltips when moderation event is pending and production location has status: %s',
+ async (claimStatus, expectedPendingTooltip, expectedClaimTooltip) => {
+ const { getAllByTestId, getByRole, findByText } = render(
+
+
+
+ );
+
+ const tooltipIcons = getAllByTestId('tooltip-icon');
+
+ // Pending icon tooltip message
+ fireEvent.mouseOver(tooltipIcons[0]);
+
+ const pendingTooltipText = await findByText(expectedPendingTooltip);
+ expect(pendingTooltipText).toBeInTheDocument();
+
+ fireEvent.mouseOut(tooltipIcons[0]);
+ expect(pendingTooltipText).not.toBeInTheDocument();
+
+ // Claim button tooltip message
+ const claimButton = getByRole('button', { name: /Continue to Claim/i });
+ expect(claimButton).toHaveAttribute('tabindex', '-1');
+
+ fireEvent.mouseOver(claimButton);
+ const claimTooltipText = await findByText(expectedClaimTooltip);
+ expect(claimTooltipText).toBeInTheDocument();
+
+ fireEvent.mouseOut(claimButton);
+ expect(claimTooltipText).not.toBeInTheDocument();
+ }
+ );
+
+ test('renders claim button and pending badge tooltips when moderation event is pending and production location is available for claim', async () => {
+ const { getAllByTestId, getByRole, findByText } = render(
+
+
+
+ );
+
+ // Pending icon tooltip message
+ const tooltipIcons = getAllByTestId('tooltip-icon');
+
+ fireEvent.mouseOver(tooltipIcons[0]);
+
+ const pendingTooltipText = await findByText(
+ 'Your submission is under review. You will receive a notification once the production location is live on OS Hub. You can proceed to submit a claim while your request is pending.'
+ );
+ expect(pendingTooltipText).toBeInTheDocument();
+
+ fireEvent.mouseOut(tooltipIcons[0]);
+ expect(pendingTooltipText).not.toBeInTheDocument();
+
+ // Claim button
+ const claimButton = getByRole('button', { name: /Continue to Claim/i });
+ expect(claimButton).toHaveAttribute('href', `/facilities/${defaultProps.osID}/claim`);
+ expect(claimButton).not.toBeDisabled();
+ });
+
+ test('renders claim button and pending badge tooltips when moderation event is pending and production location has\'t been created yet', async () => {
+ const { getAllByTestId, getByRole, findByText } = render(
+
+
+
+ );
+
+ // Pending icon tooltip message
+ const tooltipIcons = getAllByTestId('tooltip-icon');
+
+ fireEvent.mouseOver(tooltipIcons[0]);
+
+ const pendingTooltipText = await findByText(
+ 'Your submission is being reviewed. You will receive an email with your OS ID once the review is complete.'
+ );
+ expect(pendingTooltipText).toBeInTheDocument();
+
+ fireEvent.mouseOut(tooltipIcons[0]);
+ expect(pendingTooltipText).not.toBeInTheDocument();
+
+ // Claim button tooltip message
+ const claimButton = getByRole('button', { name: /Continue to Claim/i });
+ expect(claimButton).toHaveAttribute('tabindex', '-1');
+
+ fireEvent.mouseOver(claimButton);
+ const claimTooltipText = await findByText(
+ 'You will be able to claim this location once the review is complete.'
+ );
+ expect(claimTooltipText).toBeInTheDocument();
+
+ fireEvent.mouseOut(claimButton);
+ expect(claimTooltipText).not.toBeInTheDocument();
+ });
+});
diff --git a/src/react/src/__tests__/components/RejectModerationEventDialog.test.js b/src/react/src/__tests__/components/RejectModerationEventDialog.test.js
index 6eb5e9325..14b7161f6 100644
--- a/src/react/src/__tests__/components/RejectModerationEventDialog.test.js
+++ b/src/react/src/__tests__/components/RejectModerationEventDialog.test.js
@@ -33,14 +33,13 @@ jest.mock('@material-ui/core/Tooltip', () => ({ children, title, open, onOpen, o
onMouseOver={onOpen}
onFocus={onOpen}
onMouseOut={onClose}
- onBlur={onClose}
+ onBlur={onClose}
>
{children}
{open && {title}
}
));
-
-
+
describe('RejectModerationEventDialog component', () => {
const defaultProps = {
updateModerationEvent: mockUpdateModerationEvent,
@@ -66,7 +65,7 @@ describe('RejectModerationEventDialog component', () => {
test('calls closeDialog when "Cancel" button is clicked', () => {
const { getByRole } = renderWithProviders();
const cancelButton = getByRole('button', {name: /Cancel/i});
-
+
fireEvent.click(cancelButton);
expect(mockCloseDialog).toHaveBeenCalledTimes(1);
});
@@ -76,10 +75,10 @@ describe('RejectModerationEventDialog component', () => {
);
const rejectButton = getByRole('button', {name: /Reject/i});
-
+
expect(rejectButton).toBeDisabled();
});
-
+
test('reject button is enabled when editor text is at least 30 characters and calls updateModerationEvent and closeDialog on click', async () => {
const { getByRole, getByTestId } = renderWithProviders(
@@ -94,9 +93,9 @@ describe('RejectModerationEventDialog component', () => {
fireEvent.change(fakeEditor, { target: { value: validText } });
expect(rejectButton).toBeEnabled();
-
+
fireEvent.click(rejectButton);
-
+
expect(mockUpdateModerationEvent).toHaveBeenCalledTimes(1);
expect(mockUpdateModerationEvent).toHaveBeenCalledWith(
MODERATION_STATUSES_ENUM.REJECTED,
@@ -137,7 +136,7 @@ describe('RejectModerationEventDialog component', () => {
fireEvent.change(fakeEditor, { target: { value: validText } });
expect(rejectButton).toBeEnabled();
-
+
fireEvent.mouseOver(rejectButton);
expect(queryByText('Please provide a message with at least 30 characters.')).not.toBeInTheDocument();
});
diff --git a/src/react/src/components/Contribute/ProductionLocationDialog.jsx b/src/react/src/components/Contribute/ProductionLocationDialog.jsx
index b272149a3..d1c806e08 100644
--- a/src/react/src/components/Contribute/ProductionLocationDialog.jsx
+++ b/src/react/src/components/Contribute/ProductionLocationDialog.jsx
@@ -35,7 +35,10 @@ import { makeProductionLocationDialogStyles } from '../../util/styles';
import { getIsMobile, makeClaimFacilityLink } from '../../util/util';
const infoIcon = classes => (
-
+
);
const claimButton = ({ classes, osID = '', isDisabled = true }) => (
@@ -72,9 +75,21 @@ const getStatusBadgeClass = (classes, status) => {
};
const getPendingTooltipText = claimStatus => {
- if (claimStatus === PRODUCTION_LOCATION_CLAIM_STATUSES_ENUM.UNCLAIMED) {
+ const {
+ PENDING,
+ CLAIMED,
+ UNCLAIMED,
+ } = PRODUCTION_LOCATION_CLAIM_STATUSES_ENUM;
+
+ if (claimStatus === PENDING || claimStatus === CLAIMED) {
+ return 'Your submission is being reviewed. You will receive an email confirming your OS ID once the review is complete.';
+ }
+
+ if (claimStatus === UNCLAIMED) {
return 'Your submission is under review. You will receive a notification once the production location is live on OS Hub. You can proceed to submit a claim while your request is pending.';
}
+
+ // Default tooltip text if a production location hasn't been created yet.
return 'Your submission is being reviewed. You will receive an email with your OS ID once the review is complete.';
};