Skip to content
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

20616 add mobile shipment customer flows main #13693

Merged
merged 36 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
f91d419
adding in integration changes
KonstanceH Aug 26, 2024
1a20ed0
missed shape
KonstanceH Aug 26, 2024
9682d7c
missing tests
KonstanceH Aug 26, 2024
92cc5d9
remove extra comments and fix name
KonstanceH Aug 26, 2024
a0f4d85
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
KonstanceH Sep 6, 2024
b09c328
move mobile and boat info modal togeter
KonstanceH Sep 6, 2024
a05d4ad
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
KonstanceH Sep 6, 2024
43ae923
reverting to old commit
KonstanceH Sep 10, 2024
6c657a4
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
KonstanceH Sep 10, 2024
03c9c93
changes to match integration
KonstanceH Sep 11, 2024
08a7201
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
KonstanceH Sep 11, 2024
aec17dd
revert motor home
KonstanceH Sep 11, 2024
930b728
remove required tag comment
KonstanceH Sep 11, 2024
fbb3185
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
KonstanceH Sep 16, 2024
17d088b
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
taeJungCaci Sep 19, 2024
7ced8c5
merge in latest main and add epelling change from integration
KonstanceH Sep 19, 2024
5c8d19b
accidentaly removed mobile home style
KonstanceH Sep 19, 2024
8ac90a1
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
KonstanceH Sep 20, 2024
313338f
rmeoved capitalized a
KonstanceH Sep 20, 2024
9c58c79
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
KonstanceH Sep 20, 2024
fe5facf
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
taeJungCaci Sep 23, 2024
73666ec
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
taeJungCaci Sep 23, 2024
73d5377
adding tests from 20653
KonstanceH Sep 24, 2024
5d2c9e2
adding test with mobileHome changed
KonstanceH Sep 25, 2024
675eaea
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
KonstanceH Sep 25, 2024
4929ff8
remove playwright tests
KonstanceH Sep 25, 2024
e44342a
removed mobileHome part to not break int
KonstanceH Sep 25, 2024
628eb3a
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
taeJungCaci Sep 25, 2024
ced22b9
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
taeJungCaci Sep 25, 2024
850d1ca
adding in header test for shipment card working on moves test
KonstanceH Sep 26, 2024
6db2703
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
KonstanceH Sep 26, 2024
d1be426
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
taeJungCaci Sep 26, 2024
0af3bcc
moving up client test version
KonstanceH Sep 26, 2024
9f908ba
bump up server test coverage to match int
KonstanceH Sep 26, 2024
03b09af
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
taeJungCaci Sep 30, 2024
629d345
Merge branch 'main' into 20621-Add-Mobile-Shipment-Customer-Flows-MAIN
WeatherfordAaron Oct 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions pkg/handlers/internalapi/moves.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,18 @@ func (h GetAllMovesHandler) Handle(params moveop.GetAllMovesParams) middleware.R
}
/** End of Feature Flag Block **/

/** Feature Flag - Mobile Home Shipment **/
featureFlagNameMH := "mobileHome"
isMobileHomeFeatureOn := false
flagMH, err := h.FeatureFlagFetcher().GetBooleanFlagForUser(params.HTTPRequest.Context(), appCtx, featureFlagNameMH, map[string]string{})
if err != nil {
appCtx.Logger().Error("Error fetching feature flag", zap.String("featureFlagKey", featureFlagName), zap.Error(err))
isMobileHomeFeatureOn = false
} else {
isMobileHomeFeatureOn = flagMH.Match
}
/** End of Feature Flag Block **/

for _, move := range movesList {

/** Feature Flag - Boat Shipment **/
Expand Down Expand Up @@ -448,6 +460,23 @@ func (h GetAllMovesHandler) Handle(params moveop.GetAllMovesParams) middleware.R
}
/** End of Feature Flag Block **/

/** Feature Flag - Mobile Home Shipment **/
if !isMobileHomeFeatureOn {
var filteredShipments models.MTOShipments
if move.MTOShipments != nil {
filteredShipments = models.MTOShipments{}
}
for i, shipment := range move.MTOShipments {
if shipment.ShipmentType == models.MTOShipmentTypeMobileHome {
continue
}

filteredShipments = append(filteredShipments, move.MTOShipments[i])
}
move.MTOShipments = filteredShipments
}
/** End of Feature Flag Block **/

previousMovesList = append(previousMovesList, move)
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/services/orchestrators/shipment/shipment_updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (s *shipmentUpdater) UpdateShipment(appCtx appcontext.AppContext, shipment
mtoShipment.BoatShipment = boatShipment

return nil
} else if shipment.ShipmentType == models.MTOShipmentTypeMobileHome {
} else if shipment.ShipmentType == models.MTOShipmentTypeMobileHome && shipment.MobileHome != nil {
shipment.MobileHome.ShipmentID = mtoShipment.ID
shipment.MobileHome.Shipment = *mtoShipment

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,330 @@
import React from 'react';
import { func } from 'prop-types';
import * as Yup from 'yup';
import { Formik, Field } from 'formik';
import { Button, Form, Label, Textarea } from '@trussworks/react-uswds';
import classnames from 'classnames';

import styles from './MobileHomeShipmentForm.module.scss';

import SectionWrapper from 'components/Customer/SectionWrapper';
import Hint from 'components/Hint';
import Fieldset from 'shared/Fieldset';
import formStyles from 'styles/form.module.scss';
import { ShipmentShape } from 'types/shipment';
import TextField from 'components/form/fields/TextField/TextField';
import MaskedTextField from 'components/form/fields/MaskedTextField/MaskedTextField';
import Callout from 'components/Callout';
import { ErrorMessage } from 'components/form/index';
import { convertInchesToFeetAndInches } from 'utils/formatMtoShipment';

const currentYear = new Date().getFullYear();
const maxYear = currentYear + 2;

const validationShape = {
year: Yup.number().required('Required').min(1700, 'Invalid year').max(maxYear, 'Invalid year'),
make: Yup.string().required('Required'),
model: Yup.string().required('Required'),
lengthFeet: Yup.number()
.min(0)
.nullable()
.when('lengthInches', {
is: (lengthInches) => !lengthInches,
then: (schema) => schema.required('Required'),
otherwise: (schema) => schema.notRequired(),
}),
lengthInches: Yup.number(),
widthFeet: Yup.number()
.min(0)
.nullable()
.when('widthInches', {
is: (widthInches) => !widthInches,
then: (schema) => schema.required('Required'),
otherwise: (schema) => schema.notRequired(),
}),
widthInches: Yup.number().min(0),
heightFeet: Yup.number()
.min(0)
.nullable()
.when('heightInches', {
is: (heightInches) => !heightInches,
then: (schema) => schema.required('Required'),
otherwise: (schema) => schema.notRequired(),
}),
heightInches: Yup.number().min(0),
customerRemarks: Yup.string(),
};

const MobileHomeShipmentForm = ({ mtoShipment, onBack, onSubmit }) => {
const { year, make, model, lengthInInches, widthInInches, heightInInches } = mtoShipment?.mobileHomeShipment || {};

const length = convertInchesToFeetAndInches(lengthInInches);
const width = convertInchesToFeetAndInches(widthInInches);
const height = convertInchesToFeetAndInches(heightInInches);

const initialValues = {
year: year?.toString() || null,
make: make || '',
model: model || '',
lengthFeet: length.feet,
lengthInches: length.inches,
widthFeet: width.feet,
widthInches: width.inches,
heightFeet: height.feet,
heightInches: height.inches,
customerRemarks: mtoShipment?.customerRemarks,
};

return (
<Formik
initialValues={initialValues}
validationSchema={Yup.object().shape(validationShape)}
onSubmit={onSubmit}
validateOnMount
>
{({ isValid, handleSubmit, values, errors, touched, setFieldTouched, setFieldError, validateForm }) => {
const lengthHasError = !!(
(touched.lengthFeet && errors.lengthFeet) ||
(touched.lengthInches && errors.lengthFeet)
);
const widthHasError = !!((touched.widthFeet && errors.widthFeet) || (touched.widthInches && errors.widthFeet));
const heightHasError = !!(
(touched.heightFeet && errors.heightFeet) ||
(touched.heightInches && errors.heightFeet)
);
if (touched.lengthInches && !touched.lengthFeet) {
setFieldTouched('lengthFeet', true);
}
if (touched.widthInches && !touched.widthFeet) {
setFieldTouched('widthFeet', true);
}
if (touched.heightInches && !touched.heightFeet) {
setFieldTouched('heightFeet', true);
}
// manually turn off 'required' error when page loads if field is empty.
if (values.year === null && !touched.year && errors.year === 'Required') {
setFieldError('year', null);
}
return (
<div className={styles.formContainer}>
<Form className={formStyles.form}>
<SectionWrapper className={classnames(styles.sectionWrapper, formStyles.formSection, 'origin')}>
<h2>Mobile home Information</h2>
<div className="grid-row grid-gap">
<div className="mobile-lg:grid-col-3">
<MaskedTextField
data-testid="year"
name="year"
label="Year"
id="year"
maxLength={4}
mask={Number}
scale={0}
signed="false"
lazy={false}
onChange={() => {
setFieldError('year', null);
}}
onBlur={() => {
setFieldTouched('year', true);
setFieldError('year', null);
validateForm();
}}
required
/>
</div>
</div>
<div className={classnames(styles.formFieldContainer, 'mobile-lg:grid-col-7')}>
<TextField data-testid="make" name="make" label="Make" id="make" required />
<TextField data-testid="model" name="model" label="Model" id="model" required />
</div>
</SectionWrapper>
<SectionWrapper className={classnames(styles.sectionWrapper, formStyles.formSection, 'origin')}>
<h2>Mobile Home Dimensions</h2>
<p>Enter all of the dimensions of the mobile home.</p>
<div>
<Fieldset className={styles.formFieldContainer}>
<div className="labelWrapper">
<legend className="usa-label">Length</legend>
<ErrorMessage display={lengthHasError}>Required</ErrorMessage>
</div>
<div className={classnames(styles.formTextFieldWrapper, 'grid-row grid-gap')}>
<div className="mobile-lg:grid-col-3">
<MaskedTextField
data-testid="lengthFeet"
name="lengthFeet"
id="lengthFeet"
mask={Number}
scale={0} // digits after point, 0 for integers
signed="false" // disallow negative
lazy={false} // immediate masking evaluation
suffix="Feet"
errorClassName={styles.hide}
title="Length in feet"
optional
/>
</div>
<div className="mobile-lg:grid-col-3">
<MaskedTextField
data-testid="lengthInches"
name="lengthInches"
id="lengthInches"
mask={Number}
scale={0} // digits after point, 0 for integers
signed="false" // disallow negative
lazy={false} // immediate masking evaluation
suffix="Inches"
max={11}
errorClassName={styles.hide}
title="Length in inches"
optional
/>
</div>
</div>
</Fieldset>
<Fieldset className={styles.formFieldContainer}>
<div className="labelWrapper">
<legend className="usa-label">Width</legend>
<ErrorMessage display={widthHasError}>Required</ErrorMessage>
</div>
<div className={classnames(styles.formTextFieldWrapper, 'grid-row grid-gap')}>
<div className="mobile-lg:grid-col-3">
<MaskedTextField
data-testid="widthFeet"
name="widthFeet"
id="widthFeet"
mask={Number}
scale={0} // digits after point, 0 for integers
signed="false" // disallow negative
lazy={false} // immediate masking evaluation
suffix="Feet"
errorClassName={styles.hide}
title="Width in feet"
optional
/>
</div>
<div className="mobile-lg:grid-col-3">
<MaskedTextField
data-testid="widthInches"
name="widthInches"
id="widthInches"
mask={Number}
scale={0} // digits after point, 0 for integers
signed="false" // disallow negative
lazy={false} // immediate masking evaluation
suffix="Inches"
max={11}
errorClassName={styles.hide}
title="Width in inches"
optional
/>
</div>
</div>
</Fieldset>
<Fieldset className={styles.formFieldContainer}>
<div className="labelWrapper">
<legend className="usa-label">Height</legend>
<ErrorMessage display={heightHasError}>Required</ErrorMessage>
</div>
<div className={classnames(styles.formTextFieldWrapper, 'grid-row grid-gap')}>
<div className="mobile-lg:grid-col-3">
<MaskedTextField
data-testid="heightFeet"
name="heightFeet"
id="heightFeet"
mask={Number}
scale={0} // digits after point, 0 for integers
signed="false" // disallow negative
lazy={false} // immediate masking evaluation
suffix="Feet"
errorClassName={styles.hide}
title="Height in feet"
optional
/>
</div>
<div className="mobile-lg:grid-col-3">
<MaskedTextField
data-testid="heightInches"
name="heightInches"
id="heightInches"
mask={Number}
scale={0} // digits after point, 0 for integers
signed="false" // disallow negative
lazy={false} // immediate masking evaluation
suffix="Inches"
max={11}
errorClassName={styles.hide}
title="Height in inches"
optional
/>
</div>
</div>
</Fieldset>
</div>
</SectionWrapper>
<SectionWrapper className={formStyles.formSection}>
<Fieldset
legend={
<div className={formStyles.legendContent}>
Remarks <span className={formStyles.optional}>Optional</span>
</div>
}
>
<Label htmlFor="customerRemarks">
Are there things about this mobile home shipment that your counselor or movers should know or
discuss with you?
</Label>

<Callout>
Examples
<ul>
<li>
Dimensions of the mobile home on the trailer are signigicantly different than one would expect
given their individual dimensions
</li>

<li>Access info for your origin or destination address/marina</li>
</ul>
</Callout>

<Field
as={Textarea}
data-testid="remarks"
name="customerRemarks"
className={`${formStyles.remarks}`}
placeholder="Do not itemize your personal property here. Your movers will help do that when they talk to you."
id="customerRemarks"
maxLength={250}
/>
<Hint>
<p>250 characters</p>
</Hint>
</Fieldset>
</SectionWrapper>
<div className={styles.buttonContainer}>
<Button className={styles.backButton} type="button" onClick={onBack} secondary outline>
Back
</Button>
<Button className={styles.saveButton} type="button" onClick={handleSubmit} disabled={!isValid}>
Continue
</Button>
</div>
</Form>
</div>
);
}}
</Formik>
);
};

MobileHomeShipmentForm.propTypes = {
mtoShipment: ShipmentShape,
onBack: func.isRequired,
onSubmit: func.isRequired,
};

MobileHomeShipmentForm.defaultProps = {
mtoShipment: undefined,
};

export default MobileHomeShipmentForm;
Loading
Loading