Skip to content

Commit 4d45819

Browse files
committed
W-20892530 Billing Address Validation
1 parent a5deb6c commit 4d45819

File tree

11 files changed

+408
-17
lines changed

11 files changed

+408
-17
lines changed

packages/template-retail-react-app/app/pages/checkout-one-click/index.jsx

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ const CheckoutOneClick = () => {
147147

148148
// Form for billing address
149149
const billingAddressForm = useForm({
150-
mode: 'onChange',
150+
mode: 'onTouched',
151+
reValidateMode: 'onChange',
151152
shouldUnregister: false,
152153
defaultValues: {...selectedBillingAddress}
153154
})
@@ -200,17 +201,66 @@ const CheckoutOneClick = () => {
200201
let billingAddress
201202
if (billingSameAsShipping && selectedShippingAddress) {
202203
billingAddress = selectedShippingAddress
204+
// Validate that shipping address has required address fields
205+
if (!billingAddress?.address1) {
206+
showError(
207+
formatMessage({
208+
id: 'checkout.error.billing_address_required',
209+
defaultMessage: 'Please enter a billing address.'
210+
})
211+
)
212+
return
213+
}
203214
} else {
204-
const isFormValid = await billingAddressForm.trigger()
215+
// Validate all required address fields (excluding phone for billing)
216+
const fieldsToValidate = [
217+
'address1',
218+
'firstName',
219+
'lastName',
220+
'city',
221+
'stateCode',
222+
'postalCode',
223+
'countryCode'
224+
]
225+
226+
// First, mark all fields as touched so errors will be displayed when validation runs
227+
// This must happen BEFORE trigger() so errors show immediately
228+
fieldsToValidate.forEach((field) => {
229+
const currentValue = billingAddressForm.getValues(field) || ''
230+
billingAddressForm.setValue(field, currentValue, {
231+
shouldValidate: false,
232+
shouldTouch: true
233+
})
234+
})
235+
236+
// Now trigger validation - errors will show because fields are already touched
237+
const isFormValid = await billingAddressForm.trigger(fieldsToValidate)
205238

206239
if (!isFormValid) {
240+
// Payment section should already be open from onPlaceOrder
241+
// Focus on the first name field (first field in the form)
242+
setTimeout(() => {
243+
billingAddressForm.setFocus('firstName')
244+
}, 100)
207245
return
208246
}
209247
billingAddress = billingAddressForm.getValues()
248+
249+
// Double-check that address is present
250+
if (!billingAddress?.address1) {
251+
showError(
252+
formatMessage({
253+
id: 'checkout.error.billing_address_required',
254+
defaultMessage: 'Please enter a billing address.'
255+
})
256+
)
257+
setIsEditingPayment(true)
258+
return
259+
}
210260
}
211261

212262
// eslint-disable-next-line @typescript-eslint/no-unused-vars
213-
const {addressId, creationDate, lastModified, preferred, ...address} = billingAddress
263+
const {addressId, creationDate, lastModified, preferred, phone, ...address} = billingAddress
214264
const latestBasketId = currentBasketQuery.data?.basketId || basket.basketId
215265
return await updateBillingAddressForBasket({
216266
body: address,
@@ -370,15 +420,20 @@ const CheckoutOneClick = () => {
370420
}
371421
})
372422
}
423+
}
373424

374-
// Also persist billing phone as phoneHome
375-
const phoneHome = order?.billingAddress?.phone
376-
if (phoneHome) {
377-
await updateCustomer.mutateAsync({
378-
parameters: {customerId},
379-
body: {phoneHome}
380-
})
381-
}
425+
// Persist phone number as phoneHome from shipping address or basket
426+
// Since billing address no longer has phone, get it from shipping address
427+
// For delivery orders, use shipping address phone; for pickup-only, use basket customerInfo phone
428+
const phoneHome =
429+
deliveryShipments.length > 0
430+
? deliveryShipments[0]?.shippingAddress?.phone
431+
: basket?.customerInfo?.phone
432+
if (phoneHome) {
433+
await updateCustomer.mutateAsync({
434+
parameters: {customerId},
435+
body: {phoneHome}
436+
})
382437
}
383438
} catch (_e) {
384439
// Only surface error if shopper opted to register/save details; otherwise fail silently
@@ -442,6 +497,13 @@ const CheckoutOneClick = () => {
442497
}
443498
}
444499

500+
// Ensure payment section is open before validating billing address
501+
// This ensures the billing form is rendered and visible when we validate
502+
setIsEditingPayment(true)
503+
504+
// Wait for the payment section to open and billing form to render
505+
await new Promise((resolve) => setTimeout(resolve, 0))
506+
445507
// If successful `onBillingSubmit` returns the updated basket. If the form was invalid on
446508
// submit, `undefined` is returned.
447509
const updatedBasket = await onBillingSubmit()

0 commit comments

Comments
 (0)