-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MB-13125 - handle state for weightTickets #8873
Changes from 13 commits
c992558
1311e8d
36080d7
570c2e9
f67297a
59a6581
8595730
b8c6131
e93a5fb
d5c4a53
66de399
12c13e5
98c994b
b66fe15
2443572
8ba24db
d389589
3d6e244
fceb84e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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,28 +15,33 @@ 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); | ||
if (mtoShipment?.ppmShipment?.weightTickets) { | ||
mtoShipment.ppmShipment.weightTickets.push(resp); | ||
} else { | ||
mtoShipment.ppmShipment.weightTickets = [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. | ||
history.replace( | ||
|
@@ -46,30 +51,37 @@ 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; | ||
let documentField; | ||
switch (fieldName) { | ||
case 'emptyWeightTickets': | ||
documentId = weightTicket.emptyWeightDocumentId; | ||
documentId = currentWeightTicket.emptyWeightDocumentId; | ||
documentField = 'emptyDocument'; | ||
break; | ||
case 'fullWeightTickets': | ||
documentId = weightTicket.fullWeightDocumentId; | ||
documentId = currentWeightTicket.fullWeightDocumentId; | ||
documentField = 'fullDocument'; | ||
break; | ||
case 'trailerOwnershipDocs': | ||
documentId = weightTicket.trailerOwnershipDocumentId; | ||
documentId = currentWeightTicket.trailerOwnershipDocumentId; | ||
documentField = 'proofOfTrailerOwnershipDocument'; | ||
break; | ||
default: | ||
} | ||
|
||
createUploadForDocument(file, documentId) | ||
.then((upload) => { | ||
mtoShipment.ppmShipment.weightTickets[currentIndex][documentField].push(upload); | ||
dispatch(updateMTOShipment(mtoShipment)); | ||
return upload; | ||
}) | ||
.catch(() => { | ||
|
@@ -96,9 +108,27 @@ const WeightTickets = () => { | |
}; | ||
|
||
const handleUploadDelete = (uploadId, fieldName, values, setFieldTouched, setFieldValue) => { | ||
const remainingUploads = values[`${fieldName}`]?.filter((upload) => upload.id !== uploadId); | ||
let documentField; | ||
switch (fieldName) { | ||
case 'emptyWeightTickets': | ||
documentField = 'emptyDocument'; | ||
break; | ||
case 'fullWeightTickets': | ||
documentField = 'fullDocument'; | ||
break; | ||
case 'trailerOwnershipDocs': | ||
documentField = 'proofOfTrailerOwnershipDocument'; | ||
break; | ||
default: | ||
} | ||
ronaktruss marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const filterdDocuments = mtoShipment.ppmShipment.weightTickets[currentIndex][documentField].filter( | ||
(upload) => upload.id !== uploadId, | ||
); | ||
mtoShipment.ppmShipment.weightTickets[currentIndex][documentField] = filterdDocuments; | ||
const remainingUploads = values[fieldName]?.filter((upload) => upload.id !== uploadId); | ||
setFieldTouched(fieldName, true, true); | ||
setFieldValue(fieldName, remainingUploads, true); | ||
dispatch(updateMTOShipment(mtoShipment)); | ||
}; | ||
|
||
const handleBack = () => { | ||
|
@@ -120,19 +150,33 @@ 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)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know if this is reachable if it comes after history.push(), it might need moved before the history call. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I tested this, it seemed to work as expected. I'll double check the behavior during the integration. |
||
}) | ||
.catch(() => { | ||
setSubmitting(false); | ||
setErrorMessage('Failed to save updated trip record'); | ||
}); | ||
}; | ||
|
||
if (!mtoShipment || !weightTicket) { | ||
return <LoadingPlaceholder />; | ||
const renderError = () => { | ||
if (!errorMessage) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<Alert slim type="error"> | ||
{errorMessage} | ||
</Alert> | ||
); | ||
}; | ||
|
||
if (!mtoShipment || !currentWeightTicket) { | ||
return renderError() || <LoadingPlaceholder />; | ||
} | ||
|
||
return ( | ||
|
@@ -143,11 +187,7 @@ const WeightTickets = () => { | |
<Grid col desktop={{ col: 8, offset: 2 }}> | ||
<ShipmentTag shipmentType={shipmentTypes.PPM} /> | ||
<h1>Weight Tickets</h1> | ||
{errorMessage && ( | ||
<Alert slim type="error"> | ||
{errorMessage} | ||
</Alert> | ||
)} | ||
{renderError()} | ||
<div className={closingPageStyles['closing-section']}> | ||
<p> | ||
Weight tickets should include both an empty or full weight ticket for each segment or trip. If you’re | ||
|
@@ -157,7 +197,7 @@ const WeightTickets = () => { | |
<p>You must upload at least one set of weight tickets to get paid for your PPM.</p> | ||
</div> | ||
<WeightTicketForm | ||
weightTicket={weightTicket} | ||
weightTicket={currentWeightTicket} | ||
tripNumber={tripNumber} | ||
onCreateUpload={handleCreateUpload} | ||
onUploadComplete={handleUploadComplete} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason that something like
values[`${fieldName}`]
is used overvalues[fieldName]
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's usually to avoid eslint detect-object-injection errors because fieldName, if provided by the user or other malicious source, might not be a string eslint-community/eslint-plugin-security#21