diff --git a/src/components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm.jsx b/src/components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm.jsx index 177b45c7e75..fd570e2103b 100644 --- a/src/components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm.jsx +++ b/src/components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm.jsx @@ -30,7 +30,7 @@ const validationSchema = Yup.object().shape({ vehicleDescription: Yup.string().required('Required'), emptyWeight: Yup.number().min(0, 'Enter a weight 0 lbs or greater').required('Required'), missingEmptyWeightTicket: Yup.boolean(), - emptyWeightTickets: Yup.array().of(uploadShape).min(1, 'At least one upload is required'), + emptyDocument: Yup.array().of(uploadShape).min(1, 'At least one upload is required'), fullWeight: Yup.number() .min(0, 'Enter a weight 0 lbs or greater') .required('Required') @@ -40,10 +40,10 @@ const validationSchema = Yup.object().shape({ : schema; }), missingFullWeightTicket: Yup.boolean(), - fullWeightTickets: Yup.array().of(uploadShape).min(1, 'At least one upload is required'), + fullDocument: Yup.array().of(uploadShape).min(1, 'At least one upload is required'), hasOwnTrailer: Yup.boolean().required('Required'), trailerMeetsCriteria: Yup.boolean(), - trailerOwnershipDocs: Yup.array() + proofOfTrailerOwnershipDocument: Yup.array() .of(uploadShape) .when('trailerMeetsCriteria', (trailerMeetsCriteria, schema) => { return trailerMeetsCriteria ? schema.min(1, 'At least one upload is required') : schema; @@ -88,7 +88,7 @@ const WeightTicketUpload = ({ formikProps: { touched, errors, setFieldTouched, setFieldValue }, }) => { const weightTicketUploadLabel = (name, showConstructedWeight) => { - if (name === 'emptyWeightTickets') { + if (name === 'emptyDocument') { return showConstructedWeight ? 'Upload constructed weight spreadsheet' : 'Upload empty weight ticket'; } @@ -173,31 +173,31 @@ const WeightTicketForm = ({ vehicleDescription, missingEmptyWeightTicket, emptyWeight, - emptyWeightTickets, + emptyDocument, fullWeight, missingFullWeightTicket, - fullWeightTickets, + fullDocument, hasOwnTrailer, trailerMeetsCriteria, - trailerOwnershipDocs, + proofOfTrailerOwnershipDocument, } = weightTicket || {}; const initialValues = { vehicleDescription: vehicleDescription || '', missingEmptyWeightTicket: !!missingEmptyWeightTicket, emptyWeight: emptyWeight ? `${emptyWeight}` : '', - emptyWeightTickets: emptyWeightTickets || [], + emptyDocument: emptyDocument || [], fullWeight: fullWeight ? `${fullWeight}` : '', missingFullWeightTicket: !!missingFullWeightTicket, - fullWeightTickets: fullWeightTickets || [], + fullDocument: fullDocument || [], hasOwnTrailer: hasOwnTrailer ? 'true' : 'false', trailerMeetsCriteria: trailerMeetsCriteria ? 'true' : 'false', - trailerOwnershipDocs: trailerOwnershipDocs || [], + proofOfTrailerOwnershipDocument: proofOfTrailerOwnershipDocument || [], }; - const emptyWeightTicketsRef = createRef(); - const fullWeightTicketsRef = createRef(); - const trailerOwnershipDocsRef = createRef(); + const emptyDocumentRef = createRef(); + const fullDocumentRef = createRef(); + const proofOfTrailerOwnershipDocumentRef = createRef(); return ( @@ -230,12 +230,12 @@ const WeightTicketForm = ({ />
@@ -260,12 +260,12 @@ const WeightTicketForm = ({ />
@@ -331,11 +331,11 @@ const WeightTicketForm = ({
onUploadDelete( uploadId, - 'trailerOwnershipDocs', + 'proofOfTrailerOwnershipDocument', values, formikProps.setFieldTouched, formikProps.setFieldValue, @@ -344,23 +344,24 @@ const WeightTicketForm = ({ />
- {formikProps.touched?.trailerOwnershipDocs && - formikProps.errors?.trailerOwnershipDocs && ( - {formikProps.errors?.trailerOwnershipDocs} + {formikProps.touched?.proofOfTrailerOwnershipDocument && + formikProps.errors?.proofOfTrailerOwnershipDocument && ( + {formikProps.errors?.proofOfTrailerOwnershipDocument} )}

Examples include a registration or bill of sale.

@@ -371,23 +372,23 @@ const WeightTicketForm = ({

{DocumentAndImageUploadInstructions}

onCreateUpload('trailerOwnershipDocs', file)} + name="proofOfTrailerOwnershipDocument" + createUpload={(file) => onCreateUpload('proofOfTrailerOwnershipDocument', file)} labelIdle={UploadDropZoneLabel} labelIdleMobile={UploadDropZoneLabelMobile} onChange={(err, upload) => { - formikProps.setFieldTouched('trailerOwnershipDocs', true); + formikProps.setFieldTouched('proofOfTrailerOwnershipDocument', true); onUploadComplete( upload, err, - 'trailerOwnershipDocs', + 'proofOfTrailerOwnershipDocument', values, formikProps.setFieldValue, ); - trailerOwnershipDocsRef.current.removeFile(upload.id); + proofOfTrailerOwnershipDocumentRef.current.removeFile(upload.id); }} acceptedFileTypes={acceptableFileTypes} - ref={trailerOwnershipDocsRef} + ref={proofOfTrailerOwnershipDocumentRef} />
diff --git a/src/components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm.stories.jsx b/src/components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm.stories.jsx index 3b985d8893e..8658e5c66a0 100644 --- a/src/components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm.stories.jsx +++ b/src/components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm.stories.jsx @@ -86,7 +86,7 @@ ExistingWeightTickets.args = { vehicleDescription: 'DMC Delorean', missingEmptyWeightTicket: false, emptyWeight: 3456, - emptyWeightTickets: [ + emptyDocument: [ { id: 'db4713ae-6087-4330-8b0d-926b3d65c454', created_at: '2022-06-10T12:59:30.000Z', @@ -98,7 +98,7 @@ ExistingWeightTickets.args = { ], fullWeight: 6789, missingFullWeightTicket: false, - fullWeightTickets: [ + fullDocument: [ { id: '28e6e387-7b2d-441b-b96f-f9ba7ed6e794', created_at: '2022-06-09T06:30:59.000Z', @@ -141,7 +141,7 @@ MissingWeightTickets.args = { vehicleDescription: 'DMC Delorean', missingEmptyWeightTicket: true, emptyWeight: 3456, - emptyWeightTickets: [ + emptyDocument: [ { id: 'db4713ae-6087-4330-8b0d-926b3d65c454', created_at: '2022-06-10T12:59:30.000Z', @@ -153,7 +153,7 @@ MissingWeightTickets.args = { ], fullWeight: 6789, missingFullWeightTicket: true, - fullWeightTickets: [ + fullDocument: [ { id: '28e6e387-7b2d-441b-b96f-f9ba7ed6e794', created_at: '2022-06-09T06:30:59.000Z', @@ -186,7 +186,7 @@ TrailerOwnership.args = { vehicleDescription: 'DMC Delorean', missingEmptyWeightTicket: false, emptyWeight: 3456, - emptyWeightTickets: [ + emptyDocument: [ { id: 'db4713ae-6087-4330-8b0d-926b3d65c454', created_at: '2022-06-10T12:59:30.000Z', @@ -198,7 +198,7 @@ TrailerOwnership.args = { ], fullWeight: 6789, missingFullWeightTicket: false, - fullWeightTickets: [ + fullDocument: [ { id: '28e6e387-7b2d-441b-b96f-f9ba7ed6e794', created_at: '2022-06-09T06:30:59.000Z', @@ -218,7 +218,7 @@ TrailerOwnership.args = { ], hasOwnTrailer: true, trailerMeetsCriteria: true, - trailerOwnershipDocs: [ + proofOfTrailerOwnershipDocument: [ { id: '8477cc1f-29da-4e3c-a1ce-34db433cf926', created_at: '2022-06-11T12:59:30.000Z', diff --git a/src/components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm.test.jsx b/src/components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm.test.jsx index a6bf9a256ed..79514893a9d 100644 --- a/src/components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm.test.jsx +++ b/src/components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm.test.jsx @@ -32,7 +32,7 @@ const weightTicketRequiredProps = { vehicleDescription: 'DMC Delorean', emptyWeight: 3999, emptyWeightDocumentId: '27d70a0d-7f20-42af-ab79-f74350412823', - emptyWeightTickets: [ + emptyDocument: [ { id: '299e2fb4-432d-4261-bbed-d8280c6090af', created_at: '2022-06-22T23:25:50.490Z', @@ -44,7 +44,7 @@ const weightTicketRequiredProps = { ], fullWeight: 7111, fullWeightDocumentId: '1ec00b40-447d-4c22-ac73-708b98b8bc20', - fullWeightTickets: [ + fullDocument: [ { id: 'f70af8a1-38e9-4ae2-a837-3c0c61069a0d', created_at: '2022-06-23T23:25:50.490Z', @@ -64,7 +64,7 @@ const weightTicketUploadsOnlyProps = { id: '58350bae-8e87-4e83-bd75-74027fb4853f', shipmentId: '8be77cb9-e8af-4ff0-b0a2-ade17cf6653c', emptyWeightDocumentId: '27d70a0d-7f20-42af-ab79-f74350412823', - emptyWeightTickets: [ + emptyDocument: [ { id: '299e2fb4-432d-4261-bbed-d8280c6090af', created_at: '2022-06-22T23:25:50.490Z', @@ -75,7 +75,7 @@ const weightTicketUploadsOnlyProps = { }, ], fullWeightDocumentId: '1ec00b40-447d-4c22-ac73-708b98b8bc20', - fullWeightTickets: [ + fullDocument: [ { id: 'f70af8a1-38e9-4ae2-a837-3c0c61069a0d', created_at: '2022-06-23T23:25:50.490Z', @@ -96,7 +96,7 @@ const constructedWeightTrailerProps = { emptyWeight: 3999, missingEmptyWeightTicket: true, emptyWeightDocumentId: '27d70a0d-7f20-42af-ab79-f74350412823', - emptyWeightTickets: [ + emptyDocument: [ { id: '299e2fb4-432d-4261-bbed-d8280c6090af', created_at: '2022-06-22T23:25:50.490Z', @@ -109,7 +109,7 @@ const constructedWeightTrailerProps = { fullWeight: 7111, missingFullWeightTicket: true, fullWeightDocumentId: '1ec00b40-447d-4c22-ac73-708b98b8bc20', - fullWeightTickets: [ + fullDocument: [ { id: 'f70af8a1-38e9-4ae2-a837-3c0c61069a0d', created_at: '2022-06-23T23:25:50.490Z', @@ -122,7 +122,7 @@ const constructedWeightTrailerProps = { hasOwnTrailer: true, trailerMeetsCriteria: true, trailerOwnershipDocumentId: '5bf3ed20-08dd-4d8e-92ad-7603bb6377a5', - trailerOwnershipDocs: [ + proofOfTrailerOwnershipDocument: [ { id: 'fd4e80f8-d025-44b2-8c33-15240fac51ab', created_at: '2022-06-24T23:25:50.490Z', @@ -323,7 +323,7 @@ describe('WeightTicketForm component', () => { vehicleDescription: 'DMC Delorean', emptyWeight: '4999', missingEmptyWeightTicket: false, - emptyWeightTickets: [ + emptyDocument: [ { id: '299e2fb4-432d-4261-bbed-d8280c6090af', created_at: '2022-06-22T23:25:50.490Z', @@ -335,7 +335,7 @@ describe('WeightTicketForm component', () => { ], fullWeight: '6999', missingFullWeightTicket: false, - fullWeightTickets: [ + fullDocument: [ { id: 'f70af8a1-38e9-4ae2-a837-3c0c61069a0d', created_at: '2022-06-23T23:25:50.490Z', @@ -347,7 +347,7 @@ describe('WeightTicketForm component', () => { ], hasOwnTrailer: 'false', trailerMeetsCriteria: 'false', - trailerOwnershipDocs: [], + proofOfTrailerOwnershipDocument: [], }, expect.anything(), ); @@ -364,7 +364,7 @@ describe('WeightTicketForm component', () => { vehicleDescription: 'DMC Delorean', emptyWeight: '3999', missingEmptyWeightTicket: true, - emptyWeightTickets: [ + emptyDocument: [ { id: '299e2fb4-432d-4261-bbed-d8280c6090af', created_at: '2022-06-22T23:25:50.490Z', @@ -376,7 +376,7 @@ describe('WeightTicketForm component', () => { ], fullWeight: '7111', missingFullWeightTicket: true, - fullWeightTickets: [ + fullDocument: [ { id: 'f70af8a1-38e9-4ae2-a837-3c0c61069a0d', created_at: '2022-06-23T23:25:50.490Z', @@ -388,7 +388,7 @@ describe('WeightTicketForm component', () => { ], hasOwnTrailer: 'true', trailerMeetsCriteria: 'true', - trailerOwnershipDocs: [ + proofOfTrailerOwnershipDocument: [ { id: 'fd4e80f8-d025-44b2-8c33-15240fac51ab', created_at: '2022-06-24T23:25:50.490Z', diff --git a/src/pages/MyMove/PPM/Closeout/WeightTickets/WeightTickets.jsx b/src/pages/MyMove/PPM/Closeout/WeightTickets/WeightTickets.jsx index 356faa47061..7829ed3b55d 100644 --- a/src/pages/MyMove/PPM/Closeout/WeightTickets/WeightTickets.jsx +++ b/src/pages/MyMove/PPM/Closeout/WeightTickets/WeightTickets.jsx @@ -1,11 +1,11 @@ import React, { useEffect, useState } from 'react'; import { generatePath, useHistory, useParams, useLocation } from 'react-router-dom'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { Alert, Grid, GridContainer } from '@trussworks/react-uswds'; import qs from 'query-string'; import { v4 as uuidv4 } from 'uuid'; -import { selectMTOShipmentById } from 'store/entities/selectors'; +import { selectMTOShipmentById, selectWeightTicketAndIndexById } from 'store/entities/selectors'; import { customerRoutes, generalRoutes } from 'constants/routes'; import { createUploadForDocument, createWeightTicket, patchWeightTicket } from 'services/internalApi'; import LoadingPlaceholder from 'shared/LoadingPlaceholder'; @@ -15,30 +15,35 @@ import ShipmentTag from 'components/ShipmentTag/ShipmentTag'; import { shipmentTypes } from 'constants/shipments'; import closingPageStyles from 'pages/MyMove/PPM/Closeout/Closeout.module.scss'; import WeightTicketForm from 'components/Customer/PPM/Closeout/WeightTicketForm/WeightTicketForm'; +import { updateMTOShipment } from 'store/entities/actions'; const WeightTickets = () => { const [errorMessage, setErrorMessage] = useState(); + const dispatch = useDispatch(); const history = useHistory(); const { moveId, mtoShipmentId, weightTicketId } = useParams(); + const { search } = useLocation(); const { tripNumber } = qs.parse(search); - // TODO remove when replaced by Redux call - const [weightTicket, setWeightTicket] = useState(); - const mtoShipment = useSelector((state) => selectMTOShipmentById(state, mtoShipmentId)); - // TODO add selector for selecting weight ticket from Redux store when data changes are solidified + const { weightTicket: currentWeightTicket, index: currentIndex } = useSelector((state) => + selectWeightTicketAndIndexById(state, mtoShipmentId, weightTicketId), + ); useEffect(() => { if (!weightTicketId) { createWeightTicket(mtoShipmentId) .then((resp) => { - // TODO save weight ticket response in Redux and then the selector will assign the weight ticket - setWeightTicket(resp); - // I think it's necessary to update the URL so the back button would work and not create - // a new weight ticket on refresh either. + if (mtoShipment?.ppmShipment?.weightTickets) { + mtoShipment.ppmShipment.weightTickets.push(resp); + } else { + mtoShipment.ppmShipment.weightTickets = [resp]; + } + // Update the URL so the back button would work and not create a new weight ticket or on + // refresh either. history.replace( generatePath(customerRoutes.SHIPMENT_PPM_WEIGHT_TICKETS_EDIT_PATH, { moveId, @@ -46,30 +51,33 @@ const WeightTickets = () => { weightTicketId: resp.id, }), ); + dispatch(updateMTOShipment(mtoShipment)); }) .catch(() => { setErrorMessage('Failed to create trip record'); }); } - }, [weightTicketId, moveId, mtoShipmentId, history]); + }, [weightTicketId, moveId, mtoShipmentId, history, dispatch, mtoShipment]); - const handleCreateUpload = (fieldName, file) => { + const handleCreateUpload = async (fieldName, file) => { let documentId; switch (fieldName) { case 'emptyWeightTickets': - documentId = weightTicket.emptyWeightDocumentId; + documentId = currentWeightTicket.emptyWeightDocumentId; break; case 'fullWeightTickets': - documentId = weightTicket.fullWeightDocumentId; + documentId = currentWeightTicket.fullWeightDocumentId; break; case 'trailerOwnershipDocs': - documentId = weightTicket.trailerOwnershipDocumentId; + documentId = currentWeightTicket.trailerOwnershipDocumentId; break; default: } createUploadForDocument(file, documentId) .then((upload) => { + mtoShipment.ppmShipment.weightTickets[currentIndex][fieldName].push(upload); + dispatch(updateMTOShipment(mtoShipment)); return upload; }) .catch(() => { @@ -96,9 +104,14 @@ const WeightTickets = () => { }; const handleUploadDelete = (uploadId, fieldName, values, setFieldTouched, setFieldValue) => { - const remainingUploads = values[`${fieldName}`]?.filter((upload) => upload.id !== uploadId); + const filterdDocuments = mtoShipment.ppmShipment.weightTickets[currentIndex][fieldName].filter( + (upload) => upload.id !== uploadId, + ); + mtoShipment.ppmShipment.weightTickets[currentIndex][fieldName] = filterdDocuments; + const remainingUploads = values[fieldName]?.filter((upload) => upload.id !== uploadId); setFieldTouched(fieldName, true, true); setFieldValue(fieldName, remainingUploads, true); + dispatch(updateMTOShipment(mtoShipment)); }; const handleBack = () => { @@ -120,10 +133,12 @@ const WeightTickets = () => { trailerMeetsCriteria, }; - patchWeightTicket(mtoShipment.id, weightTicket.id, payload, weightTicket.eTag) - .then(() => { + patchWeightTicket(mtoShipment.id, currentWeightTicket.id, payload, currentWeightTicket.eTag) + .then((resp) => { setSubmitting(false); + mtoShipment.ppmShipment.weightTickets[currentIndex] = resp; history.push(generatePath(customerRoutes.SHIPMENT_PPM_REVIEW_PATH, { moveId, mtoShipmentId })); + dispatch(updateMTOShipment(mtoShipment)); }) .catch(() => { setSubmitting(false); @@ -131,8 +146,20 @@ const WeightTickets = () => { }); }; - if (!mtoShipment || !weightTicket) { - return ; + const renderError = () => { + if (!errorMessage) { + return null; + } + + return ( + + {errorMessage} + + ); + }; + + if (!mtoShipment || !currentWeightTicket) { + return renderError() || ; } return ( @@ -143,11 +170,7 @@ const WeightTickets = () => {

Weight Tickets

- {errorMessage && ( - - {errorMessage} - - )} + {renderError()}

Weight tickets should include both an empty or full weight ticket for each segment or trip. If you’re @@ -157,7 +180,7 @@ const WeightTickets = () => {

You must upload at least one set of weight tickets to get paid for your PPM.

({ ...jest.requireActual('store/entities/selectors'), selectMTOShipmentById: jest.fn(() => mockMTOShipment), + selectWeightTicketAndIndexById: jest.fn(() => mockEmptyWeightTicketAndIndex), })); beforeEach(() => { @@ -146,7 +152,7 @@ describe('Weight Tickets page', () => { }); it('displays an error if the createWeightTicket request fails', async () => { - createWeightTicket.mockRejectedValueOnce('an error occurred'); + createWeightTicket.mockRejectedValue('an error occurred'); render(, { wrapper: MockProviders }); @@ -161,6 +167,7 @@ describe('Weight Tickets page', () => { mtoShipmentId: mockMTOShipmentId, weightTicketId: mockWeightTicketId, })); + selectWeightTicketAndIndexById.mockReturnValue({ weightTicket: mockWeightTicket, index: 0 }); render(, { wrapper: MockProviders }); @@ -171,6 +178,8 @@ describe('Weight Tickets page', () => { it('renders the page Content', async () => { createWeightTicket.mockResolvedValue(mockWeightTicket); + selectWeightTicketAndIndexById.mockReturnValueOnce({ weightTicket: null, index: -1 }); + selectWeightTicketAndIndexById.mockReturnValue({ weightTicket: mockWeightTicket, index: 0 }); render(, { wrapper: MockProviders }); @@ -195,6 +204,8 @@ describe('Weight Tickets page', () => { it('replaces the router history with newly created weight ticket id', async () => { createWeightTicket.mockResolvedValue(mockWeightTicket); + selectWeightTicketAndIndexById.mockReturnValueOnce({ weightTicket: null, index: -1 }); + selectWeightTicketAndIndexById.mockReturnValue({ weightTicket: mockWeightTicket, index: 0 }); render(, { wrapper: MockProviders }); @@ -205,6 +216,7 @@ describe('Weight Tickets page', () => { it('routes back to home when finish later is clicked', async () => { createWeightTicket.mockResolvedValue(mockWeightTicket); + selectWeightTicketAndIndexById.mockReturnValue({ weightTicket: mockWeightTicket, index: 0 }); render(, { wrapper: MockProviders }); @@ -217,6 +229,7 @@ describe('Weight Tickets page', () => { it('calls patch weight ticket with the appropriate payload', async () => { createWeightTicket.mockResolvedValue(mockWeightTicketWithUploads); + selectWeightTicketAndIndexById.mockReturnValue({ weightTicket: mockWeightTicketWithUploads, index: 0 }); patchWeightTicket.mockResolvedValue({}); render(, { wrapper: MockProviders }); @@ -224,13 +237,13 @@ describe('Weight Tickets page', () => { await waitFor(() => { expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent('Trip 2'); }); - await userEvent.type(screen.getByLabelText('Vehicle description'), 'DMC Delorean'); - await userEvent.type(screen.getByLabelText('Empty weight'), '4999'); - await userEvent.type(screen.getByLabelText('Full weight'), '6999'); - await userEvent.click(screen.getByLabelText('Yes')); - await userEvent.click(screen.getAllByLabelText('Yes')[1]); + userEvent.type(screen.getByLabelText('Vehicle description'), 'DMC Delorean'); + userEvent.type(screen.getByLabelText('Empty weight'), '4999'); + userEvent.type(screen.getByLabelText('Full weight'), '6999'); + userEvent.click(screen.getByLabelText('Yes')); + userEvent.click(screen.getAllByLabelText('Yes')[1]); - await userEvent.click(screen.getByRole('button', { name: 'Save & Continue' })); + userEvent.click(screen.getByRole('button', { name: 'Save & Continue' })); await waitFor(() => { expect(patchWeightTicket).toHaveBeenCalledWith( @@ -255,6 +268,7 @@ describe('Weight Tickets page', () => { it('displays an error if patchWeightTicket fails', async () => { createWeightTicket.mockResolvedValue(mockWeightTicketWithUploads); + selectWeightTicketAndIndexById.mockReturnValue({ weightTicket: mockWeightTicketWithUploads, index: 0 }); patchWeightTicket.mockRejectedValueOnce('an error occurred'); render(, { wrapper: MockProviders }); @@ -262,13 +276,13 @@ describe('Weight Tickets page', () => { await waitFor(() => { expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent('Trip 2'); }); - await userEvent.type(screen.getByLabelText('Vehicle description'), 'DMC Delorean'); - await userEvent.type(screen.getByLabelText('Empty weight'), '4999'); - await userEvent.type(screen.getByLabelText('Full weight'), '6999'); - await userEvent.click(screen.getByLabelText('Yes')); - await userEvent.click(screen.getAllByLabelText('Yes')[1]); + userEvent.type(screen.getByLabelText('Vehicle description'), 'DMC Delorean'); + userEvent.type(screen.getByLabelText('Empty weight'), '4999'); + userEvent.type(screen.getByLabelText('Full weight'), '6999'); + userEvent.click(screen.getByLabelText('Yes')); + userEvent.click(screen.getAllByLabelText('Yes')[1]); - await userEvent.click(screen.getByRole('button', { name: 'Save & Continue' })); + userEvent.click(screen.getByRole('button', { name: 'Save & Continue' })); await waitFor(() => { expect(screen.getByText('Failed to save updated trip record')).toBeInTheDocument(); @@ -277,6 +291,14 @@ describe('Weight Tickets page', () => { it('calls the delete handler when removing an existing upload', async () => { createWeightTicket.mockResolvedValue(mockWeightTicketWithUploads); + selectMTOShipmentById.mockReturnValue({ + ...mockMTOShipment, + ppmShipment: { + ...mockMTOShipment.ppmShipment, + weightTickets: [mockWeightTicketWithUploads], + }, + }); + selectWeightTicketAndIndexById.mockReturnValue({ weightTicket: mockWeightTicketWithUploads, index: 0 }); render(, { wrapper: MockProviders }); @@ -285,7 +307,7 @@ describe('Weight Tickets page', () => { deleteButtons = screen.getAllByRole('button', { name: 'Delete' }); expect(deleteButtons).toHaveLength(2); }); - await userEvent.click(deleteButtons[0]); + userEvent.click(deleteButtons[0]); await waitFor(() => { expect(screen.queryByText('empty_weight.jpg')).not.toBeInTheDocument(); }); diff --git a/src/store/entities/selectors.js b/src/store/entities/selectors.js index 47ca0e84735..d21f2397263 100644 --- a/src/store/entities/selectors.js +++ b/src/store/entities/selectors.js @@ -161,6 +161,22 @@ export function selectMTOShipmentById(state, id) { } /** PPMs */ +export const selectWeightTicketAndIndexById = (state, mtoShipmentId, weightTicketId) => { + let weightTicket = null; + let index = -1; + if (weightTicketId == null) { + return { weightTicket, index }; + } + + const mtoShipment = selectMTOShipmentById(state, mtoShipmentId); + const weightTickets = mtoShipment?.ppmShipment?.weightTickets; + if (Array.isArray(weightTickets)) { + index = weightTickets.findIndex((ele) => ele.id === weightTicketId); + weightTicket = weightTickets?.[index] || null; + } + return { weightTicket, index }; +}; + export const selectPPMForMove = (state, moveId) => { const ppmForMove = Object.values(state.entities.personallyProcuredMoves).find((ppm) => ppm.move_id === moveId); if (['DRAFT', 'SUBMITTED', 'APPROVED', 'PAYMENT_REQUESTED', 'COMPLETED'].indexOf(ppmForMove?.status) > -1) { diff --git a/src/store/entities/selectors.test.js b/src/store/entities/selectors.test.js index aef6dfc73ff..2a8453b9cd6 100644 --- a/src/store/entities/selectors.test.js +++ b/src/store/entities/selectors.test.js @@ -16,6 +16,7 @@ import { selectPPMSitEstimate, selectReimbursementById, selectEntitlementsForLoggedInUser, + selectWeightTicketAndIndexById, } from './selectors'; import { profileStates } from 'constants/customerStates'; @@ -1323,6 +1324,81 @@ describe('selectPPMForMove', () => { }); }); +describe('selectWeightTicketAndIndexById', () => { + it('return the correct weight ticket and index', () => { + const weightTicketId = '71422b71-a40b-41a7-b2ff-4da922a9c7f2'; + const testState = { + entities: { + mtoShipments: { + '2ed2998e-ae36-46cd-af83-c3ecee55fe3e': { + createdAt: '2022-07-01T01:10:51.224Z', + eTag: 'MjAyMi0wNy0xMVQxODoyMDoxOC43MjQ1NzRa', + id: '2ed2998e-ae36-46cd-af83-c3ecee55fe3e', + moveTaskOrderID: '26b960d8-a96d-4450-a441-673ccd7cc3c7', + ppmShipment: { + actualDestinationPostalCode: '30813', + actualMoveDate: '2022-07-31', + actualPickupPostalCode: '90210', + advanceAmountReceived: null, + advanceAmountRequested: 598700, + approvedAt: '2022-04-15T12:30:00.000Z', + createdAt: '2022-07-01T01:10:51.231Z', + destinationPostalCode: '30813', + eTag: 'MjAyMi0wNy0xMVQxODoyMDoxOC43NTIwMDNa', + estimatedIncentive: 1000000, + estimatedWeight: 4000, + expectedDepartureDate: '2020-03-15', + hasProGear: true, + hasReceivedAdvance: false, + hasRequestedAdvance: true, + id: 'b9ae4c25-1376-4b9b-8781-106b5ae7ecab', + netWeight: null, + pickupPostalCode: '90210', + proGearWeight: 1987, + reviewedAt: null, + secondaryDestinationPostalCode: '30814', + secondaryPickupPostalCode: '90211', + shipmentId: '2ed2998e-ae36-46cd-af83-c3ecee55fe3e', + sitEstimatedCost: null, + sitEstimatedDepartureDate: null, + sitEstimatedEntryDate: null, + sitEstimatedWeight: null, + sitExpected: false, + spouseProGearWeight: 498, + status: 'WAITING_ON_CUSTOMER', + submittedAt: null, + updatedAt: '2022-07-11T18:20:18.752Z', + weightTickets: [ + { + id: 'd35d835f-8258-4266-87aa-54d61c917780', + emptyWeightDocumentId: '000676ac-c5ff-4630-8768-ef238f04e706', + fullWeightDocumentId: '7eeb270b-dc97-4f95-94c3-709c082cbf94', + trailerOwnershipDocumentId: 'd6b68bba-fe81-4402-82ac-6c02bf7cb660', + }, + { + id: weightTicketId, + emptyWeightDocumentId: '15fdd562-82a9-4892-85d7-81cc3a85e68e', + fullWeightDocumentId: '4a7f7fd9-15d1-468f-9184-53d7c0c1ccdc', + trailerOwnershipDocumentId: 'f9ed20ad-bebd-4b5d-a59b-e3a86d273b78', + }, + ], + }, + shipmentType: 'PPM', + status: 'APPROVED', + updatedAt: '2022-07-11T18:20:18.724Z', + }, + }, + }, + }; + const mtoShipmentID = Object.keys(testState.entities.mtoShipments)[0]; + + expect(selectWeightTicketAndIndexById(testState, mtoShipmentID, weightTicketId)).toEqual({ + weightTicket: testState.entities.mtoShipments[mtoShipmentID].ppmShipment.weightTickets[1], + index: 1, + }); + }); +}); + describe('selectCurrentPPM', () => { it('returns the current PPM associated with the current move', () => { const testState = {