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

feat(checkout): CHECKOUT-8824 Add Consignment Not Completed Message #2099

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
6 changes: 5 additions & 1 deletion packages/core/src/app/shipping/ConsignmentListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface ConsignmentListItemProps {
isLoading: boolean;
shippingQuoteFailedMessage: string;
onUnhandledError(error: Error): void;
resetErrorConsignmentNumber(): void;
}

const ConsignmentListItem: FunctionComponent<ConsignmentListItemProps> = ({
Expand All @@ -31,13 +32,15 @@ const ConsignmentListItem: FunctionComponent<ConsignmentListItemProps> = ({
isLoading,
shippingQuoteFailedMessage,
onUnhandledError,
resetErrorConsignmentNumber,
}: ConsignmentListItemProps) => {

const { checkoutService: { deleteConsignment } } = useCheckout();

const handleClose = async () => {
await deleteConsignment(consignment.id);
}
resetErrorConsignmentNumber();
};

return (
<div className='consignment-container'>
Expand Down Expand Up @@ -68,6 +71,7 @@ const ConsignmentListItem: FunctionComponent<ConsignmentListItemProps> = ({
<MultiShippingOptionsV2
consignment={consignment}
isLoading={isLoading}
resetErrorConsignmentNumber={resetErrorConsignmentNumber}
shippingQuoteFailedMessage={shippingQuoteFailedMessage}
/>
</div>
Expand Down
12 changes: 11 additions & 1 deletion packages/core/src/app/shipping/MultiShippingFormV2.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,19 @@ describe('MultiShippingFormV2 Component', () => {
const addShippingDestinationButton = screen.getByRole('button', { name: 'Add new destination' });

expect(addShippingDestinationButton).toBeInTheDocument();

await userEvent.click(addShippingDestinationButton);

expect(screen.queryByText(/Please complete the address/i)).not.toBeInTheDocument();

await userEvent.click(addShippingDestinationButton);

expect(screen.getByText('Destination #2')).toBeInTheDocument();
expect(
screen.getByText(
'Please complete the address, item allocation, and method selection for Destination #2.',
),
).toBeInTheDocument();

await waitFor(() => {
expect(screen.queryByText('No items allocated')).not.toBeInTheDocument();
Expand Down Expand Up @@ -521,7 +531,7 @@ describe('MultiShippingFormV2 Component', () => {
jest.spyOn(checkoutService, 'deleteConsignment').mockReturnValue(
Promise.resolve(checkoutService.getState()),
);

jest.spyOn(checkoutState.data, 'getCheckout').mockReturnValue({
...getCheckout(),
consignments: [{
Expand Down
39 changes: 35 additions & 4 deletions packages/core/src/app/shipping/MultiShippingFormV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const MultiShippingFormV2: FunctionComponent<MultiShippingFormV2Props> = ({
onUnhandledError,
}: MultiShippingFormV2Props) => {
const [isAddShippingDestination, setIsAddShippingDestination] = useState(false);
const [errorConsignmentNumber, setErrorConsignmentNumber] = useState<number | undefined>();

const {
checkoutState: {
Expand All @@ -47,8 +48,9 @@ const MultiShippingFormV2: FunctionComponent<MultiShippingFormV2Props> = ({
const consignments = getConsignments() || EMPTY_ARRAY;
const config = getConfig();

const isEveryConsignmentHasShippingOption = hasSelectedShippingOptions(consignments);
const shouldDisableSubmit = useMemo(() => {
return isLoading || !!unassignedLineItems.length || !hasSelectedShippingOptions(consignments);
return isLoading || !!unassignedLineItems.length || !isEveryConsignmentHasShippingOption;
}, [isLoading, consignments]);

if (!config) {
Expand All @@ -63,8 +65,23 @@ const MultiShippingFormV2: FunctionComponent<MultiShippingFormV2Props> = ({
} = config;

const handleAddShippingDestination = () => {
setIsAddShippingDestination(true);
}
if (
consignments.length > 0 &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍹 It appears redundant because it has already checked in hasSelectedShippingOptions

Suggested change
consignments.length > 0 &&

!isAddShippingDestination &&
!isEveryConsignmentHasShippingOption
) {
const errorConsignmentIndex = consignments.findIndex(
(consignment) => !consignment.selectedShippingOption,
);
Comment on lines +73 to +75
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to the inconsistency of the consignment order, it is better to find the index each time to locate the unfinished consignment.


setErrorConsignmentNumber(errorConsignmentIndex + 1);
} else if (isAddShippingDestination) {
setErrorConsignmentNumber(consignments.length + 1);
} else {
setErrorConsignmentNumber(undefined);
setIsAddShippingDestination(true);
}
};

const hasUnassignedItems = shippableItemsCount > 0;

Expand All @@ -79,6 +96,9 @@ const MultiShippingFormV2: FunctionComponent<MultiShippingFormV2Props> = ({
<TranslatedString id="shipping.multishipping_all_items_allocated_message" />
</Alert>;
}
const resetErrorConsignmentNumber = () => {
setErrorConsignmentNumber(undefined);
};

return (
<>
Expand All @@ -92,6 +112,7 @@ const MultiShippingFormV2: FunctionComponent<MultiShippingFormV2Props> = ({
isLoading={isLoading}
key={consignment.id}
onUnhandledError={onUnhandledError}
resetErrorConsignmentNumber={resetErrorConsignmentNumber}
shippingQuoteFailedMessage={shippingQuoteFailedMessage}
/>
))}
Expand All @@ -105,11 +126,21 @@ const MultiShippingFormV2: FunctionComponent<MultiShippingFormV2Props> = ({
setIsAddShippingDestination={setIsAddShippingDestination}
/>)
}
{hasUnassignedItems &&
{hasUnassignedItems &&
<Button className='add-consignment-button' onClick={handleAddShippingDestination} variant={ButtonVariant.Secondary}>
Add new destination
</Button>
}
{Boolean(errorConsignmentNumber) && (
<div className="form-field--error">
<span className="form-inlineMessage">
<TranslatedString
data={{ consignmentNumber: errorConsignmentNumber }}
id="shipping.multishipping_consignment_not_completed_error"
/>
</span>
</div>
)}
<MultiShippingFormV2Footer
isLoading={isLoading}
shouldDisableSubmit={shouldDisableSubmit}
Expand Down
70 changes: 58 additions & 12 deletions packages/core/src/app/shipping/MultiShippingV2.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { noop } from 'lodash';
import React, { FunctionComponent } from 'react';
import { act } from 'react-dom/test-utils';

import {
AnalyticsContextProps,
Expand Down Expand Up @@ -110,21 +111,61 @@ describe('Multi-shipping V2', () => {

await checkout.waitForShippingStep();

checkout.updateCheckout('post', '/checkouts/xxxxxxxxxx-xxxx-xxax-xxxx-xxxxxx/consignments', {
...cartReadyForMultiShipping,
consignments: [
{
...consignment,
},
],
checkout.updateCheckout(
'post',
'/checkouts/xxxxxxxxxx-xxxx-xxax-xxxx-xxxxxx/consignments',
{
...cartReadyForMultiShipping,
consignments: [
{
...consignment,
availableShippingOptions: undefined,
selectedShippingOption: undefined,
},
],
},
);
// eslint-disable-next-line testing-library/no-unnecessary-act
await act(async () => {
await userEvent.click(screen.getByText(/Ship to multiple addresses/i));
await userEvent.click(screen.getByText(/Enter a new address/i));
await userEvent.click(screen.getByText(/789 Test Ave/i));
await userEvent.click(screen.getByText(/Allocate items/i));
await userEvent.click(screen.getByText(/Select all items left/i));
await userEvent.click(screen.getByRole('button', { name: 'Allocate' }));
await userEvent.click(
await screen.findByRole('button', { name: 'Add new destination' }),
);
});

await userEvent.click(screen.getByText(/Ship to multiple addresses/i));
await userEvent.click(screen.getByText(/Enter a new address/i));
checkout.updateCheckout(
'post',
'/checkouts/xxxxxxxxxx-xxxx-xxax-xxxx-xxxxxx/consignments',
{
...cartReadyForMultiShipping,
consignments: [
{
...consignment,
},
],
},
);

expect(
screen.getByText(
"Unfortunately one or more items in your cart can't be shipped to your location. Please choose a different delivery address.",
),
).toBeInTheDocument();
expect(
screen.getByText(
'Please complete the address, item allocation, and method selection for Destination #1.',
),
).toBeInTheDocument();

await userEvent.click(
screen.getByText(/checkout test, 130 Pitt St, Sydney, New South Wales, AU, 2000/i),
);
await userEvent.click(screen.getByText(/123 Example St/i));
await userEvent.click(screen.getByText(/Allocate items/i));
await userEvent.click(screen.getByText(/Select all items left/i));
await userEvent.click(screen.getByRole('button', { name: 'Allocate' }));

expect(await screen.findAllByRole('radio')).toHaveLength(2);
expect(screen.getByLabelText(/Pickup In Store/i)).toBeInTheDocument();
Expand Down Expand Up @@ -155,5 +196,10 @@ describe('Multi-shipping V2', () => {
.getAttribute('value');

expect(selectedShippingOptionValue2).toBe('option-id-flat-rate');
expect(
screen.queryByText(
'Please complete the address, item allocation, and method selection for Destination #1.',
),
).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,21 @@ interface MultiShippingOptionsV2Props {
consignment: Consignment;
isLoading: boolean;
shippingQuoteFailedMessage: string;
resetErrorConsignmentNumber(): void;
}

export const MultiShippingOptionsV2 = ({
consignment,
isLoading,
resetErrorConsignmentNumber,
shippingQuoteFailedMessage,
}: MultiShippingOptionsV2Props) => {
const { checkoutService, checkoutState } = useCheckout();

const selectShippingOption = checkoutService.selectConsignmentShippingOption;
const selectShippingOption = async (consignmentId: string, shippingOptionId: string) => {
await checkoutService.selectConsignmentShippingOption(consignmentId, shippingOptionId);
resetErrorConsignmentNumber();
};
const isLoadingOptions = isLoadingSelector(checkoutState, isLoading)(consignment.id);

return (
Expand Down
1 change: 1 addition & 0 deletions packages/locale/src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@
"select_shipping_address_text": "Please select a shipping address in order to see shipping quotes",
"shipping_address_heading": "Shipping Address",
"multishipping_consignment_index_heading": "Destination #{consignmentNumber}",
"multishipping_consignment_not_completed_error": "Please complete the address, item allocation, and method selection for Destination #{consignmentNumber}.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍹

Suggested change
"multishipping_consignment_not_completed_error": "Please complete the address, item allocation, and method selection for Destination #{consignmentNumber}.",
"multishipping_incomplete_consignment_error": "Please complete the address, item allocation, and method selection for Destination #{consignmentNumber}.",

"multishipping_address_heading": "Choose where to ship each item",
"multishipping_address_heading_guest": "Please sign in first",
"multishipping_guest_intro": "To ship your items to multiple addresses you need to",
Expand Down