From ea2dda5c8cbc7268630d8a26a69f731f6c25310a Mon Sep 17 00:00:00 2001 From: Michael Inthavongsay Date: Wed, 28 Feb 2024 17:56:49 +0000 Subject: [PATCH 01/18] temp update to deploy to exp --- .circleci/config.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6ce2a34eb25..13c475c3642 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -40,30 +40,30 @@ references: # In addition, it's common practice to disable acceptance tests and # ignore tests for dp3 deploys. See the branch settings below. - dp3-branch: &dp3-branch placeholder_branch_name + dp3-branch: &dp3-branch B-18060-UI-Download-AOA-Packet-Customer # MUST BE ONE OF: loadtest, demo, exp. # These are used to pull in env vars so the spelling matters! - dp3-env: &dp3-env placeholder_env + dp3-env: &dp3-env exp # set integration-ignore-branch to the branch if you want to IGNORE # integration tests, or `placeholder_branch_name` if you do want to # run them - integration-ignore-branch: &integration-ignore-branch placeholder_branch_name + integration-ignore-branch: &integration-ignore-branch B-18060-UI-Download-AOA-Packet-Customer # set integration-mtls-ignore-branch to the branch if you want to # IGNORE mtls integration tests, or `placeholder_branch_name` if you # do want to run them - integration-mtls-ignore-branch: &integration-mtls-ignore-branch placeholder_branch_name + integration-mtls-ignore-branch: &integration-mtls-ignore-branch B-18060-UI-Download-AOA-Packet-Customer # set client-ignore-branch to the branch if you want to IGNORE # client tests, or `placeholder_branch_name` if you do want to run # them - client-ignore-branch: &client-ignore-branch placeholder_branch_name + client-ignore-branch: &client-ignore-branch B-18060-UI-Download-AOA-Packet-Customer # set server-ignore-branch to the branch if you want to IGNORE # server tests, or `placeholder_branch_name` if you do want to run # them - server-ignore-branch: &server-ignore-branch placeholder_branch_name + server-ignore-branch: &server-ignore-branch B-18060-UI-Download-AOA-Packet-Customer executors: base_small: From 203b9c995f5b2f9e685a62dd9d90bd71400d4947 Mon Sep 17 00:00:00 2001 From: Michael Inthavongsay Date: Wed, 28 Feb 2024 19:01:43 +0000 Subject: [PATCH 02/18] temp change to resolve db migration for exp deployment. must undo before merging to main. --- ...ment_address_update_table_sit_and_distance_columns.up.sql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql b/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql index 172b6d62e83..e17169ef6ab 100644 --- a/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql +++ b/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql @@ -2,7 +2,8 @@ ALTER TABLE shipment_address_updates ADD COLUMN sit_original_address_id uuid DEFAULT NULL, ADD COLUMN old_sit_distance_between INTEGER DEFAULT NULL, -ADD COLUMN new_sit_distance_between INTEGER DEFAULT NULL; +ADD COLUMN IF NOT EXISTS new_sit_distance_between INTEGER DEFAULT NULL; +-- ADD COLUMN new_sit_distance_between INTEGER DEFAULT NULL; -- Add foreign key constraint ALTER TABLE shipment_address_updates @@ -12,4 +13,4 @@ FOREIGN KEY (sit_original_address_id) REFERENCES addresses(id); -- Comments on new columns COMMENT on COLUMN shipment_address_updates.sit_original_address_id IS 'SIT address at the original time of SIT approval'; COMMENT on COLUMN shipment_address_updates.old_sit_distance_between IS 'Distance between original SIT address and previous shipment destination address'; -COMMENT on COLUMN shipment_address_updates.new_sit_distance_between IS 'Distance between original SIT address and new shipment destination address'; \ No newline at end of file +COMMENT on COLUMN shipment_address_updates.new_sit_distance_between IS 'Distance between original SIT address and new shipment destination address'; From 77a64a367c6278a8559dd8f8461105ddbdaa075f Mon Sep 17 00:00:00 2001 From: Michael Inthavongsay Date: Wed, 28 Feb 2024 19:38:01 +0000 Subject: [PATCH 03/18] part 2 temp change to resolve db migration for exp deployment. must undo before merging to main. --- ...ent_address_update_table_sit_and_distance_columns.up.sql | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql b/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql index e17169ef6ab..25eb012ae57 100644 --- a/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql +++ b/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql @@ -1,8 +1,10 @@ -- Adds new columns to shipment address update table ALTER TABLE shipment_address_updates -ADD COLUMN sit_original_address_id uuid DEFAULT NULL, -ADD COLUMN old_sit_distance_between INTEGER DEFAULT NULL, +ADD COLUMN IF NOT EXISTS sit_original_address_id uuid DEFAULT NULL, +ADD COLUMN IF NOT EXISTS old_sit_distance_between INTEGER DEFAULT NULL, ADD COLUMN IF NOT EXISTS new_sit_distance_between INTEGER DEFAULT NULL; +-- ADD COLUMN sit_original_address_id uuid DEFAULT NULL, +-- ADD COLUMN old_sit_distance_between INTEGER DEFAULT NULL, -- ADD COLUMN new_sit_distance_between INTEGER DEFAULT NULL; -- Add foreign key constraint From 4bbd021b0ebbb3c668165f04b89e7430689422b4 Mon Sep 17 00:00:00 2001 From: Michael Inthavongsay Date: Wed, 28 Feb 2024 19:59:13 +0000 Subject: [PATCH 04/18] part 3 temp change to resolve db migration for exp deployment. must undo before merging to main. --- ...ress_update_table_sit_and_distance_columns.up.sql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql b/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql index 25eb012ae57..e5e40181205 100644 --- a/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql +++ b/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql @@ -8,11 +8,11 @@ ADD COLUMN IF NOT EXISTS new_sit_distance_between INTEGER DEFAULT NULL; -- ADD COLUMN new_sit_distance_between INTEGER DEFAULT NULL; -- Add foreign key constraint -ALTER TABLE shipment_address_updates -ADD CONSTRAINT fk_sit_original_address -FOREIGN KEY (sit_original_address_id) REFERENCES addresses(id); +-- ALTER TABLE shipment_address_updates +-- ADD CONSTRAINT fk_sit_original_address +-- FOREIGN KEY (sit_original_address_id) REFERENCES addresses(id); -- Comments on new columns -COMMENT on COLUMN shipment_address_updates.sit_original_address_id IS 'SIT address at the original time of SIT approval'; -COMMENT on COLUMN shipment_address_updates.old_sit_distance_between IS 'Distance between original SIT address and previous shipment destination address'; -COMMENT on COLUMN shipment_address_updates.new_sit_distance_between IS 'Distance between original SIT address and new shipment destination address'; +-- COMMENT on COLUMN shipment_address_updates.sit_original_address_id IS 'SIT address at the original time of SIT approval'; +-- COMMENT on COLUMN shipment_address_updates.old_sit_distance_between IS 'Distance between original SIT address and previous shipment destination address'; +-- COMMENT on COLUMN shipment_address_updates.new_sit_distance_between IS 'Distance between original SIT address and new shipment destination address'; From 5104175d726646dac1d0083e60de1914eb34d9d8 Mon Sep 17 00:00:00 2001 From: Michael Inthavongsay Date: Wed, 28 Feb 2024 20:09:14 +0000 Subject: [PATCH 05/18] part 3 temp change to resolve db migration for exp deployment. must undo before merging to main --- ...hipment_address_update_table_sit_and_distance_columns.up.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql b/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql index e5e40181205..3a2a2bd9b24 100644 --- a/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql +++ b/migrations/app/schema/20240206173201_update_shipment_address_update_table_sit_and_distance_columns.up.sql @@ -16,3 +16,5 @@ ADD COLUMN IF NOT EXISTS new_sit_distance_between INTEGER DEFAULT NULL; -- COMMENT on COLUMN shipment_address_updates.sit_original_address_id IS 'SIT address at the original time of SIT approval'; -- COMMENT on COLUMN shipment_address_updates.old_sit_distance_between IS 'Distance between original SIT address and previous shipment destination address'; -- COMMENT on COLUMN shipment_address_updates.new_sit_distance_between IS 'Distance between original SIT address and new shipment destination address'; + +--SOME COMMENT From 85ea6d0028bbbf752284bf0844144ef8706c00dc Mon Sep 17 00:00:00 2001 From: Cameron <136814362+cameroncaci@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:58:59 -0500 Subject: [PATCH 06/18] Create main-to-integration-sync.yml --- .../workflows/main-to-integration-sync.yml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/main-to-integration-sync.yml diff --git a/.github/workflows/main-to-integration-sync.yml b/.github/workflows/main-to-integration-sync.yml new file mode 100644 index 00000000000..54d4ab94559 --- /dev/null +++ b/.github/workflows/main-to-integration-sync.yml @@ -0,0 +1,25 @@ +name: Integration Testing Syncing + +on: + pull_request: + branches: main + types: closed +jobs: + merge-main-to-int-testing: + if: github.event.pull_request.merged == true + timeout-minutes: 2 + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set Git config + run: | + git config --local user.email "actions@github.com" + git config --local user.name "Github Actions" + - name: Merge main to integrationTesting + run: | + git fetch --unshallow + git checkout dev + git pull + git merge --no-ff master -m "Auto-merge main to integrationTesting" + git push From 7b066ff089380fb3dcc6e13d9801eaeda97304b0 Mon Sep 17 00:00:00 2001 From: Michael Inthavongsay Date: Wed, 6 Mar 2024 20:59:31 +0000 Subject: [PATCH 07/18] create new shared component for download link. changed from link to button. --- .../DefinitionLists/PPMShipmentInfoList.jsx | 22 +-- .../PPMShipmentInfoList.test.jsx | 8 -- src/pages/MyMove/Home/index.jsx | 26 ++-- src/pages/MyMove/Home/index.test.jsx | 8 -- .../AsyncPacketDownloadLink.jsx | 78 +++++++++++ .../AsyncPacketDownloadLink.module.scss | 18 +++ .../AsyncPacketDownloadLink.test.jsx | 131 ++++++++++++++++++ src/utils/download.js | 34 ----- src/utils/download.test.js | 71 ---------- 9 files changed, 242 insertions(+), 154 deletions(-) create mode 100644 src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.jsx create mode 100644 src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.module.scss create mode 100644 src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.test.jsx delete mode 100644 src/utils/download.js delete mode 100644 src/utils/download.test.js diff --git a/src/components/Office/DefinitionLists/PPMShipmentInfoList.jsx b/src/components/Office/DefinitionLists/PPMShipmentInfoList.jsx index e9e7ad9b4eb..4acf5414716 100644 --- a/src/components/Office/DefinitionLists/PPMShipmentInfoList.jsx +++ b/src/components/Office/DefinitionLists/PPMShipmentInfoList.jsx @@ -1,12 +1,12 @@ import React from 'react'; import * as PropTypes from 'prop-types'; import classNames from 'classnames'; -import { Link } from 'react-router-dom'; import shipmentDefinitionListsStyles from './ShipmentDefinitionLists.module.scss'; import styles from 'styles/descriptionList.module.scss'; import { formatDate } from 'shared/dates'; +import AsyncPacketDownloadLink from 'shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink'; import { ShipmentShape } from 'types/shipment'; import { formatCentsTruncateWhole, formatWeight } from 'utils/formatters'; import { setFlagStyles, setDisplayFlags, getDisplayFlags, fieldValidationShape } from 'utils/displayFlags'; @@ -15,7 +15,6 @@ import affiliation from 'content/serviceMemberAgencies'; import { permissionTypes } from 'constants/permissions'; import Restricted from 'components/Restricted/Restricted'; import { downloadPPMAOAPacket } from 'services/ghcApi'; -import { downloadPPMAOAPacketOnSuccessHandler } from 'utils/download'; const PPMShipmentInfoList = ({ className, @@ -72,16 +71,6 @@ const PPMShipmentInfoList = ({ return (isExpanded || elementFlags.alwaysShow) && !elementFlags.hideRow; }; - const handlePPMAOAPacketDownloadClick = (shipmentId) => { - downloadPPMAOAPacket(shipmentId) - .then((response) => { - downloadPPMAOAPacketOnSuccessHandler(response); - }) - .catch(() => { - onErrorModalToggle(); - }); - }; - const expectedDepartureDateElementFlags = getDisplayFlags('expectedDepartureDate'); const expectedDepartureDateElement = (
@@ -201,9 +190,12 @@ const PPMShipmentInfoList = ({
AOA Packet

- handlePPMAOAPacketDownloadClick(shipment?.ppmShipment.id)}> - Download AOA Paperwork (PDF) - +

diff --git a/src/components/Office/DefinitionLists/PPMShipmentInfoList.test.jsx b/src/components/Office/DefinitionLists/PPMShipmentInfoList.test.jsx index 67c5c58bd49..86da49eb2ab 100644 --- a/src/components/Office/DefinitionLists/PPMShipmentInfoList.test.jsx +++ b/src/components/Office/DefinitionLists/PPMShipmentInfoList.test.jsx @@ -9,18 +9,12 @@ import { MockProviders } from 'testUtils'; import { permissionTypes } from 'constants/permissions'; import { ADVANCE_STATUSES } from 'constants/ppms'; import { downloadPPMAOAPacket } from 'services/ghcApi'; -import { downloadPPMAOAPacketOnSuccessHandler } from 'utils/download'; jest.mock('services/ghcApi', () => ({ ...jest.requireActual('services/ghcApi'), downloadPPMAOAPacket: jest.fn(), })); -jest.mock('utils/download', () => ({ - ...jest.requireActual('utils/download'), - downloadPPMAOAPacketOnSuccessHandler: jest.fn(), -})); - afterEach(() => { jest.resetAllMocks(); }); @@ -91,7 +85,6 @@ describe('PPMShipmentInfoList', () => { await waitFor(() => { expect(downloadPPMAOAPacket).toHaveBeenCalledTimes(1); - expect(downloadPPMAOAPacketOnSuccessHandler).toHaveBeenCalledTimes(1); }); }); @@ -117,7 +110,6 @@ describe('PPMShipmentInfoList', () => { await waitFor(() => { expect(downloadPPMAOAPacket).toHaveBeenCalledTimes(1); - expect(downloadPPMAOAPacketOnSuccessHandler).toHaveBeenCalledTimes(0); expect(onErrorHandler).toHaveBeenCalledTimes(1); }); }); diff --git a/src/pages/MyMove/Home/index.jsx b/src/pages/MyMove/Home/index.jsx index 04ced5e739d..1ffe8bdeb32 100644 --- a/src/pages/MyMove/Home/index.jsx +++ b/src/pages/MyMove/Home/index.jsx @@ -3,7 +3,7 @@ import { arrayOf, bool, func, node, shape, string } from 'prop-types'; import moment from 'moment'; import { connect } from 'react-redux'; import { Alert, Button } from '@trussworks/react-uswds'; -import { generatePath, Link } from 'react-router-dom'; +import { generatePath } from 'react-router-dom'; import styles from './Home.module.scss'; import { @@ -16,6 +16,7 @@ import { HelperPPMCloseoutSubmitted, } from './HomeHelpers'; +import AsyncPacketDownloadLink from 'shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink'; import ConnectedDestructiveShipmentConfirmationModal from 'components/ConfirmationModals/DestructiveShipmentConfirmationModal'; import Contact from 'components/Customer/Home/Contact'; import DocsUploaded from 'components/Customer/Home/DocsUploaded'; @@ -52,7 +53,6 @@ import { MoveShape, OrdersShape, UploadShape } from 'types/customerShapes'; import { ShipmentShape } from 'types/shipment'; import { formatCustomerDate, formatWeight } from 'utils/formatters'; import { isPPMAboutInfoComplete, isPPMShipmentComplete, isWeightTicketComplete } from 'utils/shipments'; -import { downloadPPMAOAPacketOnSuccessHandler } from 'utils/download'; import withRouter from 'utils/routing'; import { RouterShape } from 'types/router'; import { ADVANCE_STATUSES } from 'constants/ppms'; @@ -363,17 +363,6 @@ export class Home extends Component { })); }; - // eslint-disable-next-line class-methods-use-this - handlePPMAOAPacketDownloadClick = (shipmentId) => { - downloadPPMAOAPacket(shipmentId) - .then((response) => { - downloadPPMAOAPacketOnSuccessHandler(response); - }) - .catch(() => { - this.toggleDownloadAOAErrorModal(); - }); - }; - // eslint-disable-next-line class-methods-use-this sortAllShipments = (mtoShipments) => { const allShipments = JSON.parse(JSON.stringify(mtoShipments)); @@ -624,11 +613,12 @@ export class Home extends Component { {shipment?.ppmShipment?.advanceStatus === ADVANCE_STATUSES.APPROVED.apiValue && (

- this.handlePPMAOAPacketDownloadClick(shipment?.ppmShipment.id)} - > - Download AOA Paperwork (PDF) - +

)} {shipment?.ppmShipment?.advanceStatus === ADVANCE_STATUSES.REJECTED.apiValue && ( diff --git a/src/pages/MyMove/Home/index.test.jsx b/src/pages/MyMove/Home/index.test.jsx index 252c2ded61e..798b4cf7a02 100644 --- a/src/pages/MyMove/Home/index.test.jsx +++ b/src/pages/MyMove/Home/index.test.jsx @@ -24,7 +24,6 @@ import { createSubmittedPPMShipment, } from 'utils/test/factories/ppmShipment'; import { downloadPPMAOAPacket } from 'services/internalApi'; -import { downloadPPMAOAPacketOnSuccessHandler } from 'utils/download'; jest.mock('containers/FlashMessage/FlashMessage', () => { const MockFlash = () =>
Flash message
; @@ -43,11 +42,6 @@ jest.mock('services/internalApi', () => ({ downloadPPMAOAPacket: jest.fn(), })); -jest.mock('utils/download', () => ({ - ...jest.requireActual('utils/download'), - downloadPPMAOAPacketOnSuccessHandler: jest.fn(), -})); - const defaultProps = { serviceMember: { id: v4(), @@ -661,7 +655,6 @@ describe('Home component', () => { screen.getByText(/Something went wrong downloading PPM AOA paperwork./, { exact: false }), ).toBeInTheDocument(); expect(downloadPPMAOAPacket).toHaveBeenCalledTimes(1); - expect(downloadPPMAOAPacketOnSuccessHandler).toHaveBeenCalledTimes(0); }); }); @@ -694,7 +687,6 @@ describe('Home component', () => { await waitFor(() => { expect(downloadPPMAOAPacket).toHaveBeenCalledTimes(1); - expect(downloadPPMAOAPacketOnSuccessHandler).toHaveBeenCalledTimes(1); }); }); }); diff --git a/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.jsx b/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.jsx new file mode 100644 index 00000000000..9241d1db89f --- /dev/null +++ b/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.jsx @@ -0,0 +1,78 @@ +import React from 'react'; +import { Button } from '@trussworks/react-uswds'; +import PropTypes from 'prop-types'; + +import styles from './AsyncPacketDownloadLink.module.scss'; + +export const onPacketDownloadSuccessHandler = (response) => { + // dynamically update DOM to trigger browser to display SAVE AS download file modal + const contentType = response.headers['content-type']; + const url = window.URL.createObjectURL( + new Blob([response.data], { + type: contentType, + }), + ); + + const link = document.createElement('a'); + link.href = url; + const disposition = response.headers['content-disposition']; + const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/; + let strtime = new Date().toISOString(); + // we are expecting PDF + let filename = `packet-${strtime}.pdf`; + const matches = filenameRegex.exec(disposition); + if (matches != null && matches[1]) { + filename = matches[1].replace(/['"]/g, ''); + } + link.setAttribute('download', filename); + + document.body.appendChild(link); + + // Start download + link.click(); + + // Clean up and remove the link + link.parentNode.removeChild(link); +}; + +/** + * Shared component to render download links for AOA/Payment Packet packets. + * @param {string} id uuid to download + * @param {string} label link text + * @param {Promise} asyncRetrieval asynch document retrieval + * @param {func} onSucccess on success response handler + * @param {func} onFailure on failure response handler + */ +const AsyncPacketDownloadLink = ({ id, label, asyncRetrieval, onSucccess, onFailure }) => { + return ( + + ); +}; + +AsyncPacketDownloadLink.propTypes = { + id: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + asyncRetrieval: PropTypes.func.isRequired, + onSucccess: PropTypes.func.isRequired, + onFailure: PropTypes.func.isRequired, +}; + +AsyncPacketDownloadLink.defaultProps = { + onSucccess: onPacketDownloadSuccessHandler, + onFailure: () => {}, +}; + +export default AsyncPacketDownloadLink; diff --git a/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.module.scss b/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.module.scss new file mode 100644 index 00000000000..b2b2f8658d2 --- /dev/null +++ b/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.module.scss @@ -0,0 +1,18 @@ +@import 'shared/styles/colors.scss'; +@import 'shared/styles/basics'; + + +:global(.usa-button).downloadButtonToLink { + background-color: transparent; + color: $primary; + font-weight: normal; + margin: 0; + @include u-padding(0); + border-width: 0px; + outline: none !important; + height: 30px !important; +} + +:global(.usa-button).downloadButtonToLink:hover { + text-decoration: underline !important; +} diff --git a/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.test.jsx b/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.test.jsx new file mode 100644 index 00000000000..800c6e0f581 --- /dev/null +++ b/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.test.jsx @@ -0,0 +1,131 @@ +import React from 'react'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import AsyncPacketDownloadLink, { onPacketDownloadSuccessHandler } from './AsyncPacketDownloadLink'; + +afterEach(() => { + jest.resetAllMocks(); +}); + +describe('AsyncPacketDownloadLink success', () => { + it('success', async () => { + const asyncRetrieval = jest.fn().mockImplementation(() => Promise.resolve()); + const onSuccessHandler = jest.fn(); + const onErrorHandler = jest.fn(); + const expectedId = 'testID'; + const expectedLabel = 'test'; + render( + , + ); + expect(screen.getByText(expectedLabel, { exact: false })).toBeInTheDocument(); + + const downloadButton = screen.getByText(expectedLabel); + expect(downloadButton).toBeInTheDocument(); + await userEvent.click(downloadButton); + + await waitFor(() => { + expect(asyncRetrieval).toHaveBeenCalledTimes(1); + expect(onSuccessHandler).toHaveBeenCalledTimes(1); + expect(onErrorHandler).toHaveBeenCalledTimes(0); + }); + }); + + it('AsyncPacketDownloadLink failure', async () => { + const asyncRetrieval = jest.fn().mockImplementation(() => Promise.reject()); + const onSuccessHandler = jest.fn(); + const onErrorHandler = jest.fn(); + const expectedId = 'testID'; + const expectedLabel = 'test'; + render( + , + ); + expect(screen.getByText(expectedLabel, { exact: false })).toBeInTheDocument(); + + const downloadButton = screen.getByText(expectedLabel); + expect(downloadButton).toBeInTheDocument(); + await userEvent.click(downloadButton); + + await waitFor(() => { + expect(asyncRetrieval).toHaveBeenCalledTimes(1); + expect(asyncRetrieval).toHaveBeenCalledWith(expectedId); + expect(onSuccessHandler).toHaveBeenCalledTimes(0); + expect(onErrorHandler).toHaveBeenCalledTimes(1); + }); + }); + + it('success - downloadPacketOnSuccessHandler', () => { + const expectedResponseData = 'MOCK_PDF_DATA'; + const expectedFileName = 'test.pdf'; + const expectedContentType = 'application/pdf'; + + global.URL.createObjectURL = jest.fn(); + + const mockResponse = { + ok: true, + headers: { + 'content-disposition': `filename="${expectedFileName}"`, + 'content-type': expectedContentType, + }, + status: 200, + data: expectedResponseData, + }; + + function makeAnchor(target) { + /* eslint-disable no-param-reassign, no-return-assign */ + const setAttributeMock = jest.fn((key, value) => (target[key] = value)); + /* eslint-enable no-param-reassign, no-return-assign */ + return { + target, + setAttribute: setAttributeMock, + click: jest.fn(), + remove: jest.fn(), + parentNode: { + removeChild: jest.fn(), + }, + }; + } + + jest.spyOn(document.body, 'appendChild').mockReturnValue(null); + const anchor = makeAnchor({ href: '#', download: '' }); + jest.spyOn(document, 'createElement').mockReturnValue(anchor); + const clickSpy = jest.spyOn(anchor, 'click'); + + const mBlob = { size: 1024, type: 'application/pdf' }; + const blobSpy = jest.spyOn(global, 'Blob').mockImplementationOnce(() => mBlob); + + onPacketDownloadSuccessHandler(mockResponse); + + // verify response.data is used for blob + expect(blobSpy).toBeCalledWith([expectedResponseData], { + type: expectedContentType, + }); + + // verify hyperlink was created + expect(document.createElement).toBeCalledWith('a'); + + // verify download attribute is from content-disposition + expect(document.body.appendChild).toBeCalledWith( + expect.objectContaining({ + target: { download: expectedFileName, href: '#' }, + }), + ); + + // verify click event is invoked to download file + expect(clickSpy).toHaveBeenCalledTimes(1); + + // verify link is removed + expect(anchor.parentNode.removeChild).toBeCalledWith(anchor); + }); +}); diff --git a/src/utils/download.js b/src/utils/download.js deleted file mode 100644 index 7761288b5fc..00000000000 --- a/src/utils/download.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * On REST onsuccess handler for PPM AOA packet download. - * @param {httpResponse} response - */ -export const downloadPPMAOAPacketOnSuccessHandler = (response) => { - // dynamically update DOM to trigger browser to display SAVE AS download file modal - const contentType = response.headers['content-type']; - const url = window.URL.createObjectURL( - new Blob([response.data], { - type: contentType, - }), - ); - - const link = document.createElement('a'); - link.href = url; - const disposition = response.headers['content-disposition']; - const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/; - let filename = 'ppmAOAPacket.pdf'; - const matches = filenameRegex.exec(disposition); - if (matches != null && matches[1]) { - filename = matches[1].replace(/['"]/g, ''); - } - link.setAttribute('download', filename); - - document.body.appendChild(link); - - // Start download - link.click(); - - // Clean up and remove the link - link.parentNode.removeChild(link); -}; - -export default downloadPPMAOAPacketOnSuccessHandler; diff --git a/src/utils/download.test.js b/src/utils/download.test.js deleted file mode 100644 index a9f1a176744..00000000000 --- a/src/utils/download.test.js +++ /dev/null @@ -1,71 +0,0 @@ -import { downloadPPMAOAPacketOnSuccessHandler } from './download'; - -afterEach(() => { - jest.resetAllMocks(); -}); - -describe('downloadPPMAOAPacketOnSuccessHandler', () => { - it('success - downloadPPMAOAPacketOnSuccessHandler', () => { - const expectedResponseData = 'MOCK_PDF_DATA'; - const expectedFileName = 'test.pdf'; - const expectedContentType = 'application/pdf'; - - global.URL.createObjectURL = jest.fn(); - - const mockResponse = { - ok: true, - headers: { - 'content-disposition': `filename="${expectedFileName}"`, - 'content-type': expectedContentType, - }, - status: 200, - data: expectedResponseData, - }; - - function makeAnchor(target) { - /* eslint-disable no-param-reassign, no-return-assign */ - const setAttributeMock = jest.fn((key, value) => (target[key] = value)); - /* eslint-enable no-param-reassign, no-return-assign */ - return { - target, - setAttribute: setAttributeMock, - click: jest.fn(), - remove: jest.fn(), - parentNode: { - removeChild: jest.fn(), - }, - }; - } - - jest.spyOn(document.body, 'appendChild').mockReturnValue(null); - const anchor = makeAnchor({ href: '#', download: '' }); - jest.spyOn(document, 'createElement').mockReturnValue(anchor); - const clickSpy = jest.spyOn(anchor, 'click'); - - const mBlob = { size: 1024, type: 'application/pdf' }; - const blobSpy = jest.spyOn(global, 'Blob').mockImplementationOnce(() => mBlob); - - downloadPPMAOAPacketOnSuccessHandler(mockResponse); - - // verify response.data is used for blob - expect(blobSpy).toBeCalledWith([expectedResponseData], { - type: expectedContentType, - }); - - // verify hyperlink was created - expect(document.createElement).toBeCalledWith('a'); - - // verify download attribute is from content-disposition - expect(document.body.appendChild).toBeCalledWith( - expect.objectContaining({ - target: { download: expectedFileName, href: '#' }, - }), - ); - - // verify click event is invoked to download file - expect(clickSpy).toHaveBeenCalledTimes(1); - - // verify link is removed - expect(anchor.parentNode.removeChild).toBeCalledWith(anchor); - }); -}); From 1480da17074519285aacd8b4d828944976977ad8 Mon Sep 17 00:00:00 2001 From: Cameron <136814362+cameroncaci@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:03:22 -0500 Subject: [PATCH 08/18] Update main-to-integration-sync.yml --- .github/workflows/main-to-integration-sync.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main-to-integration-sync.yml b/.github/workflows/main-to-integration-sync.yml index 54d4ab94559..d539a75f94e 100644 --- a/.github/workflows/main-to-integration-sync.yml +++ b/.github/workflows/main-to-integration-sync.yml @@ -16,10 +16,10 @@ jobs: run: | git config --local user.email "actions@github.com" git config --local user.name "Github Actions" - - name: Merge main to integrationTesting + - name: Merge main to integrationTesting-Dummy run: | git fetch --unshallow - git checkout dev + git checkout integrationTesting-Dummy git pull - git merge --no-ff master -m "Auto-merge main to integrationTesting" + git merge --no-ff master -m "Auto-merge main to integrationTesting-Dummy" git push From bf8d38ddb05f4b3583c387f3beb9a66de95b5364 Mon Sep 17 00:00:00 2001 From: Michael Inthavongsay Date: Wed, 6 Mar 2024 21:23:13 +0000 Subject: [PATCH 09/18] merged main --- .../AsyncPacketDownloadLink/AsyncPacketDownloadLink.test.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.test.jsx b/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.test.jsx index 800c6e0f581..c9d04e210d1 100644 --- a/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.test.jsx +++ b/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.test.jsx @@ -83,9 +83,7 @@ describe('AsyncPacketDownloadLink success', () => { }; function makeAnchor(target) { - /* eslint-disable no-param-reassign, no-return-assign */ const setAttributeMock = jest.fn((key, value) => (target[key] = value)); - /* eslint-enable no-param-reassign, no-return-assign */ return { target, setAttribute: setAttributeMock, From 7c91c5aa76dbf696f296c78935c60d0e30ad9006 Mon Sep 17 00:00:00 2001 From: Michael Inthavongsay Date: Wed, 6 Mar 2024 21:27:11 +0000 Subject: [PATCH 10/18] restore config after exp --- .circleci/config.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 13c475c3642..6ce2a34eb25 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -40,30 +40,30 @@ references: # In addition, it's common practice to disable acceptance tests and # ignore tests for dp3 deploys. See the branch settings below. - dp3-branch: &dp3-branch B-18060-UI-Download-AOA-Packet-Customer + dp3-branch: &dp3-branch placeholder_branch_name # MUST BE ONE OF: loadtest, demo, exp. # These are used to pull in env vars so the spelling matters! - dp3-env: &dp3-env exp + dp3-env: &dp3-env placeholder_env # set integration-ignore-branch to the branch if you want to IGNORE # integration tests, or `placeholder_branch_name` if you do want to # run them - integration-ignore-branch: &integration-ignore-branch B-18060-UI-Download-AOA-Packet-Customer + integration-ignore-branch: &integration-ignore-branch placeholder_branch_name # set integration-mtls-ignore-branch to the branch if you want to # IGNORE mtls integration tests, or `placeholder_branch_name` if you # do want to run them - integration-mtls-ignore-branch: &integration-mtls-ignore-branch B-18060-UI-Download-AOA-Packet-Customer + integration-mtls-ignore-branch: &integration-mtls-ignore-branch placeholder_branch_name # set client-ignore-branch to the branch if you want to IGNORE # client tests, or `placeholder_branch_name` if you do want to run # them - client-ignore-branch: &client-ignore-branch B-18060-UI-Download-AOA-Packet-Customer + client-ignore-branch: &client-ignore-branch placeholder_branch_name # set server-ignore-branch to the branch if you want to IGNORE # server tests, or `placeholder_branch_name` if you do want to run # them - server-ignore-branch: &server-ignore-branch B-18060-UI-Download-AOA-Packet-Customer + server-ignore-branch: &server-ignore-branch placeholder_branch_name executors: base_small: From af2654439b4172bd6023139acd8900bb58fc7e83 Mon Sep 17 00:00:00 2001 From: Michael Inthavongsay Date: Wed, 6 Mar 2024 21:55:47 +0000 Subject: [PATCH 11/18] 18060 merge --- migrations/app/migrations_manifest.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/migrations/app/migrations_manifest.txt b/migrations/app/migrations_manifest.txt index 918a9d238fd..3418a931491 100644 --- a/migrations/app/migrations_manifest.txt +++ b/migrations/app/migrations_manifest.txt @@ -890,6 +890,7 @@ 20240103174317_add_customer_expense.up.sql 20240109200110_add_address_columns_to_ppmshipments4.up.sql 20240112205201_remove_ppm_estimated_weight.up.sql +20240119005610_add_authorized_end_date_to_mto_services_items.up.sql 20240124153121_remove_ppmid_from_signedcertification_table.up.sql 20240124155759_20240124-homesafeconnect-cert.up.sql 20240129153006_20240129-homesafeconnect-cert.up.sql @@ -903,9 +904,9 @@ 20240220145356_remove_rank_and_duty_location_columns_from_service_members_table.up.sql 20240222144140_redefine_order_audit_table_grade_col.up.sql 20240222154935_add_sit_delivery_miles_to_mto_service_items.up.sql +20240223144515_add_pro_gear_weights_to_mto_shipments.up.sql 20240223154843_us_post_region_city_trdm_table_creation.up.sql 20240223200739_updateDutyLocationsZip.up.sql -20240119005610_add_authorized_end_date_to_mto_services_items.up.sql 20240226183440_add_county_column_to_address_table.up.sql 20240227171439_usprc_data_dump_batch.up.sql 20240227180121_add_status_edipi_other_unique_id_and_rej_reason_to_office_users_table.up.sql From ba7bec61c8c1f7ecafa0d5476a008681c4170cd2 Mon Sep 17 00:00:00 2001 From: Alex Lusk Date: Fri, 8 Mar 2024 23:27:09 +0000 Subject: [PATCH 12/18] Added AsyncPacketDownloadLink component to MoveHome page for compatability with Multi-move --- src/pages/MyMove/Home/MoveHome.jsx | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/pages/MyMove/Home/MoveHome.jsx b/src/pages/MyMove/Home/MoveHome.jsx index cb24618d95a..f4e8614c1b7 100644 --- a/src/pages/MyMove/Home/MoveHome.jsx +++ b/src/pages/MyMove/Home/MoveHome.jsx @@ -16,6 +16,8 @@ import { HelperPPMCloseoutSubmitted, } from './HomeHelpers'; +import AsyncPacketDownloadLink from 'shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink'; +import DownloadAOAErrorModal from 'shared/DownloadAOAErrorModal/DownloadAOAErrorModal'; import ConnectedDestructiveShipmentConfirmationModal from 'components/ConfirmationModals/DestructiveShipmentConfirmationModal'; import Contact from 'components/Customer/Home/Contact'; import DocsUploaded from 'components/Customer/Home/DocsUploaded'; @@ -30,7 +32,7 @@ import MOVE_STATUSES from 'constants/moves'; import { customerRoutes } from 'constants/routes'; import { ppmShipmentStatuses, shipmentTypes } from 'constants/shipments'; import ConnectedFlashMessage from 'containers/FlashMessage/FlashMessage'; -import { deleteMTOShipment, getAllMoves, getMTOShipmentsForMove } from 'services/internalApi'; +import { deleteMTOShipment, getAllMoves, getMTOShipmentsForMove, downloadPPMAOAPacket } from 'services/internalApi'; import { withContext } from 'shared/AppContext'; import { SHIPMENT_OPTIONS } from 'shared/constants'; import { @@ -79,6 +81,7 @@ const MoveHome = ({ serviceMemberMoves, isProfileComplete, serviceMember, signed const [targetShipmentId, setTargetShipmentId] = useState(null); const [showDeleteSuccessAlert, setShowDeleteSuccessAlert] = useState(false); const [showDeleteErrorAlert, setShowDeleteErrorAlert] = useState(false); + const [showDownloadPPMAOAPaperworkErrorAlert, setShowDownloadPPMAOAPaperworkErrorAlert] = useState(false); // fetching all move data on load since this component is dependent on that data // this will run each time the component is loaded/accessed @@ -366,6 +369,10 @@ const MoveHome = ({ serviceMemberMoves, isProfileComplete, serviceMember, signed ); }; + const toggleDownloadAOAErrorModal = () => { + setShowDownloadPPMAOAPaperworkErrorAlert(!showDownloadPPMAOAPaperworkErrorAlert); + }; + // early return if loading user/service member if (!serviceMember) { return ( @@ -410,6 +417,7 @@ const MoveHome = ({ serviceMemberMoves, isProfileComplete, serviceMember, signed submitText="Yes, Delete" closeText="No, Keep It" /> +
@@ -585,9 +593,12 @@ const MoveHome = ({ serviceMemberMoves, isProfileComplete, serviceMember, signed {shipment?.ppmShipment?.advanceStatus === ADVANCE_STATUSES.APPROVED.apiValue && ( // TODO: B-18060 will add link to method that will create the AOA packet and return for download

- - Download AOA Paperwork (PDF) - +

)} {shipment?.ppmShipment?.advanceStatus === ADVANCE_STATUSES.REJECTED.apiValue && ( From 0791b93d1ad70b01e148546720245f5e3bfd0973 Mon Sep 17 00:00:00 2001 From: Dre Jones <136509766+deandreJones@users.noreply.github.com> Date: Mon, 11 Mar 2024 08:51:51 -0500 Subject: [PATCH 13/18] Update main-to-integration-sync.yml fix whitespace --- .github/workflows/main-to-integration-sync.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main-to-integration-sync.yml b/.github/workflows/main-to-integration-sync.yml index d539a75f94e..5108529a524 100644 --- a/.github/workflows/main-to-integration-sync.yml +++ b/.github/workflows/main-to-integration-sync.yml @@ -15,7 +15,7 @@ jobs: - name: Set Git config run: | git config --local user.email "actions@github.com" - git config --local user.name "Github Actions" + git config --local user.name "Github Actions" - name: Merge main to integrationTesting-Dummy run: | git fetch --unshallow From c5c361ac2859bb81a59195bfcc4575eecc39bf8a Mon Sep 17 00:00:00 2001 From: Alex Lusk Date: Mon, 11 Mar 2024 19:58:18 +0000 Subject: [PATCH 14/18] Began tests for AOA download on MoveHome.jsx --- src/pages/MyMove/Home/MoveHome.test.jsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/pages/MyMove/Home/MoveHome.test.jsx b/src/pages/MyMove/Home/MoveHome.test.jsx index 67fdb864546..e70c45f79fe 100644 --- a/src/pages/MyMove/Home/MoveHome.test.jsx +++ b/src/pages/MyMove/Home/MoveHome.test.jsx @@ -31,6 +31,11 @@ jest.mock('services/internalApi', () => ({ getAllMoves: jest.fn().mockImplementation(() => Promise.resolve()), })); +jest.mock('services/internalApi', () => ({ + ...jest.requireActual('services/internalApi'), + downloadPPMAOAPacket: jest.fn(), +})); + const props = { serviceMember: { id: v4(), @@ -1248,5 +1253,9 @@ describe('Home component', () => { expect(confirmMoveRequest.prop('actionBtnDisabled')).toBeFalsy(); expect(confirmMoveRequest.prop('actionBtnLabel')).toBe('Review your request'); }); + + it('renders download AOA paperwork', () => { + expect(wrapper.text().toContain('Download AOA Paperwork (PDF)')); + }); }); }); From 4995571d4d97871b2133c658166c64897040644e Mon Sep 17 00:00:00 2001 From: Alex Lusk Date: Mon, 11 Mar 2024 19:50:03 -0400 Subject: [PATCH 15/18] Revert "Began tests for AOA download on MoveHome.jsx" This reverts commit c5c361ac2859bb81a59195bfcc4575eecc39bf8a. --- src/pages/MyMove/Home/MoveHome.test.jsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/pages/MyMove/Home/MoveHome.test.jsx b/src/pages/MyMove/Home/MoveHome.test.jsx index e70c45f79fe..67fdb864546 100644 --- a/src/pages/MyMove/Home/MoveHome.test.jsx +++ b/src/pages/MyMove/Home/MoveHome.test.jsx @@ -31,11 +31,6 @@ jest.mock('services/internalApi', () => ({ getAllMoves: jest.fn().mockImplementation(() => Promise.resolve()), })); -jest.mock('services/internalApi', () => ({ - ...jest.requireActual('services/internalApi'), - downloadPPMAOAPacket: jest.fn(), -})); - const props = { serviceMember: { id: v4(), @@ -1253,9 +1248,5 @@ describe('Home component', () => { expect(confirmMoveRequest.prop('actionBtnDisabled')).toBeFalsy(); expect(confirmMoveRequest.prop('actionBtnLabel')).toBe('Review your request'); }); - - it('renders download AOA paperwork', () => { - expect(wrapper.text().toContain('Download AOA Paperwork (PDF)')); - }); }); }); From 878edbb467e4680a45f2abc614d6f42be819753c Mon Sep 17 00:00:00 2001 From: Alex Lusk Date: Mon, 11 Mar 2024 19:50:33 -0400 Subject: [PATCH 16/18] Revert "Added AsyncPacketDownloadLink component to MoveHome page for compatability with Multi-move" This reverts commit ba7bec61c8c1f7ecafa0d5476a008681c4170cd2. --- src/pages/MyMove/Home/MoveHome.jsx | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/pages/MyMove/Home/MoveHome.jsx b/src/pages/MyMove/Home/MoveHome.jsx index f4e8614c1b7..cb24618d95a 100644 --- a/src/pages/MyMove/Home/MoveHome.jsx +++ b/src/pages/MyMove/Home/MoveHome.jsx @@ -16,8 +16,6 @@ import { HelperPPMCloseoutSubmitted, } from './HomeHelpers'; -import AsyncPacketDownloadLink from 'shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink'; -import DownloadAOAErrorModal from 'shared/DownloadAOAErrorModal/DownloadAOAErrorModal'; import ConnectedDestructiveShipmentConfirmationModal from 'components/ConfirmationModals/DestructiveShipmentConfirmationModal'; import Contact from 'components/Customer/Home/Contact'; import DocsUploaded from 'components/Customer/Home/DocsUploaded'; @@ -32,7 +30,7 @@ import MOVE_STATUSES from 'constants/moves'; import { customerRoutes } from 'constants/routes'; import { ppmShipmentStatuses, shipmentTypes } from 'constants/shipments'; import ConnectedFlashMessage from 'containers/FlashMessage/FlashMessage'; -import { deleteMTOShipment, getAllMoves, getMTOShipmentsForMove, downloadPPMAOAPacket } from 'services/internalApi'; +import { deleteMTOShipment, getAllMoves, getMTOShipmentsForMove } from 'services/internalApi'; import { withContext } from 'shared/AppContext'; import { SHIPMENT_OPTIONS } from 'shared/constants'; import { @@ -81,7 +79,6 @@ const MoveHome = ({ serviceMemberMoves, isProfileComplete, serviceMember, signed const [targetShipmentId, setTargetShipmentId] = useState(null); const [showDeleteSuccessAlert, setShowDeleteSuccessAlert] = useState(false); const [showDeleteErrorAlert, setShowDeleteErrorAlert] = useState(false); - const [showDownloadPPMAOAPaperworkErrorAlert, setShowDownloadPPMAOAPaperworkErrorAlert] = useState(false); // fetching all move data on load since this component is dependent on that data // this will run each time the component is loaded/accessed @@ -369,10 +366,6 @@ const MoveHome = ({ serviceMemberMoves, isProfileComplete, serviceMember, signed ); }; - const toggleDownloadAOAErrorModal = () => { - setShowDownloadPPMAOAPaperworkErrorAlert(!showDownloadPPMAOAPaperworkErrorAlert); - }; - // early return if loading user/service member if (!serviceMember) { return ( @@ -417,7 +410,6 @@ const MoveHome = ({ serviceMemberMoves, isProfileComplete, serviceMember, signed submitText="Yes, Delete" closeText="No, Keep It" /> -
@@ -593,12 +585,9 @@ const MoveHome = ({ serviceMemberMoves, isProfileComplete, serviceMember, signed {shipment?.ppmShipment?.advanceStatus === ADVANCE_STATUSES.APPROVED.apiValue && ( // TODO: B-18060 will add link to method that will create the AOA packet and return for download

- + + Download AOA Paperwork (PDF) +

)} {shipment?.ppmShipment?.advanceStatus === ADVANCE_STATUSES.REJECTED.apiValue && ( From 555b4152f01d4bacd92d2c28159d43923ab69584 Mon Sep 17 00:00:00 2001 From: Michael Inthavongsay Date: Tue, 12 Mar 2024 00:13:55 +0000 Subject: [PATCH 17/18] Implement new HomePage for MultiMove to use new download component --- src/pages/MyMove/Home/MoveHome.jsx | 19 +++++++-- src/pages/MyMove/Home/MoveHome.test.jsx | 39 ++++++++++++++++++- .../AsyncPacketDownloadLink.jsx | 2 + 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/pages/MyMove/Home/MoveHome.jsx b/src/pages/MyMove/Home/MoveHome.jsx index 98b54006903..642640f0fa5 100644 --- a/src/pages/MyMove/Home/MoveHome.jsx +++ b/src/pages/MyMove/Home/MoveHome.jsx @@ -16,6 +16,8 @@ import { HelperPPMCloseoutSubmitted, } from './HomeHelpers'; +import AsyncPacketDownloadLink from 'shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink'; +import DownloadAOAErrorModal from 'shared/DownloadAOAErrorModal/DownloadAOAErrorModal'; import ConnectedDestructiveShipmentConfirmationModal from 'components/ConfirmationModals/DestructiveShipmentConfirmationModal'; import Contact from 'components/Customer/Home/Contact'; import DocsUploaded from 'components/Customer/Home/DocsUploaded'; @@ -30,7 +32,7 @@ import MOVE_STATUSES from 'constants/moves'; import { customerRoutes } from 'constants/routes'; import { ppmShipmentStatuses, shipmentTypes } from 'constants/shipments'; import ConnectedFlashMessage from 'containers/FlashMessage/FlashMessage'; -import { deleteMTOShipment, getAllMoves, getMTOShipmentsForMove } from 'services/internalApi'; +import { deleteMTOShipment, getAllMoves, getMTOShipmentsForMove, downloadPPMAOAPacket } from 'services/internalApi'; import { withContext } from 'shared/AppContext'; import { SHIPMENT_OPTIONS } from 'shared/constants'; import { @@ -79,6 +81,7 @@ const MoveHome = ({ serviceMemberMoves, isProfileComplete, serviceMember, signed const [targetShipmentId, setTargetShipmentId] = useState(null); const [showDeleteSuccessAlert, setShowDeleteSuccessAlert] = useState(false); const [showDeleteErrorAlert, setShowDeleteErrorAlert] = useState(false); + const [showDownloadPPMAOAPaperworkErrorAlert, setShowDownloadPPMAOAPaperworkErrorAlert] = useState(false); // fetching all move data on load since this component is dependent on that data // this will run each time the component is loaded/accessed @@ -363,6 +366,10 @@ const MoveHome = ({ serviceMemberMoves, isProfileComplete, serviceMember, signed ); }; + const toggleDownloadAOAErrorModal = () => { + setShowDownloadPPMAOAPaperworkErrorAlert(!showDownloadPPMAOAPaperworkErrorAlert); + }; + // early return if loading user/service member if (!serviceMember) { return ( @@ -407,6 +414,7 @@ const MoveHome = ({ serviceMemberMoves, isProfileComplete, serviceMember, signed submitText="Yes, Delete" closeText="No, Keep It" /> +
@@ -582,9 +590,12 @@ const MoveHome = ({ serviceMemberMoves, isProfileComplete, serviceMember, signed {shipment?.ppmShipment?.advanceStatus === ADVANCE_STATUSES.APPROVED.apiValue && ( // TODO: B-18060 will add link to method that will create the AOA packet and return for download

- - Download AOA Paperwork (PDF) - +

)} {shipment?.ppmShipment?.advanceStatus === ADVANCE_STATUSES.REJECTED.apiValue && ( diff --git a/src/pages/MyMove/Home/MoveHome.test.jsx b/src/pages/MyMove/Home/MoveHome.test.jsx index 67fdb864546..26150190344 100644 --- a/src/pages/MyMove/Home/MoveHome.test.jsx +++ b/src/pages/MyMove/Home/MoveHome.test.jsx @@ -2,11 +2,13 @@ import React from 'react'; import { v4 } from 'uuid'; import { mount } from 'enzyme'; +import { waitFor } from '@testing-library/react'; import MoveHome from './MoveHome'; import { customerRoutes } from 'constants/routes'; import { MockProviders } from 'testUtils'; +import { downloadPPMAOAPacket } from 'services/internalApi'; jest.mock('containers/FlashMessage/FlashMessage', () => { const MockFlash = () =>
Flash message
; @@ -29,6 +31,7 @@ jest.mock('services/internalApi', () => ({ deleteMTOShipment: jest.fn(), getMTOShipmentsForMove: jest.fn(), getAllMoves: jest.fn().mockImplementation(() => Promise.resolve()), + downloadPPMAOAPacket: jest.fn().mockImplementation(() => Promise.resolve()), })); const props = { @@ -794,6 +797,8 @@ const defaultPropsAmendedOrdersWithAdvanceRequested = { uploadedAmendedOrderDocuments: [], }; +const expectedPpmShipmentID = 'd18b865f-fd12-495d-91fa-65b53d72705a'; + const defaultPropsWithAdvanceAndPPMApproved = { ...props, serviceMemberMoves: { @@ -829,7 +834,7 @@ const defaultPropsWithAdvanceAndPPMApproved = { hasProGear: false, hasReceivedAdvance: null, hasRequestedAdvance: true, - id: 'd18b865f-fd12-495d-91fa-65b53d72705a', + id: expectedPpmShipmentID, movingExpenses: [], pickupPostalCode: '74133', proGearWeight: null, @@ -1248,5 +1253,37 @@ describe('Home component', () => { expect(confirmMoveRequest.prop('actionBtnDisabled')).toBeFalsy(); expect(confirmMoveRequest.prop('actionBtnLabel')).toBe('Review your request'); }); + + it('Download AOA Paperwork - success', async () => { + const buttonId = `button[data-testid="asyncPacketDownloadLink${expectedPpmShipmentID}"]`; + expect(wrapper.find(buttonId).length).toBe(1); + const mockResponse = { + ok: true, + headers: { + 'content-disposition': 'filename="test.pdf"', + }, + status: 200, + data: null, + }; + downloadPPMAOAPacket.mockImplementation(() => Promise.resolve(mockResponse)); + await wrapper.find(buttonId).simulate('click'); + await waitFor(() => { + expect(downloadPPMAOAPacket).toHaveBeenCalledTimes(1); + }); + }); + + it('Download AOA Paperwork - failure', async () => { + const buttonId = `button[data-testid="asyncPacketDownloadLink${expectedPpmShipmentID}"]`; + expect(wrapper.find(buttonId).length).toBe(1); + downloadPPMAOAPacket.mockRejectedValue({ + response: { body: { title: 'Error title', detail: 'Error detail' } }, + }); + await wrapper.find(buttonId).simulate('click'); + await waitFor(() => { + // scrape text from error modal + expect(wrapper.text()).toContain('Something went wrong downloading PPM AOA paperwork'); + expect(downloadPPMAOAPacket).toHaveBeenCalledTimes(1); + }); + }); }); }); diff --git a/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.jsx b/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.jsx index 9241d1db89f..61d9e6f34c2 100644 --- a/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.jsx +++ b/src/shared/AsyncPacketDownloadLink/AsyncPacketDownloadLink.jsx @@ -44,8 +44,10 @@ export const onPacketDownloadSuccessHandler = (response) => { * @param {func} onFailure on failure response handler */ const AsyncPacketDownloadLink = ({ id, label, asyncRetrieval, onSucccess, onFailure }) => { + const dataTestId = `asyncPacketDownloadLink${id}`; return (