Skip to content

Commit

Permalink
Merge pull request #13690 from transcom/MAIN-B-19044
Browse files Browse the repository at this point in the history
MAIN B-19044
  • Loading branch information
cameroncaci authored Oct 11, 2024
2 parents 1b7e280 + 43e5876 commit 0c22356
Show file tree
Hide file tree
Showing 17 changed files with 237 additions and 104 deletions.
5 changes: 3 additions & 2 deletions eslint-plugin-ato/no-unapproved-annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const NO_ANNOTATION_MESSAGE_ID = 'no-annotation';
const NO_INLINE_DISABLE = 'no-inline-disable';
const messages = {
[REQUIRES_APPROVAL_MESSAGE_ID]:
'Please add the truss-is3 team as reviewers for this PR and ping the ISSO in #static-code-review Slack. Add label ‘needs-is3-review’ to this PR. For more information, please visit https://dp3.atlassian.net/wiki/spaces/MT/pages/1920991340/Guide+to+Static+Analysis+Security+Workflow',
'Due to an added annotation, this PR requires approval from a codeowner. Once a codeowner has reviewed/approved your PR, you will need to change the RA Validator Status to CODEOWNER ACCEPTED. For more information, please visit https://dp3.atlassian.net/wiki/spaces/MT/pages/1920991340/Guide+to+Static+Analysis+Security+Workflow',
[NO_ANNOTATION_MESSAGE_ID]:
'Disabling of this rule requires an annotation. Please visit https://dp3.atlassian.net/wiki/spaces/MT/pages/1921122376/Guide+to+Static+Analysis+Annotations+for+Disabled+Linters',
[NO_INLINE_DISABLE]: 'Please use eslint-disable-next-line instead of eslint-disable-line',
Expand All @@ -13,7 +13,8 @@ const messages = {
const disableRegex = /^eslint-disable(?:-next-line|-line)?(?<ruleId>$|(?:\s+(?:@(?:[\w-]+\/){1,2})?[\w-]+)?)/;

const validatorStatusOptions = new Set([
'RA ACCEPTED',
'CODEOWNER ACCEPTED',
'RA ACCEPTED', // THIS LINE IS DEPRECATED AS OF 9/30/2024 - leaving d/t previous implementation
'RETURN TO DEVELOPER',
'KNOWN ISSUE',
'MITIGATED',
Expand Down
2 changes: 1 addition & 1 deletion eslint-plugin-ato/tests/no-unapproved-annotation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const ruleTester = new RuleTester();

const ERRORS = {
REQUIRES_APPROVAL_MSG:
'Please add the truss-is3 team as reviewers for this PR and ping the ISSO in #static-code-review Slack. Add label ‘needs-is3-review’ to this PR. For more information, please visit https://dp3.atlassian.net/wiki/spaces/MT/pages/1920991340/Guide+to+Static+Analysis+Security+Workflow',
'Due to an added annotation, this PR requires approval from a codeowner. Once a codeowner has reviewed/approved your PR, you will need to change the RA Validator Status to CODEOWNER ACCEPTED. For more information, please visit https://dp3.atlassian.net/wiki/spaces/MT/pages/1920991340/Guide+to+Static+Analysis+Security+Workflow',
REQUIRES_ANNOTATION_MSG:
'Disabling of this rule requires an annotation. Please visit https://dp3.atlassian.net/wiki/spaces/MT/pages/1921122376/Guide+to+Static+Analysis+Annotations+for+Disabled+Linters',
NO_INLINE_DISABLE_MSG: 'Please use eslint-disable-next-line instead of eslint-disable-line',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,8 @@ test.describe('Services counselor user', () => {
await expect(page.locator('a[href*="#orders"]')).toContainText('Orders');
await expect(page.locator('a[href*="#allowances"]')).toContainText('Allowances');
await expect(page.locator('a[href*="#customer-info"]')).toContainText('Customer info');

await expect(page.locator('[data-testid="requestedShipmentsTag"]')).toContainText('3');
// one warning in red for the missing destinationType
await expect(page.locator('[data-testid="shipment-missing-info-alert"]')).toContainText('1');

// Assert that the window has scrolled after clicking a left nav item
const origScrollY = await page.evaluate(() => window.scrollY);
Expand Down Expand Up @@ -385,7 +385,7 @@ test.describe('Services counselor user', () => {

test('is able to see that the tag next to shipment is updated', async ({ page, scPage }) => {
// Verify that there's a tag on the left nav that flags missing information
await expect(page.locator('[data-testid="requestedShipmentsTag"]')).toContainText('3');
await expect(page.locator('[data-testid="shipment-missing-info-alert"]')).toContainText('1');

// Edit the shipment so that the tag disappears
await page.locator('[data-testid="ShipmentContainer"] .usa-button').last().click();
Expand All @@ -395,8 +395,8 @@ test.describe('Services counselor user', () => {

await expect(page.locator('.usa-alert__text')).toContainText('Your changes were saved.');

// Verify that the tag after the update is a 2 since missing information was filled
await expect(page.locator('[data-testid="requestedShipmentsTag"]')).toContainText('2');
// Verify that the tag after the update is blank since missing information was filled
await expect(page.locator('[data-testid="shipment-missing-info-alert"]')).toHaveCount(0);
});
});

Expand Down
4 changes: 2 additions & 2 deletions src/components/Office/DefinitionLists/PPMShipmentInfoList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,9 @@ const PPMShipmentInfoList = ({
</dd>
</div>
);
const counselorRemarksElementFlags = getDisplayFlags('counselorRemarks');

const counselorRemarksElement = (
<div className={counselorRemarksElementFlags.classes}>
<div className={styles.row}>
<dt>Counselor remarks</dt>
<dd data-testid="counselorRemarks">{shipment.counselorRemarks || '—'}</dd>
</div>
Expand Down
3 changes: 1 addition & 2 deletions src/components/Office/DefinitionLists/ShipmentInfoList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,8 @@ const ShipmentInfoList = ({
</div>
);

const counselorRemarksElementFlags = getDisplayFlags('counselorRemarks');
const counselorRemarksElement = (
<div className={counselorRemarksElementFlags.classes}>
<div className={styles.row}>
<dt>Counselor remarks</dt>
<dd data-testid="counselorRemarks">{counselorRemarks || '—'}</dd>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';

import '@testing-library/jest-dom/extend-expect';
import ConfirmCustomerExpenseModal from './ConfirmCustomerExpenseModal';

describe('ConfirmCustomerExpenseModal', () => {
let setShowConfirmModal;
let setValues;
let values;

beforeEach(() => {
setShowConfirmModal = jest.fn();
setValues = jest.fn();
values = { convertToCustomerExpense: false };
});

it('renders the modal with correct content', () => {
render(
<ConfirmCustomerExpenseModal setShowConfirmModal={setShowConfirmModal} values={values} setValues={setValues} />,
);

expect(screen.getByText('Convert to Customer Expense')).toBeInTheDocument();
expect(screen.getByText('Are you sure that you would like to convert to Customer Expense?')).toBeInTheDocument();
// Check if both "Yes" and "No" buttons are rendered
expect(screen.getByTestId('convertToCustomerExpenseConfirmationYes')).toBeInTheDocument();
expect(screen.getByTestId('convertToCustomerExpenseConfirmationNo')).toBeInTheDocument();
});

it('handles "Yes" button click by setting convertToCustomerExpense to true and closing the modal', () => {
render(
<ConfirmCustomerExpenseModal setShowConfirmModal={setShowConfirmModal} values={values} setValues={setValues} />,
);

const yesButton = screen.getByTestId('convertToCustomerExpenseConfirmationYes');
fireEvent.click(yesButton);
expect(setValues).toHaveBeenCalledWith({ ...values, convertToCustomerExpense: true });
expect(setShowConfirmModal).toHaveBeenCalledWith(false);
});

it('handles "No" button click by setting convertToCustomerExpense to false and closing the modal', () => {
render(
<ConfirmCustomerExpenseModal setShowConfirmModal={setShowConfirmModal} values={values} setValues={setValues} />,
);

const noButton = screen.getByTestId('convertToCustomerExpenseConfirmationNo');
fireEvent.click(noButton);
expect(setValues).toHaveBeenCalledWith({ ...values, convertToCustomerExpense: false });
expect(setShowConfirmModal).toHaveBeenCalledWith(false);
});

it('handles closing the modal via the close button', () => {
render(
<ConfirmCustomerExpenseModal setShowConfirmModal={setShowConfirmModal} values={values} setValues={setValues} />,
);

const closeButton = screen.getByRole('button', { name: /close/i });
fireEvent.click(closeButton);
expect(setShowConfirmModal).toHaveBeenCalledWith(false);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import 'styles/office.scss';
import TabNav from 'components/TabNav';
import { isBooleanFlagEnabled } from 'utils/featureFlags';

const ServicesCounselingTabNav = ({ unapprovedShipmentCount = 0, missingOrdersInfoCount, moveCode }) => {
const ServicesCounselingTabNav = ({
shipmentWarnConcernCount = 0,
shipmentErrorConcernCount,
missingOrdersInfoCount,
moveCode,
}) => {
const [supportingDocsFF, setSupportingDocsFF] = React.useState(false);
React.useEffect(() => {
const fetchData = async () => {
Expand All @@ -20,8 +25,11 @@ const ServicesCounselingTabNav = ({ unapprovedShipmentCount = 0, missingOrdersIn
}, []);

let moveDetailsTagCount = 0;
if (unapprovedShipmentCount > 0) {
moveDetailsTagCount += unapprovedShipmentCount;
if (shipmentWarnConcernCount > 0) {
moveDetailsTagCount += shipmentWarnConcernCount;
}
if (shipmentErrorConcernCount > 0) {
moveDetailsTagCount += shipmentErrorConcernCount;
}
if (missingOrdersInfoCount > 0) {
moveDetailsTagCount += missingOrdersInfoCount;
Expand Down Expand Up @@ -87,12 +95,9 @@ const ServicesCounselingTabNav = ({ unapprovedShipmentCount = 0, missingOrdersIn
);
};

ServicesCounselingTabNav.defaultProps = {
unapprovedShipmentCount: 0,
};
ServicesCounselingTabNav.defaultProps = {};

ServicesCounselingTabNav.propTypes = {
unapprovedShipmentCount: PropTypes.number,
moveCode: PropTypes.string.isRequired,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,25 @@ describe('Move details tag rendering', () => {
it('should render the move details tab container with a tag that shows the count of action items', () => {
const moveDetailsShipmentAndAmendedOrders = {
...basicNavProps,
unapprovedShipmentCount: 6,
missingOrdersInfoCount: 4,
};
render(<ServicesCounselingTabNav {...moveDetailsShipmentAndAmendedOrders} />, { wrapper: MemoryRouter });

const moveDetailsTab = screen.getByTestId('MoveDetails-Tab');
expect(within(moveDetailsTab).getByTestId('tag')).toHaveTextContent('10');
expect(within(moveDetailsTab).getByTestId('tag')).toHaveTextContent('4');
});

it('should render the move details tab container with a tag that shows the count of an warn and error count', () => {
const moveDetailsShipmentAndAmendedOrders = {
...basicNavProps,
missingOrdersInfoCount: 4,
shipmentWarnConcernCount: 2,
shipmentErrorConcernCount: 1,
};
render(<ServicesCounselingTabNav {...moveDetailsShipmentAndAmendedOrders} />, { wrapper: MemoryRouter });

const moveDetailsTab = screen.getByTestId('MoveDetails-Tab');
expect(within(moveDetailsTab).getByTestId('tag')).toHaveTextContent('7');
});
});

Expand Down
4 changes: 4 additions & 0 deletions src/components/Office/TXOTabNav/TXOTabNav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const TXOTabNav = ({
pendingPaymentRequestCount,
unapprovedSITExtensionCount,
missingOrdersInfoCount,
shipmentErrorConcernCount,
shipmentsWithDeliveryAddressUpdateRequestedCount,
order,
moveCode,
Expand All @@ -37,6 +38,9 @@ const TXOTabNav = ({
if (order.uploadedAmendedOrderID && !order.amendedOrdersAcknowledgedAt) {
moveDetailsTagCount += 1;
}
if (shipmentErrorConcernCount) {
moveDetailsTagCount += shipmentErrorConcernCount;
}
if (shipmentsWithDeliveryAddressUpdateRequestedCount) {
moveDetailsTagCount += shipmentsWithDeliveryAddressUpdateRequestedCount;
}
Expand Down
82 changes: 52 additions & 30 deletions src/pages/Office/MoveDetails/MoveDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,37 +36,54 @@ import { permissionTypes } from 'constants/permissions';
import { objectIsMissingFieldWithCondition } from 'utils/displayFlags';
import formattedCustomerName from 'utils/formattedCustomerName';
import { calculateEstimatedWeight } from 'hooks/custom';

const errorIfMissing = {
HHG_INTO_NTS_DOMESTIC: [
{ fieldName: 'storageFacility' },
{ fieldName: 'serviceOrderNumber' },
{ fieldName: 'tacType' },
],
HHG_OUTOF_NTS_DOMESTIC: [
{ fieldName: 'storageFacility' },
{ fieldName: 'ntsRecordedWeight' },
{ fieldName: 'serviceOrderNumber' },
{ fieldName: 'tacType' },
],
};
import { ADVANCE_STATUSES } from 'constants/ppms';

const MoveDetails = ({
setUnapprovedShipmentCount,
setUnapprovedServiceItemCount,
setExcessWeightRiskCount,
setUnapprovedSITExtensionCount,
setShipmentErrorConcernCount,
shipmentErrorConcernCount,
setShipmentsWithDeliveryAddressUpdateRequestedCount,
missingOrdersInfoCount,
setMissingOrdersInfoCount,
isMoveLocked,
}) => {
const { moveCode } = useParams();
const [isFinancialModalVisible, setIsFinancialModalVisible] = useState(false);
const [shipmentMissingRequiredInformation, setShipmentMissingRequiredInformation] = useState(false);
const [alertMessage, setAlertMessage] = useState(null);
const [alertType, setAlertType] = useState('success');

// RA Summary: eslint-disable-next-line react-hooks/exhaustive-deps
// RA: This rule is used to enforce correct dependency arrays in hooks like useEffect, useCallback, and useMemo.
// RA: We are disabling this rule here because adding useMemo causes undesired behavior in our case.
// RA Developer Status: Known Issue - Intentional decision to prevent page refresh issues related to action counts.
// RA Validator Status: CODEOWNER ACCEPTED
// RA Modified Severity: N/A
// eslint-disable-next-line react-hooks/exhaustive-deps
const errorIfMissing = {
HHG_INTO_NTS_DOMESTIC: [
{ fieldName: 'storageFacility' },
{ fieldName: 'serviceOrderNumber' },
{ fieldName: 'tacType' },
],
HHG_OUTOF_NTS_DOMESTIC: [
{ fieldName: 'storageFacility' },
{ fieldName: 'ntsRecordedWeight' },
{ fieldName: 'serviceOrderNumber' },
{ fieldName: 'tacType' },
],
PPM: [
{
fieldName: 'advanceStatus',
condition: (mtoShipment) =>
mtoShipment?.ppmShipment?.hasRequestedAdvance === true &&
mtoShipment?.ppmShipment?.advanceStatus !== ADVANCE_STATUSES.APPROVED.apiValue,
},
],
};

const navigate = useNavigate();

const { move, customerData, order, closeoutOffice, mtoShipments, mtoServiceItems, isLoading, isError } =
Expand Down Expand Up @@ -224,21 +241,25 @@ const MoveDetails = ({
}, [mtoShipments, setUnapprovedSITExtensionCount]);

useEffect(() => {
let shipmentIsMissingInformation = false;
// Reset the error count before running any logic
let numberOfErrorIfMissingForAllShipments = 0;

// Process each shipment to accumulate errors
mtoShipments?.forEach((mtoShipment) => {
const fieldsToCheckForShipment = errorIfMissing[mtoShipment.shipmentType];
const existsMissingFieldsOnShipment = fieldsToCheckForShipment?.some((field) =>
objectIsMissingFieldWithCondition(mtoShipment, field),
);

// If there were no fields to check, then nothing was required.
if (fieldsToCheckForShipment && existsMissingFieldsOnShipment) {
shipmentIsMissingInformation = true;
const errorIfMissingList = errorIfMissing[mtoShipment.shipmentType];

if (errorIfMissingList) {
errorIfMissingList.forEach((fieldToCheck) => {
if (objectIsMissingFieldWithCondition(mtoShipment, fieldToCheck)) {
numberOfErrorIfMissingForAllShipments += 1;
}
});
}
});
setShipmentMissingRequiredInformation(shipmentIsMissingInformation);
}, [mtoShipments]);

// Set the error concern count after processing
setShipmentErrorConcernCount(numberOfErrorIfMissingForAllShipments);
}, [errorIfMissing, mtoShipments, setShipmentErrorConcernCount]);

// using useMemo here due to this being used in a useEffect
// using useMemo prevents the useEffect from being rendered on ever render by memoizing the object
Expand Down Expand Up @@ -344,18 +365,18 @@ const MoveDetails = ({
</LeftNavTag>
<LeftNavTag
associatedSectionName="requested-shipments"
showTag={!shipmentMissingRequiredInformation}
showTag={submittedShipments?.length > 0}
testID="requestedShipmentsTag"
>
{submittedShipments?.length || 0}
</LeftNavTag>
<LeftNavTag
className="usa-tag usa-tag--alert"
background="#e34b11"
associatedSectionName="requested-shipments"
showTag={shipmentMissingRequiredInformation}
showTag={shipmentErrorConcernCount !== 0}
testID="shipment-missing-info-alert"
>
<FontAwesomeIcon icon="exclamation" />
{shipmentErrorConcernCount}
</LeftNavTag>
<LeftNavTag
associatedSectionName="approved-shipments"
Expand Down Expand Up @@ -529,6 +550,7 @@ MoveDetails.propTypes = {
setUnapprovedServiceItemCount: func.isRequired,
setExcessWeightRiskCount: func.isRequired,
setUnapprovedSITExtensionCount: func.isRequired,
setShipmentErrorConcernCount: func.isRequired,
setShipmentsWithDeliveryAddressUpdateRequestedCount: func,
};

Expand Down
Loading

0 comments on commit 0c22356

Please sign in to comment.