diff --git a/packages/template-retail-react-app/app/pages/checkout-one-click/index.test.js b/packages/template-retail-react-app/app/pages/checkout-one-click/index.test.js index 2c34c1a5b9..28faa58c7c 100644 --- a/packages/template-retail-react-app/app/pages/checkout-one-click/index.test.js +++ b/packages/template-retail-react-app/app/pages/checkout-one-click/index.test.js @@ -430,7 +430,7 @@ describe('Checkout One Click', () => { } // Wait for continue button and click - const continueBtn = await screen.findByText(/continue to shipping address/i) + const continueBtn = await screen.findByText(/continue to payment/i) await user.click(continueBtn) // Verify we skip directly to payment @@ -524,7 +524,7 @@ describe('Checkout One Click', () => { } // Wait for continue button and click - const continueBtn = await screen.findByText(/continue to shipping address/i) + const continueBtn = await screen.findByText(/continue to payment/i) await user.click(continueBtn) // Verify we continue to payment diff --git a/packages/template-retail-react-app/app/pages/checkout-one-click/partials/one-click-contact-info.jsx b/packages/template-retail-react-app/app/pages/checkout-one-click/partials/one-click-contact-info.jsx index 5984873c5d..28348f5216 100644 --- a/packages/template-retail-react-app/app/pages/checkout-one-click/partials/one-click-contact-info.jsx +++ b/packages/template-retail-react-app/app/pages/checkout-one-click/partials/one-click-contact-info.jsx @@ -50,6 +50,7 @@ import {API_ERROR_MESSAGE} from '@salesforce/retail-react-app/app/constants' import {isValidEmail} from '@salesforce/retail-react-app/app/utils/email-utils' import {formatPhoneNumber} from '@salesforce/retail-react-app/app/utils/phone-utils' import useMultiSite from '@salesforce/retail-react-app/app/hooks/use-multi-site' +import {isPickupShipment} from '@salesforce/retail-react-app/app/utils/shipment-utils' const ContactInfo = ({isSocialEnabled = false, idps = [], onRegisteredUserChoseGuest}) => { const {formatMessage} = useIntl() @@ -70,6 +71,14 @@ const ContactInfo = ({isSocialEnabled = false, idps = [], onRegisteredUserChoseG const {step, STEPS, goToStep, goToNextStep, setContactPhone} = useCheckout() + // Determine if this order has delivery shipments + const shipments = basket?.shipments || [] + const productItems = basket?.productItems || [] + const shipmentsWithItems = shipments.filter((s) => + productItems.some((i) => i.shipmentId === s.shipmentId) + ) + const hasDeliveryShipments = shipmentsWithItems.some((s) => !isPickupShipment(s)) + const form = useForm({ defaultValues: { email: customer?.email || basket?.customerInfo?.email || '', @@ -615,10 +624,17 @@ const ContactInfo = ({isSocialEnabled = false, idps = [], onRegisteredUserChoseG isLoading={isSubmitting} disabled={isSubmitting} > - + {hasDeliveryShipments ? ( + + ) : ( + + )} )} diff --git a/packages/template-retail-react-app/app/pages/checkout-one-click/partials/one-click-contact-info.test.js b/packages/template-retail-react-app/app/pages/checkout-one-click/partials/one-click-contact-info.test.js index 12403f2b5b..73cdbefb1a 100644 --- a/packages/template-retail-react-app/app/pages/checkout-one-click/partials/one-click-contact-info.test.js +++ b/packages/template-retail-react-app/app/pages/checkout-one-click/partials/one-click-contact-info.test.js @@ -48,7 +48,9 @@ const mockUseCurrentBasket = jest.fn(() => ({ basketId: 'test-basket-id', customerInfo: { email: null - } + }, + shipments: [{shipmentId: 'shipment-1', shipmentType: 'delivery'}], + productItems: [{productId: 'product-1', shipmentId: 'shipment-1'}] }, derivedData: { hasBasket: true, @@ -126,6 +128,17 @@ beforeEach(() => { jest.clearAllMocks() // Default: allow OTP authorization so modal can open unless a test overrides it mockAuthHelperFunctions[AuthHelpers.AuthorizePasswordless].mutateAsync.mockResolvedValue({}) + // Reset basket mock to default (delivery shipment) + mockUseCurrentBasket.mockReturnValue({ + data: { + basketId: 'test-basket-id', + customerInfo: {email: null}, + shipments: [{shipmentId: 'shipment-1', shipmentType: 'delivery'}], + productItems: [{productId: 'product-1', shipmentId: 'shipment-1'}] + }, + derivedData: {hasBasket: true, totalItems: 1}, + refetch: jest.fn() + }) }) afterEach(() => {}) @@ -405,6 +418,43 @@ describe('ContactInfo Component', () => { }) }) + test('renders "Continue to Payment" button for BOPIS-only orders', async () => { + // Mock BOPIS-only basket + mockUseCurrentBasket.mockReturnValue({ + data: { + basketId: 'test-basket-id', + customerInfo: {email: null}, + shipments: [{shipmentId: 'pickup-1', c_fromStoreId: 'store-123'}], + productItems: [{productId: 'product-1', shipmentId: 'pickup-1'}] + }, + derivedData: {hasBasket: true, totalItems: 1}, + refetch: jest.fn() + }) + + // Mock the passwordless login to fail (guest checkout) + mockAuthHelperFunctions[AuthHelpers.AuthorizePasswordless].mutateAsync.mockRejectedValue( + new Error('Email not found') + ) + + const {user} = renderWithProviders() + + const emailInput = screen.getByLabelText('Email') + await user.type(emailInput, validEmail) + fireEvent.blur(emailInput) + + await waitFor(() => { + const continueBtn = screen.getByRole('button', { + name: /continue to payment/i + }) + expect(continueBtn).toBeEnabled() + }) + + // Verify "Continue to Shipping Address" is NOT shown + expect( + screen.queryByRole('button', {name: /continue to shipping address/i}) + ).not.toBeInTheDocument() + }) + test('requires phone for guest shoppers on submit', async () => { // Ensure guest path (no OTP modal) mockAuthHelperFunctions[AuthHelpers.AuthorizePasswordless].mutateAsync.mockRejectedValue( diff --git a/packages/template-retail-react-app/app/static/translations/compiled/en-GB.json b/packages/template-retail-react-app/app/static/translations/compiled/en-GB.json index 8a492ef050..89d8658dd3 100644 --- a/packages/template-retail-react-app/app/static/translations/compiled/en-GB.json +++ b/packages/template-retail-react-app/app/static/translations/compiled/en-GB.json @@ -1547,6 +1547,12 @@ "value": "Checkout as Guest" } ], + "contact_info.button.continue_to_payment": [ + { + "type": 0, + "value": "Continue to Payment" + } + ], "contact_info.button.continue_to_shipping_address": [ { "type": 0, diff --git a/packages/template-retail-react-app/app/static/translations/compiled/en-US.json b/packages/template-retail-react-app/app/static/translations/compiled/en-US.json index 8a492ef050..89d8658dd3 100644 --- a/packages/template-retail-react-app/app/static/translations/compiled/en-US.json +++ b/packages/template-retail-react-app/app/static/translations/compiled/en-US.json @@ -1547,6 +1547,12 @@ "value": "Checkout as Guest" } ], + "contact_info.button.continue_to_payment": [ + { + "type": 0, + "value": "Continue to Payment" + } + ], "contact_info.button.continue_to_shipping_address": [ { "type": 0, diff --git a/packages/template-retail-react-app/app/static/translations/compiled/en-XA.json b/packages/template-retail-react-app/app/static/translations/compiled/en-XA.json index f0156c5ca5..2c641e591c 100644 --- a/packages/template-retail-react-app/app/static/translations/compiled/en-XA.json +++ b/packages/template-retail-react-app/app/static/translations/compiled/en-XA.json @@ -3147,6 +3147,20 @@ "value": "]" } ], + "contact_info.button.continue_to_payment": [ + { + "type": 0, + "value": "[" + }, + { + "type": 0, + "value": "Ƈǿǿƞŧīƞŭŭḗḗ ŧǿǿ Ƥȧȧẏḿḗḗƞŧ" + }, + { + "type": 0, + "value": "]" + } + ], "contact_info.button.continue_to_shipping_address": [ { "type": 0, diff --git a/packages/template-retail-react-app/translations/en-GB.json b/packages/template-retail-react-app/translations/en-GB.json index 6be89ef2c3..52e1ef67f8 100644 --- a/packages/template-retail-react-app/translations/en-GB.json +++ b/packages/template-retail-react-app/translations/en-GB.json @@ -601,6 +601,9 @@ "contact_info.button.checkout_as_guest": { "defaultMessage": "Checkout as Guest" }, + "contact_info.button.continue_to_payment": { + "defaultMessage": "Continue to Payment" + }, "contact_info.button.continue_to_shipping_address": { "defaultMessage": "Continue to Shipping Address" }, diff --git a/packages/template-retail-react-app/translations/en-US.json b/packages/template-retail-react-app/translations/en-US.json index 6be89ef2c3..52e1ef67f8 100644 --- a/packages/template-retail-react-app/translations/en-US.json +++ b/packages/template-retail-react-app/translations/en-US.json @@ -601,6 +601,9 @@ "contact_info.button.checkout_as_guest": { "defaultMessage": "Checkout as Guest" }, + "contact_info.button.continue_to_payment": { + "defaultMessage": "Continue to Payment" + }, "contact_info.button.continue_to_shipping_address": { "defaultMessage": "Continue to Shipping Address" },