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

B-21364 FF: UB shipments selectable for OCONUS duty locations #13917

Merged
merged 15 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions src/components/Customer/SelectableCard.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
@import '../../shared/styles/colors';
@import '../../shared/styles/_variables';

p+.cardContainer {
p + .cardContainer {
margin-top: 0px;
}

.cardContainer+.cardContainer {
.cardContainer + .cardContainer {
@include u-margin-top('105');
}

Expand Down Expand Up @@ -90,6 +90,7 @@ p+.cardContainer {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0);
@include u-padding-bottom('205');
padding-left: 50px;
padding-right: 40px;
}

@media (max-width: $tablet) {
Expand Down
47 changes: 38 additions & 9 deletions src/components/Customer/modals/MoveInfoModal/MoveInfoModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,25 @@ import { Button } from '@trussworks/react-uswds';

import Modal, { ModalTitle, ModalClose, ModalActions, connectModal } from 'components/Modal/Modal';

export const MoveInfoModal = ({ closeModal, enablePPM }) => (
<Modal>
export const MoveInfoModal = ({ closeModal, enablePPM, enableUB, hasOconusDutyLocation }) => (
<Modal data-testid="moveInfoModal">
<ModalClose handleClick={closeModal} />
<ModalTitle>
<h3>More info about shipments</h3>
<h3 data-testid="moveInfoModalHeading">More info about shipments</h3>
</ModalTitle>

<h4>
<strong>HHG: Professional movers pack and ship your things, the government pays</strong>
</h4>
<p>The moving company works out details with you, but handles everything.</p>
<p data-testid="hhgSubHeading">The moving company works out details with you, but handles everything.</p>
<h5>Pros</h5>
<ul>
<ul data-testid="hhgProsList">
<li>Everything is packed and moved for you</li>
<li>Expert movers care for your things</li>
<li>Anything damaged in professional shipments will be replaced</li>
</ul>
<h5>Cons</h5>
<ul>
<ul data-testid="hhgConsList">
<li>Can only move on weekdays</li>
<li>May have to work around availability of movers</li>
</ul>
Expand All @@ -31,22 +31,47 @@ export const MoveInfoModal = ({ closeModal, enablePPM }) => (
<h4>
<strong>PPM: You get your things packed and moved, the government pays you</strong>
</h4>
<p>You pack and move your own things, or arrange for someone else do it for you.</p>
<p data-testid="ppmSubHeading">You pack and move your own things, or arrange for someone else do it for you.</p>
<h5>Pros</h5>
<ul>
<ul data-testid="ppmProsList">
<li>Keep your things with you at all times</li>
<li>Get paid for the weight you move</li>
<li>Flexible dates, routes, timing</li>
<li>You can hire movers, equipment, or portable storage</li>
</ul>
<h5>Cons</h5>
<ul>
<ul data-testid="ppmConsList">
<li>You pack and move everything</li>
<li>You’re responsible if your things get damaged — no compensation</li>
<li>The more you own, the more you have to do</li>
</ul>
</>
)}
{enableUB && hasOconusDutyLocation && (
<>
<h4>
<strong>
UB: Professional movers pack and ship your more essential personal property, the government pays
</strong>
</h4>
<p data-testid="ubSubHeading">The moving company works out details with you, but handles everything.</p>
<h5>Pros</h5>
<ul data-testid="ubProsList">
<li>Everything is packed and moved for you</li>
<li>Expert movers care for your things</li>
<li>Anything damaged in professional shipments will be replaced</li>
<li>Essential items are packed as a separate shipment</li>
<li>Shorter allowable transit time than a standard HHG shipment; should arrive sooner at your destination</li>
</ul>
<h5>Cons</h5>
<ul data-testid="ubConsList">
<li>Can only move on weekdays</li>
<li>May have to work around availability of movers</li>
<li>Your UB shipment has its own weight limitation</li>
<li>Only certain kinds of personal property are allowed in a UB shipment (check with your counselor)</li>
</ul>
</>
)}
<ModalActions>
<Button secondary type="button" onClick={closeModal}>
Got it
Expand All @@ -58,11 +83,15 @@ export const MoveInfoModal = ({ closeModal, enablePPM }) => (
MoveInfoModal.propTypes = {
closeModal: PropTypes.func,
enablePPM: PropTypes.bool,
enableUB: PropTypes.bool,
hasOconusDutyLocation: PropTypes.bool,
};

MoveInfoModal.defaultProps = {
closeModal: () => {},
enablePPM: true,
enableUB: true,
hasOconusDutyLocation: true,
};

MoveInfoModal.displayName = 'MoveInfoModal';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';

import '@testing-library/jest-dom';
import { MoveInfoModal } from './MoveInfoModal';

describe('MoveInfoModal', () => {
const mockCloseModal = jest.fn();

// renders the MoveInfoModal with default props
test('renders MoveInfoModal with default props', () => {
render(<MoveInfoModal closeModal={mockCloseModal} />);
// checks if MoveInfoModal heading is present
expect(screen.getByTestId('moveInfoModalHeading')).toHaveTextContent('More info about shipments');
// checks if HHG section is rendered
expect(screen.getByText(/Professional movers pack and ship your things/)).toBeInTheDocument();
expect(screen.getByTestId('hhgSubHeading')).toBeInTheDocument();
expect(screen.getByTestId('hhgProsList')).toBeInTheDocument();
expect(screen.getByTestId('hhgConsList')).toBeInTheDocument();
});

// checks if PPM section is rendered when enablePPM is true
test('renders PPM section when enablePPM is true', () => {
render(<MoveInfoModal closeModal={mockCloseModal} enablePPM />);
expect(screen.getByText(/PPM: You get your things packed and moved/)).toBeInTheDocument();
expect(screen.getByTestId('ppmSubHeading')).toBeInTheDocument();
expect(screen.getByTestId('ppmProsList')).toBeInTheDocument();
expect(screen.getByTestId('ppmConsList')).toBeInTheDocument();
});

test('does not render PPM section when enablePPM is false', () => {
render(<MoveInfoModal closeModal={mockCloseModal} enablePPM={false} />);
expect(screen.queryByText(/PPM: You get your things packed and moved/)).toBeNull();
expect(screen.queryByTestId('ppmSubHeading')).not.toBeInTheDocument();
expect(screen.queryByTestId('ppmProsList')).not.toBeInTheDocument();
expect(screen.queryByTestId('ppmConsList')).not.toBeInTheDocument();
});

// tests UB section based on enableUB and hasOconusDutyLocation
test('renders UB section when enableUB and hasOconusDutyLocation are true', () => {
render(<MoveInfoModal closeModal={mockCloseModal} enableUB hasOconusDutyLocation />);
expect(
screen.getByText(/UB: Professional movers pack and ship your more essential personal property/),
).toBeInTheDocument();
expect(screen.getByTestId('ubSubHeading')).toBeInTheDocument();
expect(screen.getByTestId('ubProsList')).toBeInTheDocument();
expect(screen.getByTestId('ubConsList')).toBeInTheDocument();
});

test('does not render UB section when enableUB is false', () => {
render(<MoveInfoModal closeModal={mockCloseModal} enableUB={false} hasOconusDutyLocation />);

expect(
screen.queryByText(/UB: Professional movers pack and ship your more essential personal property/),
).toBeNull();
expect(screen.queryByTestId('ubSubHeading')).not.toBeInTheDocument();
expect(screen.queryByTestId('ubProsList')).not.toBeInTheDocument();
expect(screen.queryByTestId('ubConsList')).not.toBeInTheDocument();
});

test('does not render UB section when hasOconusDutyLocation is false', () => {
render(<MoveInfoModal closeModal={mockCloseModal} enableUB hasOconusDutyLocation={false} />);

expect(
screen.queryByText(/UB: Professional movers pack and ship your more essential personal property/),
).toBeNull();
expect(screen.queryByTestId('ubSubHeading')).not.toBeInTheDocument();
expect(screen.queryByTestId('ubProsList')).not.toBeInTheDocument();
expect(screen.queryByTestId('ubConsList')).not.toBeInTheDocument();
});

// tests "Got it" button functionality
test('calls closeModal function when "Got it" button is clicked', () => {
render(<MoveInfoModal closeModal={mockCloseModal} />);

const button = screen.getByRole('button', { name: /Got it/ });
fireEvent.click(button);

// Verify the closeModal function was called
expect(mockCloseModal).toHaveBeenCalled();
});
});
35 changes: 34 additions & 1 deletion src/pages/MyMove/SelectShipmentType.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { generalRoutes, customerRoutes } from 'constants/routes';
import styles from 'pages/MyMove/SelectShipmentType.module.scss';
import { loadMTOShipments as loadMTOShipmentsAction } from 'shared/Entities/modules/mtoShipments';
import { updateMove as updateMoveAction } from 'store/entities/actions';
import { selectMTOShipmentsForCurrentMove } from 'store/entities/selectors';
import { selectMTOShipmentsForCurrentMove, selectOrdersForLoggedInUser } from 'store/entities/selectors';
import formStyles from 'styles/form.module.scss';
import { MoveTaskOrderShape } from 'types/order';
import { ShipmentShape } from 'types/shipment';
Expand All @@ -40,6 +40,7 @@ export class SelectShipmentType extends Component {
enableNTSR: false,
enableBoat: false,
enableMobileHome: false,
enableUB: false,
};
}

Expand Down Expand Up @@ -71,6 +72,11 @@ export class SelectShipmentType extends Component {
enableMobileHome: enabled,
});
});
isBooleanFlagEnabled(FEATURE_FLAG_KEYS.UNACCOMPANIED_BAGGAGE).then((enabled) => {
this.setState({
enableUB: enabled,
});
});
}

setShipmentType = (e) => {
Expand Down Expand Up @@ -111,6 +117,7 @@ export class SelectShipmentType extends Component {
router: { navigate },
move,
mtoShipments,
orders,
} = this.props;
const {
shipmentType,
Expand All @@ -122,6 +129,7 @@ export class SelectShipmentType extends Component {
enableNTSR,
enableBoat,
enableMobileHome,
enableUB,
errorMessage,
} = this.state;

Expand All @@ -147,6 +155,14 @@ export class SelectShipmentType extends Component {

const mobileHomeCardText = 'Provide information about your mobile home.';

const ubCardText = shipmentInfo.isUBSelectable
? 'Certain personal property items are packed and moved by professionals, paid for by the government. Subject to item type and weight limitations. This is an unaccompanied baggage shipment (UB).'
: 'Talk with your movers directly if you want to add or change shipments.';

const hasOconusDutyLocation = orders[0]
? orders[0].origin_duty_location.address.isOconus || orders[0].new_duty_location.address.isOconus
: false;
traskowskycaci marked this conversation as resolved.
Show resolved Hide resolved
danieljordan-caci marked this conversation as resolved.
Show resolved Hide resolved

const selectableCardDefaultProps = {
onChange: (e) => this.setShipmentType(e),
name: 'shipmentType',
Expand Down Expand Up @@ -213,6 +229,19 @@ export class SelectShipmentType extends Component {
/>
)}

{enableUB && hasOconusDutyLocation && (
<SelectableCard
{...selectableCardDefaultProps}
label="Movers pack and ship limited, essential personal property to arrive earlier (UB)"
value={SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE}
id={SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE}
cardText={ubCardText}
checked={shipmentType === SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE && shipmentInfo.isUBSelectable}
disabled={!shipmentInfo.isUBSelectable}
onHelpClick={this.toggleMoveInfoModal}
/>
)}

{enableNTS || enableNTSR ? (
<>
<h3 className={styles.longTermStorageHeader} data-testid="long-term-storage-heading">
Expand Down Expand Up @@ -310,6 +339,8 @@ export class SelectShipmentType extends Component {
<ConnectedMoveInfoModal
isOpen={showMoveInfoModal}
enablePPM={enablePPM}
enableUB={enableUB}
hasOconusDutyLocation={hasOconusDutyLocation}
closeModal={this.toggleMoveInfoModal}
/>
<ConnectedStorageInfoModal
Expand Down Expand Up @@ -345,10 +376,12 @@ const mapStateToProps = (state, ownProps) => {
} = ownProps;
const move = selectMove(state, moveId);
const mtoShipments = selectMTOShipmentsForCurrentMove(state);
const orders = selectOrdersForLoggedInUser(state);

return {
move,
mtoShipments,
orders,
};
};

Expand Down
42 changes: 42 additions & 0 deletions src/pages/MyMove/SelectShipmentType.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,31 @@ const defaultProps = {
status: 'DRAFT',
},
mtoShipments: [],
orders: [],
};

const oconusOriginDutyLocationProps = {
router: { navigate: noop },
updateMove: noop,
loadMTOShipments: noop,
move: {
status: 'DRAFT',
},
mtoShipments: [],
orders: [
{
origin_duty_location: {
address: {
isOconus: true,
},
},
new_duty_location: {
address: {
isOconus: false,
},
},
},
],
};

export const Submitted = () => {
Expand Down Expand Up @@ -115,3 +140,20 @@ export const WithNTSAndNTSRComplete = () => {
</MockProviders>
);
};

export const WithUBComplete = () => {
const props = {
...oconusOriginDutyLocationProps,
mtoShipments: [
{
shipmentType: SHIPMENT_OPTIONS.UNACCOMPANIED_BAGGAGE,
},
],
};

return (
<MockProviders>
<SelectShipmentType {...props} />
</MockProviders>
);
};
Loading