From 0a3f59d789fd5c476bdd267a48b43608e5c2fe63 Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 19:07:38 +0000 Subject: [PATCH 01/15] shipment card, container, mtoshipmentform updates --- .../Customer/Home/Step/Step.stories.jsx | 1 + .../MtoShipmentForm/MtoShipmentForm.jsx | 19 +- .../MtoShipmentForm.stories.jsx | 7 + .../MtoShipmentForm/MtoShipmentForm.test.jsx | 953 ++++++++++++++++++ .../MtoShipmentForm/getShipmentOptions.js | 7 + .../Customer/Review/Summary/Summary.jsx | 31 + .../Customer/Review/Summary/Summary.test.jsx | 2 + .../ShipmentContainer/ShipmentContainer.jsx | 1 + .../ShipmentContainer.test.jsx | 1 + src/components/ShipmentList/ShipmentList.jsx | 1 + .../ShipmentList/ShipmentList.module.scss | 4 + .../ShipmentList/ShipmentList.test.jsx | 8 +- src/constants/shipments.js | 3 + src/content/shipments.js | 1 + src/shared/constants.js | 5 + src/shared/styles/colors.scss | 2 +- 16 files changed, 1039 insertions(+), 7 deletions(-) diff --git a/src/components/Customer/Home/Step/Step.stories.jsx b/src/components/Customer/Home/Step/Step.stories.jsx index 0e807fa0527..c323c98ff9d 100644 --- a/src/components/Customer/Home/Step/Step.stories.jsx +++ b/src/components/Customer/Home/Step/Step.stories.jsx @@ -119,6 +119,7 @@ Shipments.args = { weightTickets: [], }, }, + { id: '0004', shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE }, ]} onShipmentClick={action('shipment edit icon clicked')} moveSubmitted={false} diff --git a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.jsx b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.jsx index efb155918d2..6db5c0db84c 100644 --- a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.jsx +++ b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.jsx @@ -190,8 +190,9 @@ class MtoShipmentForm extends Component { const isNTSR = shipmentType === SHIPMENT_OPTIONS.NTSR; const isBoat = shipmentType === SHIPMENT_TYPES.BOAT_HAUL_AWAY || shipmentType === SHIPMENT_TYPES.BOAT_TOW_AWAY; const isMobileHome = shipmentType === SHIPMENT_TYPES.MOBILE_HOME; + const isUB = shipmentType === SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE; const shipmentNumber = - shipmentType === SHIPMENT_OPTIONS.HHG || isBoat || isMobileHome ? this.getShipmentNumber() : null; + shipmentType === SHIPMENT_OPTIONS.HHG || isBoat || isMobileHome || isUB ? this.getShipmentNumber() : null; const isRetireeSeparatee = orders.orders_type === ORDERS_TYPE.RETIREMENT || orders.orders_type === ORDERS_TYPE.SEPARATION; @@ -314,10 +315,18 @@ class MtoShipmentForm extends Component {

{shipmentForm.header[`${shipmentType}`]}

- - Remember: You can move {formatWeight(orders.authorizedWeight)} total. You’ll be billed for any - excess weight you move. - + {!isUB && ( + + Remember: You can move {formatWeight(orders.authorizedWeight)} total. You’ll be billed for any + excess weight you move. + + )} + {isUB && ( + + Remember: You can move up to your UB allowance for this move. You’ll be billed for any excess + weight you move. + + )}
{showPickupFields && ( diff --git a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.stories.jsx b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.stories.jsx index a3f5994a02f..173604f1ceb 100644 --- a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.stories.jsx +++ b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.stories.jsx @@ -95,6 +95,7 @@ export const HHGShipmentRetiree = () => renderStory({ shipmentType: SHIPMENT_OPTIONS.HHG, orders: { orders_type: 'RETIREMENT', authorizedWeight: 5000 } }); export const NTSReleaseShipment = () => renderStory({ shipmentType: SHIPMENT_OPTIONS.NTSR }); export const NTSShipment = () => renderStory({ shipmentType: SHIPMENT_OPTIONS.NTS }); +export const UBShipment = () => renderStory({ shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE }); // edit shipment stories (form should prefill) export const EditHHGShipment = () => @@ -115,6 +116,12 @@ export const EditNTSShipment = () => isCreatePage: false, mtoShipment: mockMtoShipment, }); +export const EditUBShipment = () => + renderStory({ + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + isCreatePage: false, + mtoShipment: mockMtoShipment, + }); export const EditShipmentAsSeparatee = () => renderStory({ diff --git a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.test.jsx b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.test.jsx index 1cf62db6834..3d6391e5c0c 100644 --- a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.test.jsx +++ b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.test.jsx @@ -68,6 +68,33 @@ const defaultProps = { shipmentType: SHIPMENT_OPTIONS.HHG, }; +const ubProps = { + isCreatePage: true, + pageList: ['page1', 'anotherPage/:foo/:bar'], + pageKey: 'page1', + showLoggedInUser: jest.fn(), + createMTOShipment: jest.fn(), + updateMTOShipment: jest.fn(), + dateSelectionIsWeekendHoliday: jest.fn().mockImplementation(() => Promise.resolve()), + newDutyLocationAddress: { + city: 'Fort Benning', + state: 'GA', + postalCode: '31905', + }, + currentResidence: { + city: 'Fort Benning', + state: 'GA', + postalCode: '31905', + streetAddress1: '123 Main', + streetAddress2: '', + }, + orders: { + orders_type: 'PERMANENT_CHANGE_OF_STATION', + has_dependents: false, + }, + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, +}; + const reviewPath = generatePath(customerRoutes.MOVE_REVIEW_PATH, { moveId }); beforeEach(() => { @@ -85,6 +112,13 @@ const renderMtoShipmentForm = (props) => { }); }; +const renderUBShipmentForm = (props) => { + return renderWithRouter(, { + path: customerRoutes.SHIPMENT_CREATE_PATH, + params: { moveId }, + }); +}; + describe('MtoShipmentForm component', () => { describe('when creating a new HHG shipment', () => { it('renders the HHG shipment form', async () => { @@ -1012,6 +1046,925 @@ describe('MtoShipmentForm component', () => { }); }); + describe('when creating a new UB shipment', () => { + it('renders the UB shipment form', async () => { + renderUBShipmentForm(); + + expect(await screen.findByText('UB')).toHaveClass('usa-tag'); + + expect(screen.getAllByText('Date')[0]).toBeInstanceOf(HTMLLegendElement); + expect(screen.getByLabelText(/Preferred pickup date/)).toBeInstanceOf(HTMLInputElement); + expect(screen.getByRole('heading', { level: 2, name: 'Pickup info' })).toBeInTheDocument(); + expect(screen.getByTestId('pickupDateHint')).toHaveTextContent( + 'This is the day movers would put this shipment on their truck. Packing starts earlier. Dates will be finalized when you talk to your Customer Care Representative. Your requested pickup/load date should be your latest preferred pickup/load date, or the date you need to be out of your origin residence.', + ); + expect(screen.getByText('Pickup location')).toBeInstanceOf(HTMLLegendElement); + expect(screen.getByLabelText('Use my current address')).toBeInstanceOf(HTMLInputElement); + expect(screen.getByLabelText(/Address 1/)).toBeInstanceOf(HTMLInputElement); + expect(screen.getByLabelText(/Address 2/)).toBeInstanceOf(HTMLInputElement); + expect(screen.getByLabelText(/City/)).toBeInstanceOf(HTMLInputElement); + expect(screen.getByLabelText(/State/)).toBeInstanceOf(HTMLSelectElement); + expect(screen.getByLabelText(/ZIP/)).toBeInstanceOf(HTMLInputElement); + + expect(screen.getByRole('heading', { level: 4, name: 'Second pickup location' })).toBeInTheDocument(); + expect(screen.getByTitle('Yes, I have a second pickup location')).toBeInstanceOf(HTMLInputElement); + expect(screen.getByTitle('No, I do not have a second pickup location')).toBeInstanceOf(HTMLInputElement); + + expect(screen.getByText(/Releasing agent/).parentElement).toBeInstanceOf(HTMLLegendElement); + expect(screen.getAllByLabelText(/First name/)[0]).toHaveAttribute('name', 'pickup.agent.firstName'); + expect(screen.getAllByLabelText(/Last name/)[0]).toHaveAttribute('name', 'pickup.agent.lastName'); + expect(screen.getAllByLabelText(/Phone/)[0]).toHaveAttribute('name', 'pickup.agent.phone'); + expect(screen.getAllByLabelText(/Email/)[0]).toHaveAttribute('name', 'pickup.agent.email'); + + expect(screen.getAllByText('Date')[1]).toBeInstanceOf(HTMLLegendElement); + expect(screen.getByLabelText(/Preferred delivery date/)).toBeInstanceOf(HTMLInputElement); + + expect(screen.getByText(/Delivery location/)).toBeInstanceOf(HTMLLegendElement); + expect(screen.getByTitle('Yes, I know my delivery address')).toBeInstanceOf(HTMLInputElement); + expect(screen.getByTitle('No, I do not know my delivery address')).toBeInstanceOf(HTMLInputElement); + + expect(screen.queryByRole('heading', { level: 4, name: 'Second Destination Location' })).not.toBeInTheDocument(); + expect(screen.queryByTitle('Yes, I have a second destination location')).not.toBeInTheDocument(); + expect(screen.queryByTitle('No, I do not have a second destination location')).not.toBeInTheDocument(); + + expect(screen.getByText(/Receiving agent/).parentElement).toBeInstanceOf(HTMLLegendElement); + expect(screen.getAllByLabelText(/First name/)[1]).toHaveAttribute('name', 'delivery.agent.firstName'); + expect(screen.getAllByLabelText(/Last name/)[1]).toHaveAttribute('name', 'delivery.agent.lastName'); + expect(screen.getAllByLabelText(/Phone/)[1]).toHaveAttribute('name', 'delivery.agent.phone'); + expect(screen.getAllByLabelText(/Email/)[1]).toHaveAttribute('name', 'delivery.agent.email'); + + expect( + screen.queryByText( + 'Details about the facility where your things are now, including the name or address (if you know them)', + ), + ).not.toBeInTheDocument(); + + expect( + screen.getByLabelText( + 'Are there things about this shipment that your counselor or movers should discuss with you?', + ), + ).toBeInstanceOf(HTMLTextAreaElement); + }); + + it('renders the correct helper text for Delivery Location when orders type is RETIREMENT', async () => { + renderUBShipmentForm({ orders: { orders_type: ORDERS_TYPE.RETIREMENT } }); + await waitFor(() => + expect( + screen.getByText('We can use the zip of the HOR, PLEAD or HOS you entered with your orders.') + .toBeInTheDocument, + ), + ); + }); + + it('renders the correct helper text for Delivery Location when orders type is SEPARATION', async () => { + renderUBShipmentForm({ orders: { orders_type: ORDERS_TYPE.SEPARATION } }); + await waitFor(() => + expect( + screen.getByText('We can use the zip of the HOR, PLEAD or HOS you entered with your orders.') + .toBeInTheDocument, + ), + ); + }); + + it('renders the correct helper text for Delivery Location when orders type is PERMANENT_CHANGE_OF_STATION', async () => { + renderUBShipmentForm({ orders: { orders_type: ORDERS_TYPE.PERMANENT_CHANGE_OF_STATION } }); + await waitFor(() => expect(screen.getByText(/We can use the zip of your new duty location./).toBeInTheDocument)); + }); + + it('renders the correct helper text for Delivery Location when orders type is LOCAL_MOVE', async () => { + renderUBShipmentForm({ orders: { orders_type: ORDERS_TYPE.LOCAL_MOVE } }); + await waitFor(() => expect(screen.getByText(/We can use the zip of your new duty location./).toBeInTheDocument)); + }); + + it('does not render special NTS What to expect section', async () => { + const { queryByTestId } = renderUBShipmentForm(); + + await waitFor(() => { + expect(queryByTestId('nts-what-to-expect')).not.toBeInTheDocument(); + }); + }); + + it('uses the current residence address for pickup address when checked', async () => { + const { queryByLabelText, queryAllByLabelText } = renderUBShipmentForm(); + + await userEvent.click(queryByLabelText('Use my current address')); + + await waitFor(() => { + expect(queryAllByLabelText(/Address 1/)[0]).toHaveValue(defaultProps.currentResidence.streetAddress1); + expect(queryAllByLabelText(/Address 2/)[0]).toHaveValue(''); + expect(queryAllByLabelText(/City/)[0]).toHaveValue(defaultProps.currentResidence.city); + expect(queryAllByLabelText(/State/)[0]).toHaveValue(defaultProps.currentResidence.state); + expect(queryAllByLabelText(/ZIP/)[0]).toHaveValue(defaultProps.currentResidence.postalCode); + }); + }); + + it('renders a second address fieldset when the user has a second pickup address', async () => { + renderUBShipmentForm(); + + await userEvent.click(screen.getByTitle('Yes, I have a second pickup location')); + + const streetAddress1 = await screen.findAllByLabelText(/Address 1/); + expect(streetAddress1[1]).toHaveAttribute('name', 'secondaryPickup.address.streetAddress1'); + + const streetAddress2 = await screen.findAllByLabelText(/Address 2/); + expect(streetAddress2[1]).toHaveAttribute('name', 'secondaryPickup.address.streetAddress2'); + + const city = await screen.findAllByLabelText(/City/); + expect(city[1]).toHaveAttribute('name', 'secondaryPickup.address.city'); + + const state = await screen.findAllByLabelText(/State/); + expect(state[1]).toHaveAttribute('name', 'secondaryPickup.address.state'); + + const zip = await screen.findAllByLabelText(/ZIP/); + expect(zip[1]).toHaveAttribute('name', 'secondaryPickup.address.postalCode'); + }); + + it('renders a second address fieldset when the user has a delivery address', async () => { + renderUBShipmentForm(); + + await userEvent.click(screen.getByTitle('Yes, I know my delivery address')); + + const streetAddress1 = await screen.findAllByLabelText(/Address 1/); + expect(streetAddress1[0]).toHaveAttribute('name', 'pickup.address.streetAddress1'); + expect(streetAddress1[1]).toHaveAttribute('name', 'delivery.address.streetAddress1'); + + const streetAddress2 = await screen.findAllByLabelText(/Address 2/); + expect(streetAddress2[0]).toHaveAttribute('name', 'pickup.address.streetAddress2'); + expect(streetAddress2[1]).toHaveAttribute('name', 'delivery.address.streetAddress2'); + + const city = await screen.findAllByLabelText(/City/); + expect(city[0]).toHaveAttribute('name', 'pickup.address.city'); + expect(city[1]).toHaveAttribute('name', 'delivery.address.city'); + + const state = await screen.findAllByLabelText(/State/); + expect(state[0]).toHaveAttribute('name', 'pickup.address.state'); + expect(state[1]).toHaveAttribute('name', 'delivery.address.state'); + + const zip = await screen.findAllByLabelText(/ZIP/); + expect(zip[0]).toHaveAttribute('name', 'pickup.address.postalCode'); + expect(zip[1]).toHaveAttribute('name', 'delivery.address.postalCode'); + }); + + it('renders the secondary destination address question once a user says they have a primary destination address', async () => { + renderUBShipmentForm(); + + expect(screen.queryByRole('heading', { level: 4, name: 'Second Destination Location' })).not.toBeInTheDocument(); + expect(screen.queryByTitle('Yes, I have a second destination location')).not.toBeInTheDocument(); + expect(screen.queryByTitle('No, I do not have a second destination location')).not.toBeInTheDocument(); + + await userEvent.click(screen.getByTitle('Yes, I know my delivery address')); + + expect(await screen.findByRole('heading', { level: 4, name: 'Second delivery location' })).toBeInTheDocument(); + expect(screen.getByTitle('Yes, I have a second destination location')).toBeInstanceOf(HTMLInputElement); + expect(screen.getByTitle('No, I do not have a second destination location')).toBeInstanceOf(HTMLInputElement); + }); + + it('renders another address fieldset when the user has a second destination address', async () => { + renderUBShipmentForm(); + + await userEvent.click(screen.getByTitle('Yes, I know my delivery address')); + await userEvent.click(screen.getByTitle('Yes, I have a second destination location')); + + const streetAddress1 = await screen.findAllByLabelText(/Address 1/); + expect(streetAddress1.length).toBe(3); + expect(streetAddress1[2]).toHaveAttribute('name', 'secondaryDelivery.address.streetAddress1'); + + const streetAddress2 = await screen.findAllByLabelText(/Address 2/); + expect(streetAddress2.length).toBe(3); + expect(streetAddress2[2]).toHaveAttribute('name', 'secondaryDelivery.address.streetAddress2'); + + const city = await screen.findAllByLabelText(/City/); + expect(city.length).toBe(3); + expect(city[2]).toHaveAttribute('name', 'secondaryDelivery.address.city'); + + const state = await screen.findAllByLabelText(/State/); + expect(state.length).toBe(3); + expect(state[2]).toHaveAttribute('name', 'secondaryDelivery.address.state'); + + const zip = await screen.findAllByLabelText(/ZIP/); + expect(zip.length).toBe(3); + expect(zip[2]).toHaveAttribute('name', 'secondaryDelivery.address.postalCode'); + }); + + it('goes back when the back button is clicked', async () => { + renderUBShipmentForm(); + + const backButton = await screen.findByRole('button', { name: 'Back' }); + await userEvent.click(backButton); + + await waitFor(() => { + expect(mockNavigate).toHaveBeenCalledWith(-1); + }); + }); + + it('can submit a new UB shipment successfully', async () => { + const shipmentInfo = { + requestedPickupDate: '07 Jun 2021', + pickupAddress: { + streetAddress1: '812 S 129th St', + streetAddress2: '#123', + city: 'San Antonio', + state: 'TX', + postalCode: '78234', + }, + requestedDeliveryDate: '14 Jun 2021', + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + }; + + const expectedPayload = { + agents: [ + { agentType: 'RELEASING_AGENT', email: '', firstName: '', lastName: '', phone: '' }, + { agentType: 'RECEIVING_AGENT', email: '', firstName: '', lastName: '', phone: '' }, + ], + moveTaskOrderID: moveId, + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + customerRemarks: '', + requestedPickupDate: '2021-06-07', + pickupAddress: { ...shipmentInfo.pickupAddress }, + requestedDeliveryDate: '2021-06-14', + hasSecondaryPickupAddress: false, + hasSecondaryDeliveryAddress: false, + hasTertiaryPickupAddress: false, + hasTertiaryDeliveryAddress: false, + }; + + const updatedAt = '2021-06-11T18:12:11.918Z'; + const expectedCreateResponse = { + createdAt: '2021-06-11T18:12:11.918Z', + customerRemarks: '', + eTag: window.btoa(updatedAt), + id: uuidv4(), + moveTaskOrderID: moveId, + pickupAddress: { ...shipmentInfo.pickupAddress, id: uuidv4() }, + requestedDeliveryDate: expectedPayload.requestedDeliveryDate, + requestedPickupDate: expectedPayload.requestedPickupDate, + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + status: 'SUBMITTED', + updatedAt, + }; + + createMTOShipment.mockImplementation(() => Promise.resolve(expectedCreateResponse)); + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: false, + is_holiday: false, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm(); + + const pickupDateInput = await screen.findByLabelText(/Preferred pickup date/); + await userEvent.type(pickupDateInput, shipmentInfo.requestedPickupDate); + + const pickupAddress1Input = screen.getByLabelText(/Address 1/); + await userEvent.type(pickupAddress1Input, shipmentInfo.pickupAddress.streetAddress1); + + const pickupAddress2Input = screen.getByLabelText(/Address 2/); + await userEvent.type(pickupAddress2Input, shipmentInfo.pickupAddress.streetAddress2); + + const pickupCityInput = screen.getByLabelText(/City/); + await userEvent.type(pickupCityInput, shipmentInfo.pickupAddress.city); + + const pickupStateInput = screen.getByLabelText(/State/); + await userEvent.selectOptions(pickupStateInput, shipmentInfo.pickupAddress.state); + + const pickupPostalCodeInput = screen.getByLabelText(/ZIP/); + await userEvent.type(pickupPostalCodeInput, shipmentInfo.pickupAddress.postalCode); + + const deliveryDateInput = await screen.findByLabelText(/Preferred delivery date/); + await userEvent.type(deliveryDateInput, shipmentInfo.requestedDeliveryDate); + + const nextButton = await screen.findByRole('button', { name: 'Next' }); + expect(nextButton).not.toBeDisabled(); + await userEvent.click(nextButton); + + await waitFor(() => { + expect(createMTOShipment).toHaveBeenCalledWith(expectedPayload); + }); + + expect(ubProps.updateMTOShipment).toHaveBeenCalledWith(expectedCreateResponse); + + expect(mockNavigate).toHaveBeenCalledWith(reviewPath); + }); + + it('shows an error when there is an error with the submission', async () => { + const shipmentInfo = { + requestedPickupDate: '07 Jun 2021', + pickupAddress: { + streetAddress1: '812 S 129th St', + streetAddress2: '#123', + city: 'San Antonio', + state: 'TX', + postalCode: '78234', + }, + requestedDeliveryDate: '14 Jun 2021', + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + }; + + const errorMessage = 'Something broke!'; + const errorResponse = { response: { errorMessage } }; + createMTOShipment.mockImplementation(() => Promise.reject(errorResponse)); + getResponseError.mockImplementation(() => errorMessage); + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm(); + + const pickupDateInput = await screen.findByLabelText(/Preferred pickup date/); + await userEvent.type(pickupDateInput, shipmentInfo.requestedPickupDate); + + const pickupAddress1Input = screen.getByLabelText(/Address 1/); + await userEvent.type(pickupAddress1Input, shipmentInfo.pickupAddress.streetAddress1); + + const pickupAddress2Input = screen.getByLabelText(/Address 2/); + await userEvent.type(pickupAddress2Input, shipmentInfo.pickupAddress.streetAddress2); + + const pickupCityInput = screen.getByLabelText(/City/); + await userEvent.type(pickupCityInput, shipmentInfo.pickupAddress.city); + + const pickupStateInput = screen.getByLabelText(/State/); + await userEvent.selectOptions(pickupStateInput, shipmentInfo.pickupAddress.state); + + const pickupPostalCodeInput = screen.getByLabelText(/ZIP/); + await userEvent.type(pickupPostalCodeInput, shipmentInfo.pickupAddress.postalCode); + + const deliveryDateInput = await screen.findByLabelText(/Preferred delivery date/); + await userEvent.type(deliveryDateInput, shipmentInfo.requestedDeliveryDate); + + const nextButton = await screen.findByRole('button', { name: 'Next' }); + expect(nextButton).not.toBeDisabled(); + await userEvent.click(nextButton); + + await waitFor(() => { + expect(createMTOShipment).toHaveBeenCalled(); + }); + + expect(getResponseError).toHaveBeenCalledWith( + errorResponse.response, + 'failed to create MTO shipment due to server error', + ); + + expect(await screen.findByText(errorMessage)).toBeInTheDocument(); + }); + }); + + describe('editing an already existing UB shipment', () => { + const updatedAt = '2021-06-11T18:12:11.918Z'; + + const mockMtoShipment = { + id: uuidv4(), + eTag: window.btoa(updatedAt), + createdAt: '2021-06-11T18:12:11.918Z', + updatedAt, + moveTaskOrderId: moveId, + customerRemarks: 'mock remarks', + requestedPickupDate: '2021-08-01', + requestedDeliveryDate: '2021-08-11', + pickupAddress: { + id: uuidv4(), + streetAddress1: '812 S 129th St', + city: 'San Antonio', + state: 'TX', + postalCode: '78234', + }, + destinationAddress: { + id: uuidv4(), + streetAddress1: '441 SW Rio de la Plata Drive', + city: 'Tacoma', + state: 'WA', + postalCode: '98421', + }, + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + }; + + it('renders the UB shipment form with pre-filled values', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + + expect(await screen.findByLabelText(/Preferred pickup date/)).toHaveValue('01 Aug 2021'); + expect(screen.getByLabelText('Use my current address')).not.toBeChecked(); + expect(screen.getAllByLabelText(/Address 1/)[0]).toHaveValue('812 S 129th St'); + expect(screen.getAllByLabelText(/Address 2/)[0]).toHaveValue(''); + expect(screen.getAllByLabelText(/City/)[0]).toHaveValue('San Antonio'); + expect(screen.getAllByLabelText(/State/)[0]).toHaveValue('TX'); + expect(screen.getAllByLabelText(/ZIP/)[0]).toHaveValue('78234'); + expect(screen.getByLabelText(/Preferred delivery date/)).toHaveValue('11 Aug 2021'); + expect(screen.getByTitle('Yes, I know my delivery address')).toBeChecked(); + expect(screen.getAllByLabelText(/Address 1/)[1]).toHaveValue('441 SW Rio de la Plata Drive'); + expect(screen.getAllByLabelText(/Address 2/)[1]).toHaveValue(''); + expect(screen.getAllByLabelText(/City/)[1]).toHaveValue('Tacoma'); + expect(screen.getAllByLabelText(/State/)[1]).toHaveValue('WA'); + expect(screen.getAllByLabelText(/ZIP/)[1]).toHaveValue('98421'); + expect( + screen.getByLabelText( + 'Are there things about this shipment that your counselor or movers should discuss with you?', + ), + ).toHaveValue('mock remarks'); + + expect( + screen.getByText( + /Preferred pickup date 01 Aug 2021 is on a holiday and weekend in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + expect( + screen.getAllByText( + 'Preferred pickup date 01 Aug 2021 is on a holiday and weekend in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date.', + ), + ).toHaveLength(1); + }); + + it('renders the UB shipment form with pre-filled secondary addresses', async () => { + const shipment = { + ...mockMtoShipment, + secondaryPickupAddress: { + streetAddress1: '142 E Barrel Hoop Circle', + streetAddress2: '#4A', + city: 'Corpus Christi', + state: 'TX', + postalCode: '78412', + }, + secondaryDeliveryAddress: { + streetAddress1: '3373 NW Martin Luther King Jr Blvd', + streetAddress2: '', + city: mockMtoShipment.destinationAddress.city, + state: mockMtoShipment.destinationAddress.state, + postalCode: mockMtoShipment.destinationAddress.postalCode, + }, + }; + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: shipment }); + + expect(await screen.findByTitle('Yes, I have a second pickup location')).toBeChecked(); + expect(await screen.findByTitle('Yes, I have a second destination location')).toBeChecked(); + + const streetAddress1 = await screen.findAllByLabelText(/Address 1/); + expect(streetAddress1.length).toBe(4); + + const streetAddress2 = await screen.findAllByLabelText(/Address 2/); + expect(streetAddress2.length).toBe(4); + + const city = await screen.findAllByLabelText(/City/); + expect(city.length).toBe(4); + + const state = await screen.findAllByLabelText(/State/); + expect(state.length).toBe(4); + + const zip = await screen.findAllByLabelText(/ZIP/); + expect(zip.length).toBe(4); + + // Secondary pickup address should be the 2nd address + expect(streetAddress1[1]).toHaveValue('142 E Barrel Hoop Circle'); + expect(streetAddress2[1]).toHaveValue('#4A'); + expect(city[1]).toHaveValue('Corpus Christi'); + expect(state[1]).toHaveValue('TX'); + expect(zip[1]).toHaveValue('78412'); + + // Secondary delivery address should be the 4th address + expect(streetAddress1[3]).toHaveValue('3373 NW Martin Luther King Jr Blvd'); + expect(streetAddress2[3]).toHaveValue(''); + expect(city[3]).toHaveValue(mockMtoShipment.destinationAddress.city); + expect(state[3]).toHaveValue(mockMtoShipment.destinationAddress.state); + expect(zip[3]).toHaveValue(mockMtoShipment.destinationAddress.postalCode); + }); + + it.each([ + [/Address 1/, 'Some Address'], + [/Address 2/, '123'], + [/City/, 'Some City'], + [/ZIP/, '92131'], + ])( + 'does not allow the user to save the form if the %s field on a secondary addreess is the only one filled out', + async (fieldName, text) => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: false, + is_holiday: false, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + + // Verify that the form is good to submit by checking that the save button is not disabled. + const saveButton = await screen.findByRole('button', { name: 'Save' }); + expect(saveButton).not.toBeDisabled(); + + await userEvent.click(screen.getByTitle('Yes, I have a second pickup location')); + await userEvent.click(screen.getByTitle('Yes, I have a second destination location')); + + const address = await screen.findAllByLabelText(fieldName); + // The second instance of a field is the secondary pickup + await userEvent.type(address[1], text); + await waitFor(() => { + expect(saveButton).toBeDisabled(); + }); + + // Clear the field so that the secondary delivery address can be checked + await userEvent.clear(address[1]); + await waitFor(() => { + expect(saveButton).not.toBeDisabled(); + }); + + // The fourth instance found is the secondary delivery + await userEvent.type(address[3], text); + await waitFor(() => { + expect(saveButton).toBeDisabled(); + }); + + await userEvent.clear(address[3]); + await waitFor(() => { + expect(saveButton).not.toBeDisabled(); + }); + }, + ); + + // Similar test as above, but with the state input. + // Extracted out since the state field is not a text input. + it('does not allow the user to save the form if the state field on a secondary addreess is the only one filled out', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: false, + is_holiday: false, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + + // Verify that the form is good to submit by checking that the save button is not disabled. + const saveButton = await screen.findByRole('button', { name: 'Save' }); + expect(saveButton).not.toBeDisabled(); + + await userEvent.click(screen.getByTitle('Yes, I have a second pickup location')); + await userEvent.click(screen.getByTitle('Yes, I have a second destination location')); + + const state = await screen.findAllByLabelText(/State/); + // The second instance of a field is the secondary pickup + await userEvent.selectOptions(state[1], 'CA'); + await waitFor(() => { + expect(saveButton).toBeDisabled(); + }); + + // Change the selection to blank so that the secondary delivery address can be checked + await userEvent.selectOptions(state[1], ''); + await waitFor(() => { + expect(saveButton).not.toBeDisabled(); + }); + + // The fourth instance found is the secondary delivery + await userEvent.selectOptions(state[3], 'CA'); + await waitFor(() => { + expect(saveButton).toBeDisabled(); + }); + + await userEvent.selectOptions(state[3], ''); + await waitFor(() => { + expect(saveButton).not.toBeDisabled(); + }); + }); + + it('goes back when the cancel button is clicked', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + + const cancelButton = await screen.findByRole('button', { name: 'Cancel' }); + await userEvent.click(cancelButton); + + await waitFor(() => { + expect(mockNavigate).toHaveBeenCalledWith(-1); + }); + }); + + it('can submit edits to a UB shipment successfully', async () => { + const shipmentInfo = { + pickupAddress: { + streetAddress1: '6622 Airport Way S', + streetAddress2: '#1430', + city: 'San Marcos', + state: 'TX', + postalCode: '78666', + }, + }; + + const expectedPayload = { + moveTaskOrderID: moveId, + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + pickupAddress: { ...shipmentInfo.pickupAddress }, + customerRemarks: mockMtoShipment.customerRemarks, + requestedPickupDate: mockMtoShipment.requestedPickupDate, + requestedDeliveryDate: mockMtoShipment.requestedDeliveryDate, + destinationAddress: { ...mockMtoShipment.destinationAddress, streetAddress2: '' }, + secondaryDeliveryAddress: undefined, + hasSecondaryDeliveryAddress: false, + secondaryPickupAddress: undefined, + hasSecondaryPickupAddress: false, + tertiaryDeliveryAddress: undefined, + hasTertiaryDeliveryAddress: false, + tertiaryPickupAddress: undefined, + hasTertiaryPickupAddress: false, + agents: [ + { agentType: 'RELEASING_AGENT', email: '', firstName: '', lastName: '', phone: '' }, + { agentType: 'RECEIVING_AGENT', email: '', firstName: '', lastName: '', phone: '' }, + ], + counselorRemarks: undefined, + }; + delete expectedPayload.destinationAddress.id; + + const newUpdatedAt = '2021-06-11T21:20:22.150Z'; + const expectedUpdateResponse = { + ...mockMtoShipment, + pickupAddress: { ...shipmentInfo.pickupAddress }, + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + eTag: window.btoa(newUpdatedAt), + status: 'SUBMITTED', + }; + + patchMTOShipment.mockImplementation(() => Promise.resolve(expectedUpdateResponse)); + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + + const pickupAddress1Input = screen.getAllByLabelText(/Address 1/)[0]; + await userEvent.clear(pickupAddress1Input); + await userEvent.type(pickupAddress1Input, shipmentInfo.pickupAddress.streetAddress1); + + const pickupAddress2Input = screen.getAllByLabelText(/Address 2/)[0]; + await userEvent.clear(pickupAddress2Input); + await userEvent.type(pickupAddress2Input, shipmentInfo.pickupAddress.streetAddress2); + + const pickupCityInput = screen.getAllByLabelText(/City/)[0]; + await userEvent.clear(pickupCityInput); + await userEvent.type(pickupCityInput, shipmentInfo.pickupAddress.city); + + const pickupStateInput = screen.getAllByLabelText(/State/)[0]; + await userEvent.selectOptions(pickupStateInput, shipmentInfo.pickupAddress.state); + + const pickupPostalCodeInput = screen.getAllByLabelText(/ZIP/)[0]; + await userEvent.clear(pickupPostalCodeInput); + await userEvent.type(pickupPostalCodeInput, shipmentInfo.pickupAddress.postalCode); + + const saveButton = await screen.findByRole('button', { name: 'Save' }); + expect(saveButton).not.toBeDisabled(); + await userEvent.click(saveButton); + + await waitFor(() => { + expect(patchMTOShipment).toHaveBeenCalledWith(mockMtoShipment.id, expectedPayload, mockMtoShipment.eTag); + }); + + expect(ubProps.updateMTOShipment).toHaveBeenCalledWith(expectedUpdateResponse); + + expect(mockNavigate).toHaveBeenCalledWith(reviewPath); + }); + + it('shows an error when there is an error with the submission', async () => { + const shipmentInfo = { + pickupAddress: { + streetAddress1: '6622 Airport Way S', + streetAddress2: '#1430', + city: 'San Marcos', + state: 'TX', + postalCode: '78666', + }, + }; + + const errorMessage = 'Something broke!'; + const errorResponse = { response: { errorMessage } }; + patchMTOShipment.mockImplementation(() => Promise.reject(errorResponse)); + getResponseError.mockImplementation(() => errorMessage); + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + + const pickupAddress1Input = screen.getAllByLabelText(/Address 1/)[0]; + await userEvent.clear(pickupAddress1Input); + await userEvent.type(pickupAddress1Input, shipmentInfo.pickupAddress.streetAddress1); + + const pickupAddress2Input = screen.getAllByLabelText(/Address 2/)[0]; + await userEvent.clear(pickupAddress2Input); + await userEvent.type(pickupAddress2Input, shipmentInfo.pickupAddress.streetAddress2); + + const pickupCityInput = screen.getAllByLabelText(/City/)[0]; + await userEvent.clear(pickupCityInput); + await userEvent.type(pickupCityInput, shipmentInfo.pickupAddress.city); + + const pickupStateInput = screen.getAllByLabelText(/State/)[0]; + await userEvent.selectOptions(pickupStateInput, shipmentInfo.pickupAddress.state); + + const pickupPostalCodeInput = screen.getAllByLabelText(/ZIP/)[0]; + await userEvent.clear(pickupPostalCodeInput); + await userEvent.type(pickupPostalCodeInput, shipmentInfo.pickupAddress.postalCode); + + const saveButton = await screen.findByRole('button', { name: 'Save' }); + expect(saveButton).not.toBeDisabled(); + await userEvent.click(saveButton); + + await waitFor(() => { + expect(patchMTOShipment).toHaveBeenCalled(); + }); + + expect(getResponseError).toHaveBeenCalledWith( + errorResponse.response, + 'failed to update MTO shipment due to server error', + ); + + expect(await screen.findByText(errorMessage)).toBeInTheDocument(); + }); + + it('renders the UB shipment form with pre-filled values', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + expect(await screen.findByLabelText(/Preferred pickup date/)).toHaveValue('01 Aug 2021'); + expect(screen.getByLabelText('Use my current address')).not.toBeChecked(); + expect(screen.getAllByLabelText(/Address 1/)[0]).toHaveValue('812 S 129th St'); + expect(screen.getAllByLabelText(/Address 2/)[0]).toHaveValue(''); + expect(screen.getAllByLabelText(/City/)[0]).toHaveValue('San Antonio'); + expect(screen.getAllByLabelText(/State/)[0]).toHaveValue('TX'); + expect(screen.getAllByLabelText(/ZIP/)[0]).toHaveValue('78234'); + expect(screen.getByLabelText(/Preferred delivery date/)).toHaveValue('11 Aug 2021'); + expect(screen.getByTitle('Yes, I know my delivery address')).toBeChecked(); + expect(screen.getAllByLabelText(/Address 1/)[1]).toHaveValue('441 SW Rio de la Plata Drive'); + expect(screen.getAllByLabelText(/Address 2/)[1]).toHaveValue(''); + expect(screen.getAllByLabelText(/City/)[1]).toHaveValue('Tacoma'); + expect(screen.getAllByLabelText(/State/)[1]).toHaveValue('WA'); + expect(screen.getAllByLabelText(/ZIP/)[1]).toHaveValue('98421'); + expect( + screen.getByLabelText( + 'Are there things about this shipment that your counselor or movers should discuss with you?', + ), + ).toHaveValue('mock remarks'); + }); + + it('renders the UB shipment with date validaton alerts for weekend and holiday', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United of States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + expect(await screen.findByLabelText(/Preferred pickup date/)).toHaveValue('01 Aug 2021'); + expect(screen.getByLabelText(/Preferred delivery date/)).toHaveValue('11 Aug 2021'); + await waitFor(() => { + expect( + screen.getByText( + /Preferred pickup date 01 Aug 2021 is on a holiday and weekend in the United of States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + expect( + screen.getByText( + /Preferred delivery date 11 Aug 2021 is on a holiday and weekend in the United of States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + }); + }); + + it('renders the UB shipment with date validaton alerts for weekend', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: false, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + expect(await screen.findByLabelText(/Preferred pickup date/)).toHaveValue('01 Aug 2021'); + expect(screen.getByLabelText(/Preferred delivery date/)).toHaveValue('11 Aug 2021'); + await waitFor(() => { + expect( + screen.getByText( + /Preferred pickup date 01 Aug 2021 is on a weekend in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + expect( + screen.getByText( + /Preferred delivery date 11 Aug 2021 is on a weekend in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + }); + }); + + it('renders the UB shipment with date validaton alerts for holiday', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: false, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + expect(await screen.findByLabelText(/Preferred pickup date/)).toHaveValue('01 Aug 2021'); + expect(screen.getByLabelText(/Preferred delivery date/)).toHaveValue('11 Aug 2021'); + await waitFor(() => { + expect( + screen.getByText( + /Preferred pickup date 01 Aug 2021 is on a holiday in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + expect( + screen.getByText( + /Preferred delivery date 11 Aug 2021 is on a holiday in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + }); + }); + + it('renders the UB shipment with no date validaton alerts for pickup/delivery', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: false, + is_holiday: false, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + expect(await screen.findByLabelText(/Preferred pickup date/)).toHaveValue('01 Aug 2021'); + expect(screen.getByLabelText(/Preferred delivery date/)).toHaveValue('11 Aug 2021'); + expect( + screen.getByLabelText( + 'Are there things about this shipment that your counselor or movers should discuss with you?', + ), + ).toHaveValue('mock remarks'); + + await waitFor(() => { + expect( + screen.queryAllByText( + 'Preferred pickup date 01 Aug 2021 is on a holiday in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date.', + ), + ).toHaveLength(0); + expect( + screen.queryAllByText( + 'Preferred delivery date 11 Aug 2021 is on a holiday in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date.', + ), + ).toHaveLength(0); + }); + }); + }); + describe('creating a new NTS shipment', () => { it('renders the NTS shipment form', async () => { renderMtoShipmentForm({ shipmentType: SHIPMENT_OPTIONS.NTS }); diff --git a/src/components/Customer/MtoShipmentForm/getShipmentOptions.js b/src/components/Customer/MtoShipmentForm/getShipmentOptions.js index 86c6ddb48f0..17569ce6f28 100644 --- a/src/components/Customer/MtoShipmentForm/getShipmentOptions.js +++ b/src/components/Customer/MtoShipmentForm/getShipmentOptions.js @@ -163,6 +163,13 @@ function getShipmentOptions(shipmentType, userRole) { } } + case SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE: + return { + schema: hhgShipmentSchema, + showPickupFields: true, + showDeliveryFields: true, + }; + default: throw new Error('unrecognized shipment type'); } diff --git a/src/components/Customer/Review/Summary/Summary.jsx b/src/components/Customer/Review/Summary/Summary.jsx index 2bafeb88b1a..924e172336b 100644 --- a/src/components/Customer/Review/Summary/Summary.jsx +++ b/src/components/Customer/Review/Summary/Summary.jsx @@ -172,6 +172,7 @@ export class Summary extends Component { let ppmShipmentNumber = 0; let boatShipmentNumber = 0; let mobileHomeShipmentNumber = 0; + let ubShipmentNumber = 0; return sortedShipments.map((shipment) => { let receivingAgent; let releasingAgent; @@ -302,6 +303,36 @@ export class Summary extends Component { /> ); } + if (shipment.shipmentType === SHIPMENT_TYPES.UNACCOMPANIED_BAGGAGE) { + ubShipmentNumber += 1; + return ( + + ); + } hhgShipmentNumber += 1; return ( { expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTSR); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.BOAT); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.MOBILE_HOME); + expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE); }); it('add shipment modal displays still in dev mode', async () => { @@ -699,6 +700,7 @@ describe('Summary page', () => { expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTSR); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.BOAT); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.MOBILE_HOME); + expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE); }); }); afterEach(jest.clearAllMocks); diff --git a/src/components/Office/ShipmentContainer/ShipmentContainer.jsx b/src/components/Office/ShipmentContainer/ShipmentContainer.jsx index 359032c4b61..a6491f9a8b5 100644 --- a/src/components/Office/ShipmentContainer/ShipmentContainer.jsx +++ b/src/components/Office/ShipmentContainer/ShipmentContainer.jsx @@ -22,6 +22,7 @@ const ShipmentContainer = ({ id, className, children, shipmentType }) => { 'container--accent--ppm': shipmentType === SHIPMENT_OPTIONS.PPM, 'container--accent--boat': isBoat, 'container--accent--mobilehome': shipmentType === SHIPMENT_OPTIONS.MOBILE_HOME, + 'container--accent--ub': shipmentType === SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, }, className, ); diff --git a/src/components/Office/ShipmentContainer/ShipmentContainer.test.jsx b/src/components/Office/ShipmentContainer/ShipmentContainer.test.jsx index b7fc2fa74ef..2b8f6d0729d 100644 --- a/src/components/Office/ShipmentContainer/ShipmentContainer.test.jsx +++ b/src/components/Office/ShipmentContainer/ShipmentContainer.test.jsx @@ -59,6 +59,7 @@ describe('Shipment Container', () => { [SHIPMENT_OPTIONS.HHG, 'container--accent--hhg'], [SHIPMENT_OPTIONS.NTS, 'container--accent--nts'], [SHIPMENT_OPTIONS.NTSR, 'container--accent--ntsr'], + [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, 'container--accent--ub'], ])('renders a container for a shipment (%s) with className %s ', async (shipmentType, expectedClass) => { const newHeadingInfo = { ...headingInfo, diff --git a/src/components/ShipmentList/ShipmentList.jsx b/src/components/ShipmentList/ShipmentList.jsx index f8e2393bada..6ae2e02aedd 100644 --- a/src/components/ShipmentList/ShipmentList.jsx +++ b/src/components/ShipmentList/ShipmentList.jsx @@ -39,6 +39,7 @@ export const ShipmentListItem = ({ [styles[`shipment-list-item-PPM`]]: isPPM, [styles[`shipment-list-item-Boat`]]: isBoat, [styles[`shipment-list-item-MobileHome`]]: isMobileHome, + [styles[`shipment-list-item-UB`]]: shipment.shipmentType === SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, }); const estimated = 'Estimated'; const actual = 'Actual'; diff --git a/src/components/ShipmentList/ShipmentList.module.scss b/src/components/ShipmentList/ShipmentList.module.scss index 2e2e1cd6cc3..34a8d484f1a 100644 --- a/src/components/ShipmentList/ShipmentList.module.scss +++ b/src/components/ShipmentList/ShipmentList.module.scss @@ -103,6 +103,10 @@ border-left: 5px solid $accent-mobile-home; } +.shipment-list-item-UB { + border-left: 5px solid $accent-ub; +} + .spaceBetween { display: flex; justify-content: center; diff --git a/src/components/ShipmentList/ShipmentList.test.jsx b/src/components/ShipmentList/ShipmentList.test.jsx index 6e46c06d6d2..fb93e786f9b 100644 --- a/src/components/ShipmentList/ShipmentList.test.jsx +++ b/src/components/ShipmentList/ShipmentList.test.jsx @@ -24,6 +24,7 @@ describe('ShipmentList component', () => { { id: 'ID-2', shipmentType: SHIPMENT_OPTIONS.HHG }, { id: 'ID-3', shipmentType: SHIPMENT_OPTIONS.NTS }, { id: 'ID-4', shipmentType: SHIPMENT_OPTIONS.NTSR }, + { id: 'ID-4', shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE }, ]; const onShipmentClick = jest.fn(); const onDeleteClick = jest.fn(); @@ -36,11 +37,12 @@ describe('ShipmentList component', () => { it('renders ShipmentList with shipments', async () => { render(); - expect(screen.getAllByTestId('shipment-list-item-container').length).toBe(4); + expect(screen.getAllByTestId('shipment-list-item-container').length).toBe(5); expect(screen.getAllByTestId('shipment-list-item-container')[0]).toHaveTextContent(/^ppm/i); expect(screen.getAllByTestId('shipment-list-item-container')[1]).toHaveTextContent(/^hhg/i); expect(screen.getAllByTestId('shipment-list-item-container')[2]).toHaveTextContent(/^nts/i); expect(screen.getAllByTestId('shipment-list-item-container')[3]).toHaveTextContent(/^nts-release/i); + expect(screen.getAllByTestId('shipment-list-item-container')[4]).toHaveTextContent(/^UB/i); }); it.each([ @@ -72,6 +74,9 @@ describe('ShipmentList component', () => { editBtn = queryByRole(screen.getAllByTestId('shipment-list-item-container')[3], 'button', { name: 'Edit' }); await checkShipmentClick('ID-4', 1, SHIPMENT_OPTIONS.NTSR); + + editBtn = queryByRole(screen.getAllByTestId('shipment-list-item-container')[4], 'button', { name: 'Edit' }); + await checkShipmentClick('ID-4', 1, SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE); }); it.each([ @@ -79,6 +84,7 @@ describe('ShipmentList component', () => { [SHIPMENT_OPTIONS.HHG, 2], [SHIPMENT_OPTIONS.NTS, 3], [SHIPMENT_OPTIONS.NTSR, 4], + [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, 5], ])('calls onDeleteClick for shipment type %s when delete is clicked', async (_, id) => { render(); const deleteBtn = getByRole(screen.getAllByTestId('shipment-list-item-container')[id - 1], 'button', { diff --git a/src/constants/shipments.js b/src/constants/shipments.js index 9a9154f44b1..0be6c1adc97 100644 --- a/src/constants/shipments.js +++ b/src/constants/shipments.js @@ -10,6 +10,7 @@ export const shipmentTypes = { [SHIPMENT_OPTIONS.BOAT]: 'Boat', [SHIPMENT_TYPES.BOAT_HAUL_AWAY]: 'Boat', [SHIPMENT_TYPES.BOAT_TOW_AWAY]: 'Boat', + [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE]: 'UB', }; export const shipmentModificationTypes = { @@ -22,6 +23,8 @@ export const mtoShipmentTypes = { [SHIPMENT_OPTIONS.PPM]: 'Personally procured move', [SHIPMENT_OPTIONS.NTS]: 'Non-temp storage', [SHIPMENT_OPTIONS.NTSR]: 'Non-temp storage release', + [SHIPMENT_OPTIONS.HHG]: 'Household goods', + [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE]: 'UB', }; export const shipmentStatuses = { diff --git a/src/content/shipments.js b/src/content/shipments.js index 828401103fd..2cabf052de4 100644 --- a/src/content/shipments.js +++ b/src/content/shipments.js @@ -10,6 +10,7 @@ export const shipmentTypeLabels = { [SHIPMENT_TYPES.BOAT_HAUL_AWAY]: 'Boat', [SHIPMENT_TYPES.BOAT_TOW_AWAY]: 'Boat', [SHIPMENT_TYPES.MOBILE_HOME]: 'Mobile Home', + [SHIPMENT_TYPES.UNACCOMPANIED_BAGGAGE]: 'UB', }; export const shipmentForm = { diff --git a/src/shared/constants.js b/src/shared/constants.js index 0571f76d0ad..94903bd65c4 100644 --- a/src/shared/constants.js +++ b/src/shared/constants.js @@ -83,6 +83,7 @@ export const SHIPMENT_OPTIONS = { BOAT_HAUL_AWAY: 'BOAT', BOAT_TOW_AWAY: 'BOAT', MOBILE_HOME: 'MOBILE_HOME', + UNACCOMPANIED_BAGGAGE: 'UNACCOMPANIED_BAGGAGE', }; export const SHIPMENT_TYPES = { @@ -93,6 +94,7 @@ export const SHIPMENT_TYPES = { BOAT_HAUL_AWAY: 'BOAT_HAUL_AWAY', BOAT_TOW_AWAY: 'BOAT_TOW_AWAY', MOBILE_HOME: 'MOBILE_HOME', + UNACCOMPANIED_BAGGAGE: 'UNACCOMPANIED_BAGGAGE', }; // These constants are used for forming URLs that have the shipment type in @@ -104,6 +106,7 @@ export const SHIPMENT_OPTIONS_URL = { NTSrelease: 'NTSrelease', BOAT: 'Boat', MOBILE_HOME: 'Mobilehome', + UNACCOMPANIED_BAGGAGE: 'UB', }; export const LOA_TYPE = { @@ -125,6 +128,7 @@ export const shipmentOptionLabels = [ { key: SHIPMENT_OPTIONS.MOBILE_HOME, label: 'Mobile Home' }, { key: SHIPMENT_TYPES.BOAT_HAUL_AWAY, label: 'Boat' }, { key: SHIPMENT_TYPES.BOAT_TOW_AWAY, label: 'Boat' }, + { key: SHIPMENT_TYPES.UNACCOMPANIED_BAGGAGE, label: 'UB' }, ]; export const SERVICE_ITEM_STATUS = { @@ -198,6 +202,7 @@ export const FEATURE_FLAG_KEYS = { NTSR: 'ntsr', BOAT: 'boat', MOBILE_HOME: 'mobile_home', + UNACCOMPANIED_BAGGAGE: 'unaccompanied_baggage', }; export const MOVE_DOCUMENT_TYPE = { diff --git a/src/shared/styles/colors.scss b/src/shared/styles/colors.scss index 96e08a1b223..0acc2a82868 100644 --- a/src/shared/styles/colors.scss +++ b/src/shared/styles/colors.scss @@ -34,7 +34,7 @@ $link-light-hover: #b7caf0; $accent-teal: #027a97; $accent-hhg: #0096f4; $accent-ppm: #e6c74c; -$accent-ub: #f2938c; +$accent-ub: #5050c4; $accent-nts: #d85bef; $accent-ntsr: #8168b3; $accent-boat: #5d92ba; From 870a3c9f7a5991977b7b82d5d3674faca1612825 Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 19:46:30 +0000 Subject: [PATCH 02/15] change color back to peach for ubs --- src/shared/styles/colors.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/styles/colors.scss b/src/shared/styles/colors.scss index 0acc2a82868..96e08a1b223 100644 --- a/src/shared/styles/colors.scss +++ b/src/shared/styles/colors.scss @@ -34,7 +34,7 @@ $link-light-hover: #b7caf0; $accent-teal: #027a97; $accent-hhg: #0096f4; $accent-ppm: #e6c74c; -$accent-ub: #5050c4; +$accent-ub: #f2938c; $accent-nts: #d85bef; $accent-ntsr: #8168b3; $accent-boat: #5d92ba; From ba8eada20f0c09001ec2b24011c5c19080540fc5 Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 19:47:15 +0000 Subject: [PATCH 03/15] expand hhgshipmentcard tests to test ubs --- .../HHGShipmentCard/HHGShipmentCard.test.jsx | 185 ++++++++++++++++++ .../Customer/Review/Summary/Summary.test.jsx | 2 - 2 files changed, 185 insertions(+), 2 deletions(-) diff --git a/src/components/Customer/Review/ShipmentCard/HHGShipmentCard/HHGShipmentCard.test.jsx b/src/components/Customer/Review/ShipmentCard/HHGShipmentCard/HHGShipmentCard.test.jsx index dfdbe85c95c..bbcbdb9546c 100644 --- a/src/components/Customer/Review/ShipmentCard/HHGShipmentCard/HHGShipmentCard.test.jsx +++ b/src/components/Customer/Review/ShipmentCard/HHGShipmentCard/HHGShipmentCard.test.jsx @@ -7,6 +7,7 @@ import userEvent from '@testing-library/user-event'; import HHGShipmentCard from 'components/Customer/Review/ShipmentCard/HHGShipmentCard/HHGShipmentCard'; import { formatCustomerDate } from 'utils/formatters'; import { shipmentStatuses } from 'constants/shipments'; +import { SHIPMENT_OPTIONS } from 'shared/constants'; const defaultProps = { moveId: 'testMove123', @@ -205,3 +206,187 @@ describe('HHGShipmentCard component', () => { expect(mockedOnIncompleteClickFunction).toHaveBeenCalledWith('HHG 1', 'ABC123K-01', 'HHG'); }); }); + +const ubProps = { + moveId: 'testMove123', + editPath: '', + onEditClick: jest.fn(), + onDeleteClick: jest.fn(), + shipmentNumber: 1, + shipmentId: '#ABC123K', + shipmentLocator: '#ABC123K-01', + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + showEditAndDeleteBtn: false, + requestedPickupDate: new Date('01/01/2020').toISOString(), + pickupLocation: { + streetAddress1: '17 8th St', + city: 'New York', + state: 'NY', + postalCode: '11111', + }, + releasingAgent: { + firstName: 'Jo', + lastName: 'Xi', + phone: '(555) 555-5555', + email: 'jo.xi@email.com', + }, + requestedDeliveryDate: new Date('03/01/2020').toISOString(), + destinationZIP: '73523', + receivingAgent: { + firstName: 'Dorothy', + lastName: 'Lagomarsino', + phone: '(999) 999-9999', + email: 'dorothy.lagomarsino@email.com', + }, + remarks: + 'This is 500 characters of customer remarks right here. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', +}; + +const incompleteUBProps = { + moveId: 'testMove123', + editPath: '', + onEditClick: jest.fn(), + onDeleteClick: jest.fn(), + onIncompleteClick: mockedOnIncompleteClickFunction, + shipmentNumber: 1, + shipmentId: 'ABC123K', + shipmentLocator: 'ABC123K-01', + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + showEditAndDeleteBtn: false, + requestedPickupDate: new Date('01/01/2020').toISOString(), + status: shipmentStatuses.DRAFT, +}; + +const completeUBProps = { + moveId: 'testMove123', + editPath: '', + onEditClick: jest.fn(), + onDeleteClick: jest.fn(), + shipmentNumber: 1, + shipmentId: 'ABC123K', + shipmentLocator: 'ABC123K-01', + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + showEditAndDeleteBtn: false, + requestedPickupDate: new Date('01/01/2020').toISOString(), + status: shipmentStatuses.SUBMITTED, +}; + +function mountHHGShipmentCardForUBShipment(props) { + return mount(); +} + +describe('HHGShipmentCard component can be reused for UB shipment card', () => { + it('renders component with all fields', () => { + const wrapper = mountHHGShipmentCardForUBShipment(); + const tableHeaders = [ + 'Requested pickup date', + 'Pickup location', + 'Releasing agent', + 'Requested delivery date', + 'Destination', + 'Receiving agent', + 'Remarks', + ]; + const { streetAddress1, city, state, postalCode } = ubProps.pickupLocation; + const { + firstName: releasingFirstName, + lastName: releasingLastName, + phone: releasingTelephone, + email: releasingEmail, + } = ubProps.releasingAgent; + const { + firstName: receivingFirstName, + lastName: receivingLastName, + phone: receivingTelephone, + email: receivingEmail, + } = ubProps.receivingAgent; + const tableData = [ + formatCustomerDate(ubProps.requestedPickupDate), + `${streetAddress1} ${city}, ${state} ${postalCode}`, + `${releasingFirstName} ${releasingLastName} ${releasingTelephone} ${releasingEmail}`, + formatCustomerDate(ubProps.requestedDeliveryDate), + ubProps.destinationZIP, + `${receivingFirstName} ${receivingLastName} ${receivingTelephone} ${receivingEmail}`, + ]; + + tableHeaders.forEach((label, index) => expect(wrapper.find('dt').at(index).text()).toBe(label)); + tableData.forEach((label, index) => expect(wrapper.find('dd').at(index).text()).toBe(label)); + expect(wrapper.find('.remarksCell').text()).toBe(ubProps.remarks); + }); + + it('should render UB shipment card without releasing/receiving agents and remarks', () => { + const wrapper = mountHHGShipmentCardForUBShipment({ + ...ubProps, + releasingAgent: null, + receivingAgent: null, + remarks: '', + }); + const tableHeaders = ['Requested pickup date', 'Pickup location', 'Requested delivery date', 'Destination']; + const { streetAddress1, city, state, postalCode } = ubProps.pickupLocation; + const tableData = [ + formatCustomerDate(ubProps.requestedPickupDate), + `${streetAddress1} ${city}, ${state} ${postalCode}`, + formatCustomerDate(ubProps.requestedDeliveryDate), + ubProps.destinationZIP, + ]; + tableHeaders.forEach((label, index) => expect(wrapper.find('dt').at(index).text()).toBe(label)); + tableData.forEach((label, index) => expect(wrapper.find('dd').at(index).text()).toBe(label)); + expect(wrapper.find('.remarksCell').length).toBe(0); + }); + + it('should not render a secondary pickup location on UB shipment card if not provided one', async () => { + render(); + + const secondPickupLocation = await screen.queryByText('Second pickup location'); + expect(secondPickupLocation).not.toBeInTheDocument(); + }); + + it('should not render a secondary destination location on UB shipment card if not provided one', async () => { + render(); + + const secondDestination = await screen.queryByText('Second Destination'); + expect(secondDestination).not.toBeInTheDocument(); + }); + + it('should render a UB shipment card secondary pickup location if provided one', async () => { + render(); + + const secondPickupLocation = await screen.getByText('Second pickup location'); + expect(secondPickupLocation).toBeInTheDocument(); + const secondPickupLocationInformation = await screen.getByText(/Some Other Street Name/); + expect(secondPickupLocationInformation).toBeInTheDocument(); + }); + + it('should render a UB shipment card secondary destination location if provided one', async () => { + render(); + + const secondDestination = await screen.getByText('Second Destination'); + expect(secondDestination).toBeInTheDocument(); + const secondDesintationInformation = await screen.getByText(/Some Street Name/); + expect(secondDesintationInformation).toBeInTheDocument(); + }); + + it('does not render UB shipment card incomplete label and tooltip icon for completed UB shipment with SUBMITTED status', async () => { + render(); + + expect(screen.getByRole('heading', { level: 3 })).toHaveTextContent('UB 1'); + expect(screen.getByText(/^#ABC123K-01$/, { selector: 'p' })).toBeInTheDocument(); + + expect(screen.queryByText('Incomplete')).toBeNull(); + }); + + it('renders incomplete label and tooltip icon for incomplete UB shipment with DRAFT status', async () => { + render(); + + expect(screen.getByRole('heading', { level: 3 })).toHaveTextContent('UB 1'); + expect(screen.getByText(/^#ABC123K-01$/, { selector: 'p' })).toBeInTheDocument(); + + expect(screen.getByText(/^Incomplete$/, { selector: 'span' })).toBeInTheDocument(); + + expect(screen.getByTitle('Help about incomplete shipment')).toBeInTheDocument(); + await userEvent.click(screen.getByTitle('Help about incomplete shipment')); + + // verify onclick is getting json string as parameter + expect(mockedOnIncompleteClickFunction).toHaveBeenCalledWith('UB 1', 'ABC123K-01', 'UNACCOMPANIED_BAGGAGE'); + }); +}); diff --git a/src/components/Customer/Review/Summary/Summary.test.jsx b/src/components/Customer/Review/Summary/Summary.test.jsx index d788fdaf94a..d62077b1083 100644 --- a/src/components/Customer/Review/Summary/Summary.test.jsx +++ b/src/components/Customer/Review/Summary/Summary.test.jsx @@ -667,7 +667,6 @@ describe('Summary page', () => { expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTSR); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.BOAT); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.MOBILE_HOME); - expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE); }); it('add shipment modal displays still in dev mode', async () => { @@ -700,7 +699,6 @@ describe('Summary page', () => { expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTSR); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.BOAT); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.MOBILE_HOME); - expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE); }); }); afterEach(jest.clearAllMocks); From 5ff85c6fbf1b51a0807c05f743fc29912de7985b Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 20:07:28 +0000 Subject: [PATCH 04/15] update ub to match other type naming convention --- src/constants/shipments.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants/shipments.js b/src/constants/shipments.js index 0be6c1adc97..70f9e908392 100644 --- a/src/constants/shipments.js +++ b/src/constants/shipments.js @@ -24,7 +24,7 @@ export const mtoShipmentTypes = { [SHIPMENT_OPTIONS.NTS]: 'Non-temp storage', [SHIPMENT_OPTIONS.NTSR]: 'Non-temp storage release', [SHIPMENT_OPTIONS.HHG]: 'Household goods', - [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE]: 'UB', + [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE]: 'Unaccompanied baggage', }; export const shipmentStatuses = { From 121688171a2de3326d2fcb5911f73ac3c0b404e6 Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 20:07:57 +0000 Subject: [PATCH 05/15] update summary --- src/components/Customer/Review/Summary/Summary.jsx | 5 +++++ src/components/Customer/Review/Summary/Summary.test.jsx | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/components/Customer/Review/Summary/Summary.jsx b/src/components/Customer/Review/Summary/Summary.jsx index 924e172336b..c44ed4f7916 100644 --- a/src/components/Customer/Review/Summary/Summary.jsx +++ b/src/components/Customer/Review/Summary/Summary.jsx @@ -97,6 +97,11 @@ export class Summary extends Component { enableMobileHome: enabled, }); }); + isBooleanFlagEnabled(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE).then((enabled) => { + this.setState({ + enableMobileHome: enabled, + }); + }); } handleEditClick = (path) => { diff --git a/src/components/Customer/Review/Summary/Summary.test.jsx b/src/components/Customer/Review/Summary/Summary.test.jsx index d62077b1083..d788fdaf94a 100644 --- a/src/components/Customer/Review/Summary/Summary.test.jsx +++ b/src/components/Customer/Review/Summary/Summary.test.jsx @@ -667,6 +667,7 @@ describe('Summary page', () => { expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTSR); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.BOAT); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.MOBILE_HOME); + expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE); }); it('add shipment modal displays still in dev mode', async () => { @@ -699,6 +700,7 @@ describe('Summary page', () => { expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTSR); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.BOAT); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.MOBILE_HOME); + expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE); }); }); afterEach(jest.clearAllMocks); From db8f79b2c357cb6dc28a5cceaf9258467c736afd Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 20:14:04 +0000 Subject: [PATCH 06/15] fix failing shipmentlist test --- src/components/ShipmentList/ShipmentList.test.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ShipmentList/ShipmentList.test.jsx b/src/components/ShipmentList/ShipmentList.test.jsx index fb93e786f9b..4dd3fccb8bb 100644 --- a/src/components/ShipmentList/ShipmentList.test.jsx +++ b/src/components/ShipmentList/ShipmentList.test.jsx @@ -24,7 +24,7 @@ describe('ShipmentList component', () => { { id: 'ID-2', shipmentType: SHIPMENT_OPTIONS.HHG }, { id: 'ID-3', shipmentType: SHIPMENT_OPTIONS.NTS }, { id: 'ID-4', shipmentType: SHIPMENT_OPTIONS.NTSR }, - { id: 'ID-4', shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE }, + { id: 'ID-5', shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE }, ]; const onShipmentClick = jest.fn(); const onDeleteClick = jest.fn(); @@ -76,7 +76,7 @@ describe('ShipmentList component', () => { await checkShipmentClick('ID-4', 1, SHIPMENT_OPTIONS.NTSR); editBtn = queryByRole(screen.getAllByTestId('shipment-list-item-container')[4], 'button', { name: 'Edit' }); - await checkShipmentClick('ID-4', 1, SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE); + await checkShipmentClick('ID-5', 1, SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE); }); it.each([ From 0497a44ab131451ffb0fc673995d7a4e4b6e814a Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 19:07:38 +0000 Subject: [PATCH 07/15] shipment card, container, mtoshipmentform updates --- .../Customer/Home/Step/Step.stories.jsx | 1 + .../MtoShipmentForm/MtoShipmentForm.jsx | 19 +- .../MtoShipmentForm.stories.jsx | 7 + .../MtoShipmentForm/MtoShipmentForm.test.jsx | 953 ++++++++++++++++++ .../MtoShipmentForm/getShipmentOptions.js | 7 + .../Customer/Review/Summary/Summary.jsx | 31 + .../Customer/Review/Summary/Summary.test.jsx | 4 + .../ShipmentContainer/ShipmentContainer.jsx | 1 + .../ShipmentContainer.test.jsx | 1 + src/components/ShipmentList/ShipmentList.jsx | 1 + .../ShipmentList/ShipmentList.module.scss | 4 + .../ShipmentList/ShipmentList.test.jsx | 8 +- src/constants/shipments.js | 3 + src/content/shipments.js | 1 + src/shared/constants.js | 5 + src/shared/styles/colors.scss | 2 +- 16 files changed, 1041 insertions(+), 7 deletions(-) diff --git a/src/components/Customer/Home/Step/Step.stories.jsx b/src/components/Customer/Home/Step/Step.stories.jsx index 0e807fa0527..c323c98ff9d 100644 --- a/src/components/Customer/Home/Step/Step.stories.jsx +++ b/src/components/Customer/Home/Step/Step.stories.jsx @@ -119,6 +119,7 @@ Shipments.args = { weightTickets: [], }, }, + { id: '0004', shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE }, ]} onShipmentClick={action('shipment edit icon clicked')} moveSubmitted={false} diff --git a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.jsx b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.jsx index 20c62106ef0..42282fc9cd3 100644 --- a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.jsx +++ b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.jsx @@ -190,8 +190,9 @@ class MtoShipmentForm extends Component { const isNTSR = shipmentType === SHIPMENT_OPTIONS.NTSR; const isBoat = shipmentType === SHIPMENT_TYPES.BOAT_HAUL_AWAY || shipmentType === SHIPMENT_TYPES.BOAT_TOW_AWAY; const isMobileHome = shipmentType === SHIPMENT_TYPES.MOBILE_HOME; + const isUB = shipmentType === SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE; const shipmentNumber = - shipmentType === SHIPMENT_OPTIONS.HHG || isBoat || isMobileHome ? this.getShipmentNumber() : null; + shipmentType === SHIPMENT_OPTIONS.HHG || isBoat || isMobileHome || isUB ? this.getShipmentNumber() : null; const isRetireeSeparatee = orders.orders_type === ORDERS_TYPE.RETIREMENT || orders.orders_type === ORDERS_TYPE.SEPARATION; @@ -314,10 +315,18 @@ class MtoShipmentForm extends Component {

{shipmentForm.header[`${shipmentType}`]}

- - Remember: You can move {formatWeight(orders.authorizedWeight)} total. You’ll be billed for any - excess weight you move. - + {!isUB && ( + + Remember: You can move {formatWeight(orders.authorizedWeight)} total. You’ll be billed for any + excess weight you move. + + )} + {isUB && ( + + Remember: You can move up to your UB allowance for this move. You’ll be billed for any excess + weight you move. + + )} {showPickupFields && ( diff --git a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.stories.jsx b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.stories.jsx index a3f5994a02f..173604f1ceb 100644 --- a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.stories.jsx +++ b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.stories.jsx @@ -95,6 +95,7 @@ export const HHGShipmentRetiree = () => renderStory({ shipmentType: SHIPMENT_OPTIONS.HHG, orders: { orders_type: 'RETIREMENT', authorizedWeight: 5000 } }); export const NTSReleaseShipment = () => renderStory({ shipmentType: SHIPMENT_OPTIONS.NTSR }); export const NTSShipment = () => renderStory({ shipmentType: SHIPMENT_OPTIONS.NTS }); +export const UBShipment = () => renderStory({ shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE }); // edit shipment stories (form should prefill) export const EditHHGShipment = () => @@ -115,6 +116,12 @@ export const EditNTSShipment = () => isCreatePage: false, mtoShipment: mockMtoShipment, }); +export const EditUBShipment = () => + renderStory({ + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + isCreatePage: false, + mtoShipment: mockMtoShipment, + }); export const EditShipmentAsSeparatee = () => renderStory({ diff --git a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.test.jsx b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.test.jsx index 89dbe86cc40..664fd8b521b 100644 --- a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.test.jsx +++ b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.test.jsx @@ -62,6 +62,33 @@ const defaultProps = { shipmentType: SHIPMENT_OPTIONS.HHG, }; +const ubProps = { + isCreatePage: true, + pageList: ['page1', 'anotherPage/:foo/:bar'], + pageKey: 'page1', + showLoggedInUser: jest.fn(), + createMTOShipment: jest.fn(), + updateMTOShipment: jest.fn(), + dateSelectionIsWeekendHoliday: jest.fn().mockImplementation(() => Promise.resolve()), + newDutyLocationAddress: { + city: 'Fort Benning', + state: 'GA', + postalCode: '31905', + }, + currentResidence: { + city: 'Fort Benning', + state: 'GA', + postalCode: '31905', + streetAddress1: '123 Main', + streetAddress2: '', + }, + orders: { + orders_type: 'PERMANENT_CHANGE_OF_STATION', + has_dependents: false, + }, + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, +}; + const reviewPath = generatePath(customerRoutes.MOVE_REVIEW_PATH, { moveId }); beforeEach(jest.resetAllMocks); @@ -73,6 +100,13 @@ const renderMtoShipmentForm = (props) => { }); }; +const renderUBShipmentForm = (props) => { + return renderWithRouter(, { + path: customerRoutes.SHIPMENT_CREATE_PATH, + params: { moveId }, + }); +}; + describe('MtoShipmentForm component', () => { describe('when creating a new HHG shipment', () => { it('renders the HHG shipment form', async () => { @@ -1000,6 +1034,925 @@ describe('MtoShipmentForm component', () => { }); }); + describe('when creating a new UB shipment', () => { + it('renders the UB shipment form', async () => { + renderUBShipmentForm(); + + expect(await screen.findByText('UB')).toHaveClass('usa-tag'); + + expect(screen.getAllByText('Date')[0]).toBeInstanceOf(HTMLLegendElement); + expect(screen.getByLabelText(/Preferred pickup date/)).toBeInstanceOf(HTMLInputElement); + expect(screen.getByRole('heading', { level: 2, name: 'Pickup info' })).toBeInTheDocument(); + expect(screen.getByTestId('pickupDateHint')).toHaveTextContent( + 'This is the day movers would put this shipment on their truck. Packing starts earlier. Dates will be finalized when you talk to your Customer Care Representative. Your requested pickup/load date should be your latest preferred pickup/load date, or the date you need to be out of your origin residence.', + ); + expect(screen.getByText('Pickup location')).toBeInstanceOf(HTMLLegendElement); + expect(screen.getByLabelText('Use my current address')).toBeInstanceOf(HTMLInputElement); + expect(screen.getByLabelText(/Address 1/)).toBeInstanceOf(HTMLInputElement); + expect(screen.getByLabelText(/Address 2/)).toBeInstanceOf(HTMLInputElement); + expect(screen.getByLabelText(/City/)).toBeInstanceOf(HTMLInputElement); + expect(screen.getByLabelText(/State/)).toBeInstanceOf(HTMLSelectElement); + expect(screen.getByLabelText(/ZIP/)).toBeInstanceOf(HTMLInputElement); + + expect(screen.getByRole('heading', { level: 4, name: 'Second pickup location' })).toBeInTheDocument(); + expect(screen.getByTitle('Yes, I have a second pickup location')).toBeInstanceOf(HTMLInputElement); + expect(screen.getByTitle('No, I do not have a second pickup location')).toBeInstanceOf(HTMLInputElement); + + expect(screen.getByText(/Releasing agent/).parentElement).toBeInstanceOf(HTMLLegendElement); + expect(screen.getAllByLabelText(/First name/)[0]).toHaveAttribute('name', 'pickup.agent.firstName'); + expect(screen.getAllByLabelText(/Last name/)[0]).toHaveAttribute('name', 'pickup.agent.lastName'); + expect(screen.getAllByLabelText(/Phone/)[0]).toHaveAttribute('name', 'pickup.agent.phone'); + expect(screen.getAllByLabelText(/Email/)[0]).toHaveAttribute('name', 'pickup.agent.email'); + + expect(screen.getAllByText('Date')[1]).toBeInstanceOf(HTMLLegendElement); + expect(screen.getByLabelText(/Preferred delivery date/)).toBeInstanceOf(HTMLInputElement); + + expect(screen.getByText(/Delivery location/)).toBeInstanceOf(HTMLLegendElement); + expect(screen.getByTitle('Yes, I know my delivery address')).toBeInstanceOf(HTMLInputElement); + expect(screen.getByTitle('No, I do not know my delivery address')).toBeInstanceOf(HTMLInputElement); + + expect(screen.queryByRole('heading', { level: 4, name: 'Second Destination Location' })).not.toBeInTheDocument(); + expect(screen.queryByTitle('Yes, I have a second destination location')).not.toBeInTheDocument(); + expect(screen.queryByTitle('No, I do not have a second destination location')).not.toBeInTheDocument(); + + expect(screen.getByText(/Receiving agent/).parentElement).toBeInstanceOf(HTMLLegendElement); + expect(screen.getAllByLabelText(/First name/)[1]).toHaveAttribute('name', 'delivery.agent.firstName'); + expect(screen.getAllByLabelText(/Last name/)[1]).toHaveAttribute('name', 'delivery.agent.lastName'); + expect(screen.getAllByLabelText(/Phone/)[1]).toHaveAttribute('name', 'delivery.agent.phone'); + expect(screen.getAllByLabelText(/Email/)[1]).toHaveAttribute('name', 'delivery.agent.email'); + + expect( + screen.queryByText( + 'Details about the facility where your things are now, including the name or address (if you know them)', + ), + ).not.toBeInTheDocument(); + + expect( + screen.getByLabelText( + 'Are there things about this shipment that your counselor or movers should discuss with you?', + ), + ).toBeInstanceOf(HTMLTextAreaElement); + }); + + it('renders the correct helper text for Delivery Location when orders type is RETIREMENT', async () => { + renderUBShipmentForm({ orders: { orders_type: ORDERS_TYPE.RETIREMENT } }); + await waitFor(() => + expect( + screen.getByText('We can use the zip of the HOR, PLEAD or HOS you entered with your orders.') + .toBeInTheDocument, + ), + ); + }); + + it('renders the correct helper text for Delivery Location when orders type is SEPARATION', async () => { + renderUBShipmentForm({ orders: { orders_type: ORDERS_TYPE.SEPARATION } }); + await waitFor(() => + expect( + screen.getByText('We can use the zip of the HOR, PLEAD or HOS you entered with your orders.') + .toBeInTheDocument, + ), + ); + }); + + it('renders the correct helper text for Delivery Location when orders type is PERMANENT_CHANGE_OF_STATION', async () => { + renderUBShipmentForm({ orders: { orders_type: ORDERS_TYPE.PERMANENT_CHANGE_OF_STATION } }); + await waitFor(() => expect(screen.getByText(/We can use the zip of your new duty location./).toBeInTheDocument)); + }); + + it('renders the correct helper text for Delivery Location when orders type is LOCAL_MOVE', async () => { + renderUBShipmentForm({ orders: { orders_type: ORDERS_TYPE.LOCAL_MOVE } }); + await waitFor(() => expect(screen.getByText(/We can use the zip of your new duty location./).toBeInTheDocument)); + }); + + it('does not render special NTS What to expect section', async () => { + const { queryByTestId } = renderUBShipmentForm(); + + await waitFor(() => { + expect(queryByTestId('nts-what-to-expect')).not.toBeInTheDocument(); + }); + }); + + it('uses the current residence address for pickup address when checked', async () => { + const { queryByLabelText, queryAllByLabelText } = renderUBShipmentForm(); + + await userEvent.click(queryByLabelText('Use my current address')); + + await waitFor(() => { + expect(queryAllByLabelText(/Address 1/)[0]).toHaveValue(defaultProps.currentResidence.streetAddress1); + expect(queryAllByLabelText(/Address 2/)[0]).toHaveValue(''); + expect(queryAllByLabelText(/City/)[0]).toHaveValue(defaultProps.currentResidence.city); + expect(queryAllByLabelText(/State/)[0]).toHaveValue(defaultProps.currentResidence.state); + expect(queryAllByLabelText(/ZIP/)[0]).toHaveValue(defaultProps.currentResidence.postalCode); + }); + }); + + it('renders a second address fieldset when the user has a second pickup address', async () => { + renderUBShipmentForm(); + + await userEvent.click(screen.getByTitle('Yes, I have a second pickup location')); + + const streetAddress1 = await screen.findAllByLabelText(/Address 1/); + expect(streetAddress1[1]).toHaveAttribute('name', 'secondaryPickup.address.streetAddress1'); + + const streetAddress2 = await screen.findAllByLabelText(/Address 2/); + expect(streetAddress2[1]).toHaveAttribute('name', 'secondaryPickup.address.streetAddress2'); + + const city = await screen.findAllByLabelText(/City/); + expect(city[1]).toHaveAttribute('name', 'secondaryPickup.address.city'); + + const state = await screen.findAllByLabelText(/State/); + expect(state[1]).toHaveAttribute('name', 'secondaryPickup.address.state'); + + const zip = await screen.findAllByLabelText(/ZIP/); + expect(zip[1]).toHaveAttribute('name', 'secondaryPickup.address.postalCode'); + }); + + it('renders a second address fieldset when the user has a delivery address', async () => { + renderUBShipmentForm(); + + await userEvent.click(screen.getByTitle('Yes, I know my delivery address')); + + const streetAddress1 = await screen.findAllByLabelText(/Address 1/); + expect(streetAddress1[0]).toHaveAttribute('name', 'pickup.address.streetAddress1'); + expect(streetAddress1[1]).toHaveAttribute('name', 'delivery.address.streetAddress1'); + + const streetAddress2 = await screen.findAllByLabelText(/Address 2/); + expect(streetAddress2[0]).toHaveAttribute('name', 'pickup.address.streetAddress2'); + expect(streetAddress2[1]).toHaveAttribute('name', 'delivery.address.streetAddress2'); + + const city = await screen.findAllByLabelText(/City/); + expect(city[0]).toHaveAttribute('name', 'pickup.address.city'); + expect(city[1]).toHaveAttribute('name', 'delivery.address.city'); + + const state = await screen.findAllByLabelText(/State/); + expect(state[0]).toHaveAttribute('name', 'pickup.address.state'); + expect(state[1]).toHaveAttribute('name', 'delivery.address.state'); + + const zip = await screen.findAllByLabelText(/ZIP/); + expect(zip[0]).toHaveAttribute('name', 'pickup.address.postalCode'); + expect(zip[1]).toHaveAttribute('name', 'delivery.address.postalCode'); + }); + + it('renders the secondary destination address question once a user says they have a primary destination address', async () => { + renderUBShipmentForm(); + + expect(screen.queryByRole('heading', { level: 4, name: 'Second Destination Location' })).not.toBeInTheDocument(); + expect(screen.queryByTitle('Yes, I have a second destination location')).not.toBeInTheDocument(); + expect(screen.queryByTitle('No, I do not have a second destination location')).not.toBeInTheDocument(); + + await userEvent.click(screen.getByTitle('Yes, I know my delivery address')); + + expect(await screen.findByRole('heading', { level: 4, name: 'Second delivery location' })).toBeInTheDocument(); + expect(screen.getByTitle('Yes, I have a second destination location')).toBeInstanceOf(HTMLInputElement); + expect(screen.getByTitle('No, I do not have a second destination location')).toBeInstanceOf(HTMLInputElement); + }); + + it('renders another address fieldset when the user has a second destination address', async () => { + renderUBShipmentForm(); + + await userEvent.click(screen.getByTitle('Yes, I know my delivery address')); + await userEvent.click(screen.getByTitle('Yes, I have a second destination location')); + + const streetAddress1 = await screen.findAllByLabelText(/Address 1/); + expect(streetAddress1.length).toBe(3); + expect(streetAddress1[2]).toHaveAttribute('name', 'secondaryDelivery.address.streetAddress1'); + + const streetAddress2 = await screen.findAllByLabelText(/Address 2/); + expect(streetAddress2.length).toBe(3); + expect(streetAddress2[2]).toHaveAttribute('name', 'secondaryDelivery.address.streetAddress2'); + + const city = await screen.findAllByLabelText(/City/); + expect(city.length).toBe(3); + expect(city[2]).toHaveAttribute('name', 'secondaryDelivery.address.city'); + + const state = await screen.findAllByLabelText(/State/); + expect(state.length).toBe(3); + expect(state[2]).toHaveAttribute('name', 'secondaryDelivery.address.state'); + + const zip = await screen.findAllByLabelText(/ZIP/); + expect(zip.length).toBe(3); + expect(zip[2]).toHaveAttribute('name', 'secondaryDelivery.address.postalCode'); + }); + + it('goes back when the back button is clicked', async () => { + renderUBShipmentForm(); + + const backButton = await screen.findByRole('button', { name: 'Back' }); + await userEvent.click(backButton); + + await waitFor(() => { + expect(mockNavigate).toHaveBeenCalledWith(-1); + }); + }); + + it('can submit a new UB shipment successfully', async () => { + const shipmentInfo = { + requestedPickupDate: '07 Jun 2021', + pickupAddress: { + streetAddress1: '812 S 129th St', + streetAddress2: '#123', + city: 'San Antonio', + state: 'TX', + postalCode: '78234', + }, + requestedDeliveryDate: '14 Jun 2021', + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + }; + + const expectedPayload = { + agents: [ + { agentType: 'RELEASING_AGENT', email: '', firstName: '', lastName: '', phone: '' }, + { agentType: 'RECEIVING_AGENT', email: '', firstName: '', lastName: '', phone: '' }, + ], + moveTaskOrderID: moveId, + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + customerRemarks: '', + requestedPickupDate: '2021-06-07', + pickupAddress: { ...shipmentInfo.pickupAddress }, + requestedDeliveryDate: '2021-06-14', + hasSecondaryPickupAddress: false, + hasSecondaryDeliveryAddress: false, + hasTertiaryPickupAddress: false, + hasTertiaryDeliveryAddress: false, + }; + + const updatedAt = '2021-06-11T18:12:11.918Z'; + const expectedCreateResponse = { + createdAt: '2021-06-11T18:12:11.918Z', + customerRemarks: '', + eTag: window.btoa(updatedAt), + id: uuidv4(), + moveTaskOrderID: moveId, + pickupAddress: { ...shipmentInfo.pickupAddress, id: uuidv4() }, + requestedDeliveryDate: expectedPayload.requestedDeliveryDate, + requestedPickupDate: expectedPayload.requestedPickupDate, + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + status: 'SUBMITTED', + updatedAt, + }; + + createMTOShipment.mockImplementation(() => Promise.resolve(expectedCreateResponse)); + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: false, + is_holiday: false, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm(); + + const pickupDateInput = await screen.findByLabelText(/Preferred pickup date/); + await userEvent.type(pickupDateInput, shipmentInfo.requestedPickupDate); + + const pickupAddress1Input = screen.getByLabelText(/Address 1/); + await userEvent.type(pickupAddress1Input, shipmentInfo.pickupAddress.streetAddress1); + + const pickupAddress2Input = screen.getByLabelText(/Address 2/); + await userEvent.type(pickupAddress2Input, shipmentInfo.pickupAddress.streetAddress2); + + const pickupCityInput = screen.getByLabelText(/City/); + await userEvent.type(pickupCityInput, shipmentInfo.pickupAddress.city); + + const pickupStateInput = screen.getByLabelText(/State/); + await userEvent.selectOptions(pickupStateInput, shipmentInfo.pickupAddress.state); + + const pickupPostalCodeInput = screen.getByLabelText(/ZIP/); + await userEvent.type(pickupPostalCodeInput, shipmentInfo.pickupAddress.postalCode); + + const deliveryDateInput = await screen.findByLabelText(/Preferred delivery date/); + await userEvent.type(deliveryDateInput, shipmentInfo.requestedDeliveryDate); + + const nextButton = await screen.findByRole('button', { name: 'Next' }); + expect(nextButton).not.toBeDisabled(); + await userEvent.click(nextButton); + + await waitFor(() => { + expect(createMTOShipment).toHaveBeenCalledWith(expectedPayload); + }); + + expect(ubProps.updateMTOShipment).toHaveBeenCalledWith(expectedCreateResponse); + + expect(mockNavigate).toHaveBeenCalledWith(reviewPath); + }); + + it('shows an error when there is an error with the submission', async () => { + const shipmentInfo = { + requestedPickupDate: '07 Jun 2021', + pickupAddress: { + streetAddress1: '812 S 129th St', + streetAddress2: '#123', + city: 'San Antonio', + state: 'TX', + postalCode: '78234', + }, + requestedDeliveryDate: '14 Jun 2021', + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + }; + + const errorMessage = 'Something broke!'; + const errorResponse = { response: { errorMessage } }; + createMTOShipment.mockImplementation(() => Promise.reject(errorResponse)); + getResponseError.mockImplementation(() => errorMessage); + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm(); + + const pickupDateInput = await screen.findByLabelText(/Preferred pickup date/); + await userEvent.type(pickupDateInput, shipmentInfo.requestedPickupDate); + + const pickupAddress1Input = screen.getByLabelText(/Address 1/); + await userEvent.type(pickupAddress1Input, shipmentInfo.pickupAddress.streetAddress1); + + const pickupAddress2Input = screen.getByLabelText(/Address 2/); + await userEvent.type(pickupAddress2Input, shipmentInfo.pickupAddress.streetAddress2); + + const pickupCityInput = screen.getByLabelText(/City/); + await userEvent.type(pickupCityInput, shipmentInfo.pickupAddress.city); + + const pickupStateInput = screen.getByLabelText(/State/); + await userEvent.selectOptions(pickupStateInput, shipmentInfo.pickupAddress.state); + + const pickupPostalCodeInput = screen.getByLabelText(/ZIP/); + await userEvent.type(pickupPostalCodeInput, shipmentInfo.pickupAddress.postalCode); + + const deliveryDateInput = await screen.findByLabelText(/Preferred delivery date/); + await userEvent.type(deliveryDateInput, shipmentInfo.requestedDeliveryDate); + + const nextButton = await screen.findByRole('button', { name: 'Next' }); + expect(nextButton).not.toBeDisabled(); + await userEvent.click(nextButton); + + await waitFor(() => { + expect(createMTOShipment).toHaveBeenCalled(); + }); + + expect(getResponseError).toHaveBeenCalledWith( + errorResponse.response, + 'failed to create MTO shipment due to server error', + ); + + expect(await screen.findByText(errorMessage)).toBeInTheDocument(); + }); + }); + + describe('editing an already existing UB shipment', () => { + const updatedAt = '2021-06-11T18:12:11.918Z'; + + const mockMtoShipment = { + id: uuidv4(), + eTag: window.btoa(updatedAt), + createdAt: '2021-06-11T18:12:11.918Z', + updatedAt, + moveTaskOrderId: moveId, + customerRemarks: 'mock remarks', + requestedPickupDate: '2021-08-01', + requestedDeliveryDate: '2021-08-11', + pickupAddress: { + id: uuidv4(), + streetAddress1: '812 S 129th St', + city: 'San Antonio', + state: 'TX', + postalCode: '78234', + }, + destinationAddress: { + id: uuidv4(), + streetAddress1: '441 SW Rio de la Plata Drive', + city: 'Tacoma', + state: 'WA', + postalCode: '98421', + }, + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + }; + + it('renders the UB shipment form with pre-filled values', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + + expect(await screen.findByLabelText(/Preferred pickup date/)).toHaveValue('01 Aug 2021'); + expect(screen.getByLabelText('Use my current address')).not.toBeChecked(); + expect(screen.getAllByLabelText(/Address 1/)[0]).toHaveValue('812 S 129th St'); + expect(screen.getAllByLabelText(/Address 2/)[0]).toHaveValue(''); + expect(screen.getAllByLabelText(/City/)[0]).toHaveValue('San Antonio'); + expect(screen.getAllByLabelText(/State/)[0]).toHaveValue('TX'); + expect(screen.getAllByLabelText(/ZIP/)[0]).toHaveValue('78234'); + expect(screen.getByLabelText(/Preferred delivery date/)).toHaveValue('11 Aug 2021'); + expect(screen.getByTitle('Yes, I know my delivery address')).toBeChecked(); + expect(screen.getAllByLabelText(/Address 1/)[1]).toHaveValue('441 SW Rio de la Plata Drive'); + expect(screen.getAllByLabelText(/Address 2/)[1]).toHaveValue(''); + expect(screen.getAllByLabelText(/City/)[1]).toHaveValue('Tacoma'); + expect(screen.getAllByLabelText(/State/)[1]).toHaveValue('WA'); + expect(screen.getAllByLabelText(/ZIP/)[1]).toHaveValue('98421'); + expect( + screen.getByLabelText( + 'Are there things about this shipment that your counselor or movers should discuss with you?', + ), + ).toHaveValue('mock remarks'); + + expect( + screen.getByText( + /Preferred pickup date 01 Aug 2021 is on a holiday and weekend in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + expect( + screen.getAllByText( + 'Preferred pickup date 01 Aug 2021 is on a holiday and weekend in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date.', + ), + ).toHaveLength(1); + }); + + it('renders the UB shipment form with pre-filled secondary addresses', async () => { + const shipment = { + ...mockMtoShipment, + secondaryPickupAddress: { + streetAddress1: '142 E Barrel Hoop Circle', + streetAddress2: '#4A', + city: 'Corpus Christi', + state: 'TX', + postalCode: '78412', + }, + secondaryDeliveryAddress: { + streetAddress1: '3373 NW Martin Luther King Jr Blvd', + streetAddress2: '', + city: mockMtoShipment.destinationAddress.city, + state: mockMtoShipment.destinationAddress.state, + postalCode: mockMtoShipment.destinationAddress.postalCode, + }, + }; + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: shipment }); + + expect(await screen.findByTitle('Yes, I have a second pickup location')).toBeChecked(); + expect(await screen.findByTitle('Yes, I have a second destination location')).toBeChecked(); + + const streetAddress1 = await screen.findAllByLabelText(/Address 1/); + expect(streetAddress1.length).toBe(4); + + const streetAddress2 = await screen.findAllByLabelText(/Address 2/); + expect(streetAddress2.length).toBe(4); + + const city = await screen.findAllByLabelText(/City/); + expect(city.length).toBe(4); + + const state = await screen.findAllByLabelText(/State/); + expect(state.length).toBe(4); + + const zip = await screen.findAllByLabelText(/ZIP/); + expect(zip.length).toBe(4); + + // Secondary pickup address should be the 2nd address + expect(streetAddress1[1]).toHaveValue('142 E Barrel Hoop Circle'); + expect(streetAddress2[1]).toHaveValue('#4A'); + expect(city[1]).toHaveValue('Corpus Christi'); + expect(state[1]).toHaveValue('TX'); + expect(zip[1]).toHaveValue('78412'); + + // Secondary delivery address should be the 4th address + expect(streetAddress1[3]).toHaveValue('3373 NW Martin Luther King Jr Blvd'); + expect(streetAddress2[3]).toHaveValue(''); + expect(city[3]).toHaveValue(mockMtoShipment.destinationAddress.city); + expect(state[3]).toHaveValue(mockMtoShipment.destinationAddress.state); + expect(zip[3]).toHaveValue(mockMtoShipment.destinationAddress.postalCode); + }); + + it.each([ + [/Address 1/, 'Some Address'], + [/Address 2/, '123'], + [/City/, 'Some City'], + [/ZIP/, '92131'], + ])( + 'does not allow the user to save the form if the %s field on a secondary addreess is the only one filled out', + async (fieldName, text) => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: false, + is_holiday: false, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + + // Verify that the form is good to submit by checking that the save button is not disabled. + const saveButton = await screen.findByRole('button', { name: 'Save' }); + expect(saveButton).not.toBeDisabled(); + + await userEvent.click(screen.getByTitle('Yes, I have a second pickup location')); + await userEvent.click(screen.getByTitle('Yes, I have a second destination location')); + + const address = await screen.findAllByLabelText(fieldName); + // The second instance of a field is the secondary pickup + await userEvent.type(address[1], text); + await waitFor(() => { + expect(saveButton).toBeDisabled(); + }); + + // Clear the field so that the secondary delivery address can be checked + await userEvent.clear(address[1]); + await waitFor(() => { + expect(saveButton).not.toBeDisabled(); + }); + + // The fourth instance found is the secondary delivery + await userEvent.type(address[3], text); + await waitFor(() => { + expect(saveButton).toBeDisabled(); + }); + + await userEvent.clear(address[3]); + await waitFor(() => { + expect(saveButton).not.toBeDisabled(); + }); + }, + ); + + // Similar test as above, but with the state input. + // Extracted out since the state field is not a text input. + it('does not allow the user to save the form if the state field on a secondary addreess is the only one filled out', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: false, + is_holiday: false, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + + // Verify that the form is good to submit by checking that the save button is not disabled. + const saveButton = await screen.findByRole('button', { name: 'Save' }); + expect(saveButton).not.toBeDisabled(); + + await userEvent.click(screen.getByTitle('Yes, I have a second pickup location')); + await userEvent.click(screen.getByTitle('Yes, I have a second destination location')); + + const state = await screen.findAllByLabelText(/State/); + // The second instance of a field is the secondary pickup + await userEvent.selectOptions(state[1], 'CA'); + await waitFor(() => { + expect(saveButton).toBeDisabled(); + }); + + // Change the selection to blank so that the secondary delivery address can be checked + await userEvent.selectOptions(state[1], ''); + await waitFor(() => { + expect(saveButton).not.toBeDisabled(); + }); + + // The fourth instance found is the secondary delivery + await userEvent.selectOptions(state[3], 'CA'); + await waitFor(() => { + expect(saveButton).toBeDisabled(); + }); + + await userEvent.selectOptions(state[3], ''); + await waitFor(() => { + expect(saveButton).not.toBeDisabled(); + }); + }); + + it('goes back when the cancel button is clicked', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + + const cancelButton = await screen.findByRole('button', { name: 'Cancel' }); + await userEvent.click(cancelButton); + + await waitFor(() => { + expect(mockNavigate).toHaveBeenCalledWith(-1); + }); + }); + + it('can submit edits to a UB shipment successfully', async () => { + const shipmentInfo = { + pickupAddress: { + streetAddress1: '6622 Airport Way S', + streetAddress2: '#1430', + city: 'San Marcos', + state: 'TX', + postalCode: '78666', + }, + }; + + const expectedPayload = { + moveTaskOrderID: moveId, + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + pickupAddress: { ...shipmentInfo.pickupAddress }, + customerRemarks: mockMtoShipment.customerRemarks, + requestedPickupDate: mockMtoShipment.requestedPickupDate, + requestedDeliveryDate: mockMtoShipment.requestedDeliveryDate, + destinationAddress: { ...mockMtoShipment.destinationAddress, streetAddress2: '' }, + secondaryDeliveryAddress: undefined, + hasSecondaryDeliveryAddress: false, + secondaryPickupAddress: undefined, + hasSecondaryPickupAddress: false, + tertiaryDeliveryAddress: undefined, + hasTertiaryDeliveryAddress: false, + tertiaryPickupAddress: undefined, + hasTertiaryPickupAddress: false, + agents: [ + { agentType: 'RELEASING_AGENT', email: '', firstName: '', lastName: '', phone: '' }, + { agentType: 'RECEIVING_AGENT', email: '', firstName: '', lastName: '', phone: '' }, + ], + counselorRemarks: undefined, + }; + delete expectedPayload.destinationAddress.id; + + const newUpdatedAt = '2021-06-11T21:20:22.150Z'; + const expectedUpdateResponse = { + ...mockMtoShipment, + pickupAddress: { ...shipmentInfo.pickupAddress }, + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + eTag: window.btoa(newUpdatedAt), + status: 'SUBMITTED', + }; + + patchMTOShipment.mockImplementation(() => Promise.resolve(expectedUpdateResponse)); + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + + const pickupAddress1Input = screen.getAllByLabelText(/Address 1/)[0]; + await userEvent.clear(pickupAddress1Input); + await userEvent.type(pickupAddress1Input, shipmentInfo.pickupAddress.streetAddress1); + + const pickupAddress2Input = screen.getAllByLabelText(/Address 2/)[0]; + await userEvent.clear(pickupAddress2Input); + await userEvent.type(pickupAddress2Input, shipmentInfo.pickupAddress.streetAddress2); + + const pickupCityInput = screen.getAllByLabelText(/City/)[0]; + await userEvent.clear(pickupCityInput); + await userEvent.type(pickupCityInput, shipmentInfo.pickupAddress.city); + + const pickupStateInput = screen.getAllByLabelText(/State/)[0]; + await userEvent.selectOptions(pickupStateInput, shipmentInfo.pickupAddress.state); + + const pickupPostalCodeInput = screen.getAllByLabelText(/ZIP/)[0]; + await userEvent.clear(pickupPostalCodeInput); + await userEvent.type(pickupPostalCodeInput, shipmentInfo.pickupAddress.postalCode); + + const saveButton = await screen.findByRole('button', { name: 'Save' }); + expect(saveButton).not.toBeDisabled(); + await userEvent.click(saveButton); + + await waitFor(() => { + expect(patchMTOShipment).toHaveBeenCalledWith(mockMtoShipment.id, expectedPayload, mockMtoShipment.eTag); + }); + + expect(ubProps.updateMTOShipment).toHaveBeenCalledWith(expectedUpdateResponse); + + expect(mockNavigate).toHaveBeenCalledWith(reviewPath); + }); + + it('shows an error when there is an error with the submission', async () => { + const shipmentInfo = { + pickupAddress: { + streetAddress1: '6622 Airport Way S', + streetAddress2: '#1430', + city: 'San Marcos', + state: 'TX', + postalCode: '78666', + }, + }; + + const errorMessage = 'Something broke!'; + const errorResponse = { response: { errorMessage } }; + patchMTOShipment.mockImplementation(() => Promise.reject(errorResponse)); + getResponseError.mockImplementation(() => errorMessage); + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + + const pickupAddress1Input = screen.getAllByLabelText(/Address 1/)[0]; + await userEvent.clear(pickupAddress1Input); + await userEvent.type(pickupAddress1Input, shipmentInfo.pickupAddress.streetAddress1); + + const pickupAddress2Input = screen.getAllByLabelText(/Address 2/)[0]; + await userEvent.clear(pickupAddress2Input); + await userEvent.type(pickupAddress2Input, shipmentInfo.pickupAddress.streetAddress2); + + const pickupCityInput = screen.getAllByLabelText(/City/)[0]; + await userEvent.clear(pickupCityInput); + await userEvent.type(pickupCityInput, shipmentInfo.pickupAddress.city); + + const pickupStateInput = screen.getAllByLabelText(/State/)[0]; + await userEvent.selectOptions(pickupStateInput, shipmentInfo.pickupAddress.state); + + const pickupPostalCodeInput = screen.getAllByLabelText(/ZIP/)[0]; + await userEvent.clear(pickupPostalCodeInput); + await userEvent.type(pickupPostalCodeInput, shipmentInfo.pickupAddress.postalCode); + + const saveButton = await screen.findByRole('button', { name: 'Save' }); + expect(saveButton).not.toBeDisabled(); + await userEvent.click(saveButton); + + await waitFor(() => { + expect(patchMTOShipment).toHaveBeenCalled(); + }); + + expect(getResponseError).toHaveBeenCalledWith( + errorResponse.response, + 'failed to update MTO shipment due to server error', + ); + + expect(await screen.findByText(errorMessage)).toBeInTheDocument(); + }); + + it('renders the UB shipment form with pre-filled values', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + expect(await screen.findByLabelText(/Preferred pickup date/)).toHaveValue('01 Aug 2021'); + expect(screen.getByLabelText('Use my current address')).not.toBeChecked(); + expect(screen.getAllByLabelText(/Address 1/)[0]).toHaveValue('812 S 129th St'); + expect(screen.getAllByLabelText(/Address 2/)[0]).toHaveValue(''); + expect(screen.getAllByLabelText(/City/)[0]).toHaveValue('San Antonio'); + expect(screen.getAllByLabelText(/State/)[0]).toHaveValue('TX'); + expect(screen.getAllByLabelText(/ZIP/)[0]).toHaveValue('78234'); + expect(screen.getByLabelText(/Preferred delivery date/)).toHaveValue('11 Aug 2021'); + expect(screen.getByTitle('Yes, I know my delivery address')).toBeChecked(); + expect(screen.getAllByLabelText(/Address 1/)[1]).toHaveValue('441 SW Rio de la Plata Drive'); + expect(screen.getAllByLabelText(/Address 2/)[1]).toHaveValue(''); + expect(screen.getAllByLabelText(/City/)[1]).toHaveValue('Tacoma'); + expect(screen.getAllByLabelText(/State/)[1]).toHaveValue('WA'); + expect(screen.getAllByLabelText(/ZIP/)[1]).toHaveValue('98421'); + expect( + screen.getByLabelText( + 'Are there things about this shipment that your counselor or movers should discuss with you?', + ), + ).toHaveValue('mock remarks'); + }); + + it('renders the UB shipment with date validaton alerts for weekend and holiday', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United of States', + is_weekend: true, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + expect(await screen.findByLabelText(/Preferred pickup date/)).toHaveValue('01 Aug 2021'); + expect(screen.getByLabelText(/Preferred delivery date/)).toHaveValue('11 Aug 2021'); + await waitFor(() => { + expect( + screen.getByText( + /Preferred pickup date 01 Aug 2021 is on a holiday and weekend in the United of States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + expect( + screen.getByText( + /Preferred delivery date 11 Aug 2021 is on a holiday and weekend in the United of States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + }); + }); + + it('renders the UB shipment with date validaton alerts for weekend', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: true, + is_holiday: false, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + expect(await screen.findByLabelText(/Preferred pickup date/)).toHaveValue('01 Aug 2021'); + expect(screen.getByLabelText(/Preferred delivery date/)).toHaveValue('11 Aug 2021'); + await waitFor(() => { + expect( + screen.getByText( + /Preferred pickup date 01 Aug 2021 is on a weekend in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + expect( + screen.getByText( + /Preferred delivery date 11 Aug 2021 is on a weekend in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + }); + }); + + it('renders the UB shipment with date validaton alerts for holiday', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: false, + is_holiday: true, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + expect(await screen.findByLabelText(/Preferred pickup date/)).toHaveValue('01 Aug 2021'); + expect(screen.getByLabelText(/Preferred delivery date/)).toHaveValue('11 Aug 2021'); + await waitFor(() => { + expect( + screen.getByText( + /Preferred pickup date 01 Aug 2021 is on a holiday in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + expect( + screen.getByText( + /Preferred delivery date 11 Aug 2021 is on a holiday in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date./, + ), + ).toHaveClass('usa-alert__text'); + }); + }); + + it('renders the UB shipment with no date validaton alerts for pickup/delivery', async () => { + const expectedDateSelectionIsWeekendHolidayResponse = { + country_code: 'US', + country_name: 'United States', + is_weekend: false, + is_holiday: false, + }; + dateSelectionIsWeekendHoliday.mockImplementation(() => + Promise.resolve({ data: JSON.stringify(expectedDateSelectionIsWeekendHolidayResponse) }), + ); + renderUBShipmentForm({ isCreatePage: false, mtoShipment: mockMtoShipment }); + expect(await screen.findByLabelText(/Preferred pickup date/)).toHaveValue('01 Aug 2021'); + expect(screen.getByLabelText(/Preferred delivery date/)).toHaveValue('11 Aug 2021'); + expect( + screen.getByLabelText( + 'Are there things about this shipment that your counselor or movers should discuss with you?', + ), + ).toHaveValue('mock remarks'); + + await waitFor(() => { + expect( + screen.queryAllByText( + 'Preferred pickup date 01 Aug 2021 is on a holiday in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date.', + ), + ).toHaveLength(0); + expect( + screen.queryAllByText( + 'Preferred delivery date 11 Aug 2021 is on a holiday in the United States. This date may not be accepted. A government representative may not be available to provide assistance on this date.', + ), + ).toHaveLength(0); + }); + }); + }); + describe('creating a new NTS shipment', () => { it('renders the NTS shipment form', async () => { renderMtoShipmentForm({ shipmentType: SHIPMENT_OPTIONS.NTS }); diff --git a/src/components/Customer/MtoShipmentForm/getShipmentOptions.js b/src/components/Customer/MtoShipmentForm/getShipmentOptions.js index 4d9d391ff36..653a7b4e982 100644 --- a/src/components/Customer/MtoShipmentForm/getShipmentOptions.js +++ b/src/components/Customer/MtoShipmentForm/getShipmentOptions.js @@ -158,6 +158,13 @@ function getShipmentOptions(shipmentType, userRole) { } } + case SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE: + return { + schema: hhgShipmentSchema, + showPickupFields: true, + showDeliveryFields: true, + }; + default: throw new Error('unrecognized shipment type'); } diff --git a/src/components/Customer/Review/Summary/Summary.jsx b/src/components/Customer/Review/Summary/Summary.jsx index 2bafeb88b1a..924e172336b 100644 --- a/src/components/Customer/Review/Summary/Summary.jsx +++ b/src/components/Customer/Review/Summary/Summary.jsx @@ -172,6 +172,7 @@ export class Summary extends Component { let ppmShipmentNumber = 0; let boatShipmentNumber = 0; let mobileHomeShipmentNumber = 0; + let ubShipmentNumber = 0; return sortedShipments.map((shipment) => { let receivingAgent; let releasingAgent; @@ -302,6 +303,36 @@ export class Summary extends Component { /> ); } + if (shipment.shipmentType === SHIPMENT_TYPES.UNACCOMPANIED_BAGGAGE) { + ubShipmentNumber += 1; + return ( + + ); + } hhgShipmentNumber += 1; return ( { expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTS); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTSR); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.BOAT); + expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.MOBILE_HOME); + expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE); }); it('add shipment modal displays still in dev mode', async () => { @@ -697,6 +699,8 @@ describe('Summary page', () => { expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTS); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTSR); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.BOAT); + expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.MOBILE_HOME); + expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE); }); }); afterEach(jest.clearAllMocks); diff --git a/src/components/Office/ShipmentContainer/ShipmentContainer.jsx b/src/components/Office/ShipmentContainer/ShipmentContainer.jsx index 3231860de51..615ae4a0b12 100644 --- a/src/components/Office/ShipmentContainer/ShipmentContainer.jsx +++ b/src/components/Office/ShipmentContainer/ShipmentContainer.jsx @@ -21,6 +21,7 @@ const ShipmentContainer = ({ id, className, children, shipmentType }) => { 'container--accent--ppm': shipmentType === SHIPMENT_OPTIONS.PPM, 'container--accent--boat': shipmentType === SHIPMENT_OPTIONS.BOAT, 'container--accent--mobilehome': shipmentType === SHIPMENT_OPTIONS.MOBILE_HOME, + 'container--accent--ub': shipmentType === SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, }, className, ); diff --git a/src/components/Office/ShipmentContainer/ShipmentContainer.test.jsx b/src/components/Office/ShipmentContainer/ShipmentContainer.test.jsx index b7fc2fa74ef..2b8f6d0729d 100644 --- a/src/components/Office/ShipmentContainer/ShipmentContainer.test.jsx +++ b/src/components/Office/ShipmentContainer/ShipmentContainer.test.jsx @@ -59,6 +59,7 @@ describe('Shipment Container', () => { [SHIPMENT_OPTIONS.HHG, 'container--accent--hhg'], [SHIPMENT_OPTIONS.NTS, 'container--accent--nts'], [SHIPMENT_OPTIONS.NTSR, 'container--accent--ntsr'], + [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, 'container--accent--ub'], ])('renders a container for a shipment (%s) with className %s ', async (shipmentType, expectedClass) => { const newHeadingInfo = { ...headingInfo, diff --git a/src/components/ShipmentList/ShipmentList.jsx b/src/components/ShipmentList/ShipmentList.jsx index fb7cf1366c8..fade72641e9 100644 --- a/src/components/ShipmentList/ShipmentList.jsx +++ b/src/components/ShipmentList/ShipmentList.jsx @@ -38,6 +38,7 @@ export const ShipmentListItem = ({ [styles[`shipment-list-item-PPM`]]: isPPM, [styles[`shipment-list-item-Boat`]]: isBoat, [styles[`shipment-list-item-MobileHome`]]: isMobileHome, + [styles[`shipment-list-item-UB`]]: shipment.shipmentType === SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, }); const estimated = 'Estimated'; const actual = 'Actual'; diff --git a/src/components/ShipmentList/ShipmentList.module.scss b/src/components/ShipmentList/ShipmentList.module.scss index 2e2e1cd6cc3..34a8d484f1a 100644 --- a/src/components/ShipmentList/ShipmentList.module.scss +++ b/src/components/ShipmentList/ShipmentList.module.scss @@ -103,6 +103,10 @@ border-left: 5px solid $accent-mobile-home; } +.shipment-list-item-UB { + border-left: 5px solid $accent-ub; +} + .spaceBetween { display: flex; justify-content: center; diff --git a/src/components/ShipmentList/ShipmentList.test.jsx b/src/components/ShipmentList/ShipmentList.test.jsx index 6e46c06d6d2..fb93e786f9b 100644 --- a/src/components/ShipmentList/ShipmentList.test.jsx +++ b/src/components/ShipmentList/ShipmentList.test.jsx @@ -24,6 +24,7 @@ describe('ShipmentList component', () => { { id: 'ID-2', shipmentType: SHIPMENT_OPTIONS.HHG }, { id: 'ID-3', shipmentType: SHIPMENT_OPTIONS.NTS }, { id: 'ID-4', shipmentType: SHIPMENT_OPTIONS.NTSR }, + { id: 'ID-4', shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE }, ]; const onShipmentClick = jest.fn(); const onDeleteClick = jest.fn(); @@ -36,11 +37,12 @@ describe('ShipmentList component', () => { it('renders ShipmentList with shipments', async () => { render(); - expect(screen.getAllByTestId('shipment-list-item-container').length).toBe(4); + expect(screen.getAllByTestId('shipment-list-item-container').length).toBe(5); expect(screen.getAllByTestId('shipment-list-item-container')[0]).toHaveTextContent(/^ppm/i); expect(screen.getAllByTestId('shipment-list-item-container')[1]).toHaveTextContent(/^hhg/i); expect(screen.getAllByTestId('shipment-list-item-container')[2]).toHaveTextContent(/^nts/i); expect(screen.getAllByTestId('shipment-list-item-container')[3]).toHaveTextContent(/^nts-release/i); + expect(screen.getAllByTestId('shipment-list-item-container')[4]).toHaveTextContent(/^UB/i); }); it.each([ @@ -72,6 +74,9 @@ describe('ShipmentList component', () => { editBtn = queryByRole(screen.getAllByTestId('shipment-list-item-container')[3], 'button', { name: 'Edit' }); await checkShipmentClick('ID-4', 1, SHIPMENT_OPTIONS.NTSR); + + editBtn = queryByRole(screen.getAllByTestId('shipment-list-item-container')[4], 'button', { name: 'Edit' }); + await checkShipmentClick('ID-4', 1, SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE); }); it.each([ @@ -79,6 +84,7 @@ describe('ShipmentList component', () => { [SHIPMENT_OPTIONS.HHG, 2], [SHIPMENT_OPTIONS.NTS, 3], [SHIPMENT_OPTIONS.NTSR, 4], + [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, 5], ])('calls onDeleteClick for shipment type %s when delete is clicked', async (_, id) => { render(); const deleteBtn = getByRole(screen.getAllByTestId('shipment-list-item-container')[id - 1], 'button', { diff --git a/src/constants/shipments.js b/src/constants/shipments.js index 9a9154f44b1..0be6c1adc97 100644 --- a/src/constants/shipments.js +++ b/src/constants/shipments.js @@ -10,6 +10,7 @@ export const shipmentTypes = { [SHIPMENT_OPTIONS.BOAT]: 'Boat', [SHIPMENT_TYPES.BOAT_HAUL_AWAY]: 'Boat', [SHIPMENT_TYPES.BOAT_TOW_AWAY]: 'Boat', + [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE]: 'UB', }; export const shipmentModificationTypes = { @@ -22,6 +23,8 @@ export const mtoShipmentTypes = { [SHIPMENT_OPTIONS.PPM]: 'Personally procured move', [SHIPMENT_OPTIONS.NTS]: 'Non-temp storage', [SHIPMENT_OPTIONS.NTSR]: 'Non-temp storage release', + [SHIPMENT_OPTIONS.HHG]: 'Household goods', + [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE]: 'UB', }; export const shipmentStatuses = { diff --git a/src/content/shipments.js b/src/content/shipments.js index 2d7ecae0329..8b2594a2590 100644 --- a/src/content/shipments.js +++ b/src/content/shipments.js @@ -10,6 +10,7 @@ export const shipmentTypeLabels = { [SHIPMENT_TYPES.BOAT_HAUL_AWAY]: 'Boat', [SHIPMENT_TYPES.BOAT_TOW_AWAY]: 'Boat', [SHIPMENT_TYPES.MOBILE_HOME]: 'Mobile Home', + [SHIPMENT_TYPES.UNACCOMPANIED_BAGGAGE]: 'UB', }; export const shipmentForm = { diff --git a/src/shared/constants.js b/src/shared/constants.js index 5b55b14150a..f4d30dd4c3c 100644 --- a/src/shared/constants.js +++ b/src/shared/constants.js @@ -79,6 +79,7 @@ export const SHIPMENT_OPTIONS = { NTSR: 'HHG_OUTOF_NTS_DOMESTIC', BOAT: 'BOAT', MOBILE_HOME: 'MOBILE_HOME', + UNACCOMPANIED_BAGGAGE: 'UNACCOMPANIED_BAGGAGE', }; export const SHIPMENT_TYPES = { @@ -89,6 +90,7 @@ export const SHIPMENT_TYPES = { BOAT_HAUL_AWAY: 'BOAT_HAUL_AWAY', BOAT_TOW_AWAY: 'BOAT_TOW_AWAY', MOBILE_HOME: 'MOBILE_HOME', + UNACCOMPANIED_BAGGAGE: 'UNACCOMPANIED_BAGGAGE', }; // These constants are used for forming URLs that have the shipment type in @@ -100,6 +102,7 @@ export const SHIPMENT_OPTIONS_URL = { NTSrelease: 'NTSrelease', BOAT: 'Boat', MOBILE_HOME: 'Mobilehome', + UNACCOMPANIED_BAGGAGE: 'UB', }; export const LOA_TYPE = { @@ -121,6 +124,7 @@ export const shipmentOptionLabels = [ { key: SHIPMENT_OPTIONS.MOBILE_HOME, label: 'MobileHome' }, { key: SHIPMENT_TYPES.BOAT_HAUL_AWAY, label: 'Boat' }, { key: SHIPMENT_TYPES.BOAT_TOW_AWAY, label: 'Boat' }, + { key: SHIPMENT_TYPES.UNACCOMPANIED_BAGGAGE, label: 'UB' }, ]; export const SERVICE_ITEM_STATUS = { @@ -194,6 +198,7 @@ export const FEATURE_FLAG_KEYS = { NTSR: 'ntsr', BOAT: 'boat', MOBILE_HOME: 'mobile_home', + UNACCOMPANIED_BAGGAGE: 'unaccompanied_baggage', }; export const MOVE_DOCUMENT_TYPE = { diff --git a/src/shared/styles/colors.scss b/src/shared/styles/colors.scss index 96e08a1b223..0acc2a82868 100644 --- a/src/shared/styles/colors.scss +++ b/src/shared/styles/colors.scss @@ -34,7 +34,7 @@ $link-light-hover: #b7caf0; $accent-teal: #027a97; $accent-hhg: #0096f4; $accent-ppm: #e6c74c; -$accent-ub: #f2938c; +$accent-ub: #5050c4; $accent-nts: #d85bef; $accent-ntsr: #8168b3; $accent-boat: #5d92ba; From f98f6ac7770c6eefc76d66478bc81c1671915828 Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 19:46:30 +0000 Subject: [PATCH 08/15] change color back to peach for ubs --- src/shared/styles/colors.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/styles/colors.scss b/src/shared/styles/colors.scss index 0acc2a82868..96e08a1b223 100644 --- a/src/shared/styles/colors.scss +++ b/src/shared/styles/colors.scss @@ -34,7 +34,7 @@ $link-light-hover: #b7caf0; $accent-teal: #027a97; $accent-hhg: #0096f4; $accent-ppm: #e6c74c; -$accent-ub: #5050c4; +$accent-ub: #f2938c; $accent-nts: #d85bef; $accent-ntsr: #8168b3; $accent-boat: #5d92ba; From 48202a6ffc7a803ecbf46d2b0e47569b7137c773 Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 19:47:15 +0000 Subject: [PATCH 09/15] expand hhgshipmentcard tests to test ubs --- .../HHGShipmentCard/HHGShipmentCard.test.jsx | 185 ++++++++++++++++++ .../Customer/Review/Summary/Summary.test.jsx | 2 - 2 files changed, 185 insertions(+), 2 deletions(-) diff --git a/src/components/Customer/Review/ShipmentCard/HHGShipmentCard/HHGShipmentCard.test.jsx b/src/components/Customer/Review/ShipmentCard/HHGShipmentCard/HHGShipmentCard.test.jsx index dfdbe85c95c..bbcbdb9546c 100644 --- a/src/components/Customer/Review/ShipmentCard/HHGShipmentCard/HHGShipmentCard.test.jsx +++ b/src/components/Customer/Review/ShipmentCard/HHGShipmentCard/HHGShipmentCard.test.jsx @@ -7,6 +7,7 @@ import userEvent from '@testing-library/user-event'; import HHGShipmentCard from 'components/Customer/Review/ShipmentCard/HHGShipmentCard/HHGShipmentCard'; import { formatCustomerDate } from 'utils/formatters'; import { shipmentStatuses } from 'constants/shipments'; +import { SHIPMENT_OPTIONS } from 'shared/constants'; const defaultProps = { moveId: 'testMove123', @@ -205,3 +206,187 @@ describe('HHGShipmentCard component', () => { expect(mockedOnIncompleteClickFunction).toHaveBeenCalledWith('HHG 1', 'ABC123K-01', 'HHG'); }); }); + +const ubProps = { + moveId: 'testMove123', + editPath: '', + onEditClick: jest.fn(), + onDeleteClick: jest.fn(), + shipmentNumber: 1, + shipmentId: '#ABC123K', + shipmentLocator: '#ABC123K-01', + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + showEditAndDeleteBtn: false, + requestedPickupDate: new Date('01/01/2020').toISOString(), + pickupLocation: { + streetAddress1: '17 8th St', + city: 'New York', + state: 'NY', + postalCode: '11111', + }, + releasingAgent: { + firstName: 'Jo', + lastName: 'Xi', + phone: '(555) 555-5555', + email: 'jo.xi@email.com', + }, + requestedDeliveryDate: new Date('03/01/2020').toISOString(), + destinationZIP: '73523', + receivingAgent: { + firstName: 'Dorothy', + lastName: 'Lagomarsino', + phone: '(999) 999-9999', + email: 'dorothy.lagomarsino@email.com', + }, + remarks: + 'This is 500 characters of customer remarks right here. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', +}; + +const incompleteUBProps = { + moveId: 'testMove123', + editPath: '', + onEditClick: jest.fn(), + onDeleteClick: jest.fn(), + onIncompleteClick: mockedOnIncompleteClickFunction, + shipmentNumber: 1, + shipmentId: 'ABC123K', + shipmentLocator: 'ABC123K-01', + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + showEditAndDeleteBtn: false, + requestedPickupDate: new Date('01/01/2020').toISOString(), + status: shipmentStatuses.DRAFT, +}; + +const completeUBProps = { + moveId: 'testMove123', + editPath: '', + onEditClick: jest.fn(), + onDeleteClick: jest.fn(), + shipmentNumber: 1, + shipmentId: 'ABC123K', + shipmentLocator: 'ABC123K-01', + shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE, + showEditAndDeleteBtn: false, + requestedPickupDate: new Date('01/01/2020').toISOString(), + status: shipmentStatuses.SUBMITTED, +}; + +function mountHHGShipmentCardForUBShipment(props) { + return mount(); +} + +describe('HHGShipmentCard component can be reused for UB shipment card', () => { + it('renders component with all fields', () => { + const wrapper = mountHHGShipmentCardForUBShipment(); + const tableHeaders = [ + 'Requested pickup date', + 'Pickup location', + 'Releasing agent', + 'Requested delivery date', + 'Destination', + 'Receiving agent', + 'Remarks', + ]; + const { streetAddress1, city, state, postalCode } = ubProps.pickupLocation; + const { + firstName: releasingFirstName, + lastName: releasingLastName, + phone: releasingTelephone, + email: releasingEmail, + } = ubProps.releasingAgent; + const { + firstName: receivingFirstName, + lastName: receivingLastName, + phone: receivingTelephone, + email: receivingEmail, + } = ubProps.receivingAgent; + const tableData = [ + formatCustomerDate(ubProps.requestedPickupDate), + `${streetAddress1} ${city}, ${state} ${postalCode}`, + `${releasingFirstName} ${releasingLastName} ${releasingTelephone} ${releasingEmail}`, + formatCustomerDate(ubProps.requestedDeliveryDate), + ubProps.destinationZIP, + `${receivingFirstName} ${receivingLastName} ${receivingTelephone} ${receivingEmail}`, + ]; + + tableHeaders.forEach((label, index) => expect(wrapper.find('dt').at(index).text()).toBe(label)); + tableData.forEach((label, index) => expect(wrapper.find('dd').at(index).text()).toBe(label)); + expect(wrapper.find('.remarksCell').text()).toBe(ubProps.remarks); + }); + + it('should render UB shipment card without releasing/receiving agents and remarks', () => { + const wrapper = mountHHGShipmentCardForUBShipment({ + ...ubProps, + releasingAgent: null, + receivingAgent: null, + remarks: '', + }); + const tableHeaders = ['Requested pickup date', 'Pickup location', 'Requested delivery date', 'Destination']; + const { streetAddress1, city, state, postalCode } = ubProps.pickupLocation; + const tableData = [ + formatCustomerDate(ubProps.requestedPickupDate), + `${streetAddress1} ${city}, ${state} ${postalCode}`, + formatCustomerDate(ubProps.requestedDeliveryDate), + ubProps.destinationZIP, + ]; + tableHeaders.forEach((label, index) => expect(wrapper.find('dt').at(index).text()).toBe(label)); + tableData.forEach((label, index) => expect(wrapper.find('dd').at(index).text()).toBe(label)); + expect(wrapper.find('.remarksCell').length).toBe(0); + }); + + it('should not render a secondary pickup location on UB shipment card if not provided one', async () => { + render(); + + const secondPickupLocation = await screen.queryByText('Second pickup location'); + expect(secondPickupLocation).not.toBeInTheDocument(); + }); + + it('should not render a secondary destination location on UB shipment card if not provided one', async () => { + render(); + + const secondDestination = await screen.queryByText('Second Destination'); + expect(secondDestination).not.toBeInTheDocument(); + }); + + it('should render a UB shipment card secondary pickup location if provided one', async () => { + render(); + + const secondPickupLocation = await screen.getByText('Second pickup location'); + expect(secondPickupLocation).toBeInTheDocument(); + const secondPickupLocationInformation = await screen.getByText(/Some Other Street Name/); + expect(secondPickupLocationInformation).toBeInTheDocument(); + }); + + it('should render a UB shipment card secondary destination location if provided one', async () => { + render(); + + const secondDestination = await screen.getByText('Second Destination'); + expect(secondDestination).toBeInTheDocument(); + const secondDesintationInformation = await screen.getByText(/Some Street Name/); + expect(secondDesintationInformation).toBeInTheDocument(); + }); + + it('does not render UB shipment card incomplete label and tooltip icon for completed UB shipment with SUBMITTED status', async () => { + render(); + + expect(screen.getByRole('heading', { level: 3 })).toHaveTextContent('UB 1'); + expect(screen.getByText(/^#ABC123K-01$/, { selector: 'p' })).toBeInTheDocument(); + + expect(screen.queryByText('Incomplete')).toBeNull(); + }); + + it('renders incomplete label and tooltip icon for incomplete UB shipment with DRAFT status', async () => { + render(); + + expect(screen.getByRole('heading', { level: 3 })).toHaveTextContent('UB 1'); + expect(screen.getByText(/^#ABC123K-01$/, { selector: 'p' })).toBeInTheDocument(); + + expect(screen.getByText(/^Incomplete$/, { selector: 'span' })).toBeInTheDocument(); + + expect(screen.getByTitle('Help about incomplete shipment')).toBeInTheDocument(); + await userEvent.click(screen.getByTitle('Help about incomplete shipment')); + + // verify onclick is getting json string as parameter + expect(mockedOnIncompleteClickFunction).toHaveBeenCalledWith('UB 1', 'ABC123K-01', 'UNACCOMPANIED_BAGGAGE'); + }); +}); diff --git a/src/components/Customer/Review/Summary/Summary.test.jsx b/src/components/Customer/Review/Summary/Summary.test.jsx index d788fdaf94a..d62077b1083 100644 --- a/src/components/Customer/Review/Summary/Summary.test.jsx +++ b/src/components/Customer/Review/Summary/Summary.test.jsx @@ -667,7 +667,6 @@ describe('Summary page', () => { expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTSR); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.BOAT); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.MOBILE_HOME); - expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE); }); it('add shipment modal displays still in dev mode', async () => { @@ -700,7 +699,6 @@ describe('Summary page', () => { expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTSR); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.BOAT); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.MOBILE_HOME); - expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE); }); }); afterEach(jest.clearAllMocks); From 314548e35f7fb319ea9e1b3ff81b59c0d6549ade Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 20:07:28 +0000 Subject: [PATCH 10/15] update ub to match other type naming convention --- src/constants/shipments.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants/shipments.js b/src/constants/shipments.js index 0be6c1adc97..70f9e908392 100644 --- a/src/constants/shipments.js +++ b/src/constants/shipments.js @@ -24,7 +24,7 @@ export const mtoShipmentTypes = { [SHIPMENT_OPTIONS.NTS]: 'Non-temp storage', [SHIPMENT_OPTIONS.NTSR]: 'Non-temp storage release', [SHIPMENT_OPTIONS.HHG]: 'Household goods', - [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE]: 'UB', + [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE]: 'Unaccompanied baggage', }; export const shipmentStatuses = { From a27b81c3976a5df276d1ccea7f3f82ddac338033 Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 20:07:57 +0000 Subject: [PATCH 11/15] update summary --- src/components/Customer/Review/Summary/Summary.jsx | 5 +++++ src/components/Customer/Review/Summary/Summary.test.jsx | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/components/Customer/Review/Summary/Summary.jsx b/src/components/Customer/Review/Summary/Summary.jsx index 924e172336b..c44ed4f7916 100644 --- a/src/components/Customer/Review/Summary/Summary.jsx +++ b/src/components/Customer/Review/Summary/Summary.jsx @@ -97,6 +97,11 @@ export class Summary extends Component { enableMobileHome: enabled, }); }); + isBooleanFlagEnabled(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE).then((enabled) => { + this.setState({ + enableMobileHome: enabled, + }); + }); } handleEditClick = (path) => { diff --git a/src/components/Customer/Review/Summary/Summary.test.jsx b/src/components/Customer/Review/Summary/Summary.test.jsx index d62077b1083..d788fdaf94a 100644 --- a/src/components/Customer/Review/Summary/Summary.test.jsx +++ b/src/components/Customer/Review/Summary/Summary.test.jsx @@ -667,6 +667,7 @@ describe('Summary page', () => { expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTSR); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.BOAT); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.MOBILE_HOME); + expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE); }); it('add shipment modal displays still in dev mode', async () => { @@ -699,6 +700,7 @@ describe('Summary page', () => { expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.NTSR); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.BOAT); expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.MOBILE_HOME); + expect(isBooleanFlagEnabled).toBeCalledWith(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE); }); }); afterEach(jest.clearAllMocks); From 090c9774a8e2af0576bdd299f81e28410c06d792 Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 20:14:04 +0000 Subject: [PATCH 12/15] fix failing shipmentlist test --- src/components/ShipmentList/ShipmentList.test.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ShipmentList/ShipmentList.test.jsx b/src/components/ShipmentList/ShipmentList.test.jsx index fb93e786f9b..4dd3fccb8bb 100644 --- a/src/components/ShipmentList/ShipmentList.test.jsx +++ b/src/components/ShipmentList/ShipmentList.test.jsx @@ -24,7 +24,7 @@ describe('ShipmentList component', () => { { id: 'ID-2', shipmentType: SHIPMENT_OPTIONS.HHG }, { id: 'ID-3', shipmentType: SHIPMENT_OPTIONS.NTS }, { id: 'ID-4', shipmentType: SHIPMENT_OPTIONS.NTSR }, - { id: 'ID-4', shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE }, + { id: 'ID-5', shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE }, ]; const onShipmentClick = jest.fn(); const onDeleteClick = jest.fn(); @@ -76,7 +76,7 @@ describe('ShipmentList component', () => { await checkShipmentClick('ID-4', 1, SHIPMENT_OPTIONS.NTSR); editBtn = queryByRole(screen.getAllByTestId('shipment-list-item-container')[4], 'button', { name: 'Edit' }); - await checkShipmentClick('ID-4', 1, SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE); + await checkShipmentClick('ID-5', 1, SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE); }); it.each([ From 2d254c9d54d46dea8ed96f17d7c4fe067f968cb1 Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Thu, 10 Oct 2024 22:01:07 +0000 Subject: [PATCH 13/15] remove dup hhg type --- src/constants/shipments.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/constants/shipments.js b/src/constants/shipments.js index 70f9e908392..00f29a37874 100644 --- a/src/constants/shipments.js +++ b/src/constants/shipments.js @@ -23,7 +23,6 @@ export const mtoShipmentTypes = { [SHIPMENT_OPTIONS.PPM]: 'Personally procured move', [SHIPMENT_OPTIONS.NTS]: 'Non-temp storage', [SHIPMENT_OPTIONS.NTSR]: 'Non-temp storage release', - [SHIPMENT_OPTIONS.HHG]: 'Household goods', [SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE]: 'Unaccompanied baggage', }; From 262467552c8e1c68fac712a63cca0dce8ed99938 Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Fri, 11 Oct 2024 05:10:44 +0000 Subject: [PATCH 14/15] fix enableUB --- src/components/Customer/Review/Summary/Summary.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Customer/Review/Summary/Summary.jsx b/src/components/Customer/Review/Summary/Summary.jsx index c44ed4f7916..2690920c8f9 100644 --- a/src/components/Customer/Review/Summary/Summary.jsx +++ b/src/components/Customer/Review/Summary/Summary.jsx @@ -58,6 +58,7 @@ export class Summary extends Component { enableNTSR: true, enableBoat: true, enableMobileHome: true, + enableUB: true, }; } @@ -99,7 +100,7 @@ export class Summary extends Component { }); isBooleanFlagEnabled(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE).then((enabled) => { this.setState({ - enableMobileHome: enabled, + enableUB: enabled, }); }); } From 1a6f3d4ec2a1a5c4b8c5b8f7cb8a61912917c858 Mon Sep 17 00:00:00 2001 From: Maria Traskowsky Date: Fri, 11 Oct 2024 14:13:18 +0000 Subject: [PATCH 15/15] ternary for shipment message --- .../MtoShipmentForm/MtoShipmentForm.jsx | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.jsx b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.jsx index 42282fc9cd3..f4018c567f9 100644 --- a/src/components/Customer/MtoShipmentForm/MtoShipmentForm.jsx +++ b/src/components/Customer/MtoShipmentForm/MtoShipmentForm.jsx @@ -312,22 +312,14 @@ class MtoShipmentForm extends Component {
-

{shipmentForm.header[`${shipmentType}`]}

- - {!isUB && ( - - Remember: You can move {formatWeight(orders.authorizedWeight)} total. You’ll be billed for any - excess weight you move. - - )} - {isUB && ( - - Remember: You can move up to your UB allowance for this move. You’ll be billed for any excess - weight you move. - - )} - + + Remember: You can move + {isUB + ? ` up to your UB allowance for this move` + : ` ${formatWeight(orders.authorizedWeight)} total`} + . You’ll be billed for any excess weight you move. + {showPickupFields && (