From 797bf0833da375def1d251b215b81ec959103796 Mon Sep 17 00:00:00 2001 From: Phil Bennett Date: Tue, 28 Oct 2025 12:57:28 -0500 Subject: [PATCH 01/13] sync latest checkout library changes - Tracking field additions - draftOrder and draftOrderTotals refactor - Address autocomplete options - fix country & region matching --- .../checkout/address/address-form.tsx | 273 ++++--------- .../checkout/address/country-region-data.ts | 359 +++++++++--------- .../checkout/address/get-country-region.ts | 6 +- .../address/utils/check-is-valid-address.ts | 2 +- .../address/utils/use-address-verification.ts | 17 +- .../utils/use-clear-billing-address.ts | 25 ++ .../address/utils/use-sync-billing-address.ts | 79 ++++ .../src/components/checkout/checkout.tsx | 8 +- .../checkout/contact/phone-input.tsx | 23 +- .../checkout/delivery/delivery-method.tsx | 16 +- .../utils/use-apply-fulfillment-location.ts | 7 +- .../checkout/discount/discount-standalone.tsx | 8 +- .../checkout/discount/discount-tag.tsx | 2 +- .../discount/utils/use-discount-apply.ts | 123 +++++- .../checkout/form/checkout-form-container.tsx | 39 +- .../checkout/form/checkout-form.tsx | 21 +- .../checkout/order/use-draft-order-sync.ts | 57 ++- .../checkout/order/use-draft-order.ts | 25 +- .../checkout/order/use-update-order.ts | 18 +- .../checkout/order/use-update-taxes.ts | 11 +- .../checkout-buttons/credit-card/square.tsx | 4 +- .../checkout-buttons/express/godaddy.tsx | 131 ++++--- .../checkout-buttons/offline/default.tsx | 4 +- .../payment/checkout-buttons/paze/godaddy.tsx | 79 ++-- .../checkout/payment/lazy-payment-loader.tsx | 2 + .../checkout/payment/payment-form.tsx | 48 ++- .../payment-methods/credit-card/container.tsx | 2 +- .../payment-methods/credit-card/godaddy.tsx | 97 +++-- .../payment/utils/conditional-providers.tsx | 12 +- .../payment/utils/payment-address-toggle.tsx | 67 ++++ .../payment/utils/stripe-provider.tsx | 2 +- .../utils/use-build-payment-request.ts | 8 +- .../payment/utils/use-load-poynt-collect.ts | 63 ++- .../checkout/payment/utils/use-load-square.ts | 41 +- .../payment/utils/use-stripe-checkout.ts | 5 +- .../utils/use-stripe-payment-intent.ts | 2 +- .../checkout/pickup/local-pickup.tsx | 4 - .../checkout/shipping/shipping-method.tsx | 154 ++++++-- .../utils/use-apply-shipping-method.ts | 64 +++- .../utils/use-draft-order-shipping-methods.ts | 9 +- .../utils/use-remove-shipping-method.ts | 61 ++- .../components/checkout/tips/tips-form.tsx | 2 +- .../src/components/checkout/totals/totals.tsx | 16 +- .../totals/utils/use-is-order-free.ts | 2 +- .../checkout/utils/checkout-transformers.ts | 30 +- .../react/src/components/ui/autocomplete.tsx | 10 + packages/react/src/components/ui/button.tsx | 3 +- packages/react/src/components/ui/dialog.tsx | 43 ++- packages/react/src/components/ui/sheet.tsx | 37 +- packages/react/src/lib/godaddy/godaddy.ts | 98 ++--- .../react/src/lib/godaddy/graphql-env.d.ts | 17 +- packages/react/src/lib/godaddy/mutations.ts | 13 + packages/react/src/lib/godaddy/queries.ts | 32 -- packages/react/src/server.ts | 24 +- .../react/src/tracking/event-properties.ts | 5 +- .../react/src/tracking/tracking-provider.tsx | 10 +- packages/react/src/types.ts | 13 +- 57 files changed, 1435 insertions(+), 898 deletions(-) create mode 100644 packages/react/src/components/checkout/address/utils/use-clear-billing-address.ts create mode 100644 packages/react/src/components/checkout/address/utils/use-sync-billing-address.ts create mode 100644 packages/react/src/components/checkout/payment/utils/payment-address-toggle.tsx diff --git a/packages/react/src/components/checkout/address/address-form.tsx b/packages/react/src/components/checkout/address/address-form.tsx index 3653881e..22a40e23 100644 --- a/packages/react/src/components/checkout/address/address-form.tsx +++ b/packages/react/src/components/checkout/address/address-form.tsx @@ -5,18 +5,14 @@ import { getRegions, hasRegionData, } from "@/components/checkout/address/get-country-region"; -// TEMPORARY: Comment out autocomplete/verification imports - will be restored later -// import { checkIsValidAddress } from "@/components/checkout/address/utils/check-is-valid-address"; -// import { formatSingleLineAddress } from "@/components/checkout/address/utils/format-address"; -// import { isAddressComplete } from "@/components/checkout/address/utils/is-address-complete"; +import { isAddressComplete } from "@/components/checkout/address/utils/is-address-complete"; import { mapAddressFieldsToInput } from "@/components/checkout/address/utils/map-address-fields-to-input"; -// import { useAddressMatches } from "@/components/checkout/address/utils/use-address-matches"; -// import { useAddressVerification } from "@/components/checkout/address/utils/use-address-verification"; +import { useAddressMatches } from "@/components/checkout/address/utils/use-address-matches"; import { useCheckoutContext } from "@/components/checkout/checkout"; import { PhoneInput } from "@/components/checkout/contact/phone-input"; import { useDraftOrder } from "@/components/checkout/order/use-draft-order"; import { useDraftOrderFieldSync } from "@/components/checkout/order/use-draft-order-sync"; -// import { AutoComplete } from "@/components/ui/autocomplete"; +import { AutoComplete } from "@/components/ui/autocomplete"; import { Button } from "@/components/ui/button"; import { Command, @@ -50,7 +46,7 @@ import { useGoDaddyContext } from "@/godaddy-provider"; import { cn } from "@/lib/utils"; import { eventIds } from "@/tracking/events"; import { TrackingEventType, track } from "@/tracking/track"; -// import type { Address } from "@/types"; +import type { Address } from "@/types"; import { useDebouncedValue } from "@tanstack/react-pacer"; import { Check, ChevronsUpDown } from "lucide-react"; import * as React from "react"; @@ -58,16 +54,17 @@ import { useFormContext } from "react-hook-form"; export function AddressForm({ sectionKey }: { sectionKey: string }) { const form = useFormContext(); + const { session } = useCheckoutContext(); const { t } = useGoDaddyContext(); const { isConfirmingCheckout, requiredFields } = useCheckoutContext(); const { data: draftOrder } = useDraftOrder(); const countryTriggerRef = React.useRef(null); const [triggerWidth, setTriggerWidth] = React.useState(null); - // TEMPORARY: Comment out suggested address state - will be restored later - // const [showSuggestedAddress, setShowSuggestedAddress] = React.useState(false); const [isCountrySelectOpen, setCountrySelectOpen] = React.useState(false); + const [isAutocompleteOpen, setIsAutocompleteOpen] = + React.useState(false); React.useEffect(() => { function updateWidth() { @@ -80,38 +77,10 @@ export function AddressForm({ sectionKey }: { sectionKey: string }) { return () => window.removeEventListener("resize", updateWidth); }, []); - // TEMPORARY: Comment out address value watching for autocomplete - will be restored later - // const addressValue = form.watch(`${sectionKey}AddressLine1`); + const addressValue = form.watch(`${sectionKey}AddressLine1`); const countryValue = form.watch(`${sectionKey}CountryCode`); - - // Reset AdminArea1 if current value is not valid for the selected country - React.useEffect(() => { - if (countryValue) { - const currentAdminArea1 = form.getValues(`${sectionKey}AdminArea1`); - if (hasRegionData(countryValue) && currentAdminArea1) { - const regions = getRegions(countryValue); - const isValidRegion = regions.some( - (region) => region.code === currentAdminArea1, - ); - if (!isValidRegion) { - form.setValue(`${sectionKey}AdminArea1`, "", { - shouldValidate: true, - shouldDirty: true, - shouldTouch: true, - }); - // Force validation for this specific field - form.trigger(`${sectionKey}AdminArea1`); - } - } - } - }, [countryValue, form, sectionKey]); - const useShippingAddress = form.watch("paymentUseShippingAddress"); - // const [debouncedAddressValue] = useDebouncedValue(addressValue, { - // wait: 200, - // }); - const [ firstName, lastName, @@ -150,26 +119,9 @@ export function AddressForm({ sectionKey }: { sectionKey: string }) { }, ); - // const addressMatchesQuery = useAddressMatches(debouncedAddressValue, { - // enabled: - // !!line1AddressIsDirty && - // !!debouncedAddressValue && - // countryValue === "US" && - // debouncedFullAddress === Object.values(address).join(""), - // }); - - // const shouldVerifyAddress = - // !!debouncedFullAddress && - // debouncedFullAddress !== "US" && - // addressLine1 !== "" && - // postalCode !== "" && - // countryCode !== "" && - // addressIsDirty && - // debouncedFullAddress === Object.values(address).join(""); - - // const verifyAddressQuery = useAddressVerification(address, { - // enabled: shouldVerifyAddress, - // }); + const [debouncedAddressValue] = useDebouncedValue(addressValue, { + wait: 200, + }); // Check if name values differ from order values const nameHasChanged = React.useMemo(() => { @@ -206,52 +158,6 @@ export function AddressForm({ sectionKey }: { sectionKey: string }) { }, }); - // TEMPORARY: Comment out address validation logic - will be restored later - // const isAddressValid = React.useMemo(() => { - // if ( - // verifyAddressQuery.status === "success" && - // !verifyAddressQuery.isLoading && - // verifyAddressQuery.data?.[0] && - // address && - // addressIsDirty && - // debouncedFullAddress === Object.values(address).join("") - // ) { - // return checkIsValidAddress(address, verifyAddressQuery.data[0]); - // } - // return false; - // }, [ - // verifyAddressQuery.status, - // verifyAddressQuery.isLoading, - // verifyAddressQuery.data, - // address, - // debouncedFullAddress, - // addressIsDirty, - // ]); - - // TEMPORARY: Comment out suggested address effect - will be restored later - // React.useEffect(() => { - // if ( - // verifyAddressQuery.status === "success" && - // !verifyAddressQuery.isFetching && - // !isAddressValid && - // !!addressIsDirty - // ) { - // setShowSuggestedAddress(true); - // form.setValue(`${sectionKey}Valid`, false, { shouldValidate: true }); - // } else { - // setShowSuggestedAddress(false); - // form.setValue(`${sectionKey}Valid`, true, { shouldValidate: true }); - // } - // }, [ - // isAddressValid, - // verifyAddressQuery.status, - // verifyAddressQuery.isFetching, - // form.setValue, - // sectionKey, - // addressIsDirty, - // ]); - - // TEMPORARY: Simplified draft order sync without validation dependencies const address = React.useMemo( () => ({ addressLine1, @@ -330,14 +236,45 @@ export function AddressForm({ sectionKey }: { sectionKey: string }) { countryCode, ]); + const addressLine1HasChanged = React.useMemo(() => { + if (!orderAddress) return true; + + return orderAddress.addressLine1 !== (addressLine1 || ""); + }, [orderAddress, addressLine1]); + + const addressMatchesQuery = useAddressMatches(debouncedAddressValue, { + enabled: + !!session?.enableAddressAutocomplete && + !!debouncedAddressValue && + countryValue === "US" && + addressLine1HasChanged, + }); + + function handleUpdateAddress(address?: Address) { + if (!address) return; + + const fieldMap: Record = { + AddressLine1: address.addressLine1, + AddressLine2: address.addressLine2, + AdminArea2: address.adminArea3, + AdminArea1: address.adminArea1, + PostalCode: address.postalCode, + }; + + for (const [key, value] of Object.entries(fieldMap)) { + if (value) { + form.setValue(`${sectionKey}${key}`, value, { shouldValidate: true }); + } + } + } + const shouldUpdateAddress = Boolean( addressHasChanged && // Only sync if values differ from order !!debouncedFullAddress && - addressLine1?.trim() !== "" && - postalCode?.trim() !== "" && - countryCode?.trim() !== "" && + isAddressComplete(address) && debouncedFullAddress === Object.values(address).join("") && - debouncedFullAddress.trim() !== "", + debouncedFullAddress.trim() !== "" && + !isAutocompleteOpen, ); useDraftOrderFieldSync({ @@ -364,25 +301,6 @@ export function AddressForm({ sectionKey }: { sectionKey: string }) { }, }); - // TEMPORARY: Comment out address update handler - will be restored later - // function handleUpdateAddress(address?: Address) { - // if (!address) return; - - // const fieldMap: Record = { - // AddressLine1: address.addressLine1, - // AddressLine2: address.addressLine2, - // AdminArea3: address.adminArea3, - // AdminArea1: address.adminArea1, - // PostalCode: address.postalCode, - // }; - - // for (const [key, value] of Object.entries(fieldMap)) { - // if (value) { - // form.setValue(`${sectionKey}${key}`, value, { shouldValidate: true }); - // } - // } - // } - return (
{field.value ? countries.find( @@ -441,11 +360,6 @@ export function AddressForm({ sectionKey }: { sectionKey: string }) { const previousCountry = form.getValues( `${sectionKey}CountryCode`, ); - const isChangingCountryType = - (hasRegionData(previousCountry) && - !hasRegionData(country.value)) || - (!hasRegionData(previousCountry) && - hasRegionData(country.value)); // Set the new country value form.setValue( @@ -456,22 +370,22 @@ export function AddressForm({ sectionKey }: { sectionKey: string }) { }, ); - // Reset AdminArea1 field when changing country types or when current value is invalid - const currentAdminArea1 = form.getValues( - `${sectionKey}AdminArea1`, - ); - const newCountryRegions = getRegions(country.value); - const isCurrentValueValid = newCountryRegions.some( - (region) => region.code === currentAdminArea1, - ); - - if ( - isChangingCountryType || - (hasRegionData(country.value) && - !isCurrentValueValid) - ) { + if (previousCountry !== country.value) { + form.setValue(`${sectionKey}AddressLine1`, "", { + shouldDirty: true, + shouldValidate: false, + }); form.setValue(`${sectionKey}AdminArea1`, "", { shouldDirty: true, + shouldValidate: false, + }); + form.setValue(`${sectionKey}AdminArea2`, "", { + shouldDirty: true, + shouldValidate: false, + }); + form.setValue(`${sectionKey}PostalCode`, "", { + shouldDirty: true, + shouldValidate: false, }); } @@ -561,39 +475,35 @@ export function AddressForm({ sectionKey }: { sectionKey: string }) { {t.shipping.address1} - {/* TEMPORARY: Comment out autocomplete for US addresses - will be restored later */} - {/* {countryValue === "US" ? ( + {countryValue === "US" && session?.enableAddressAutocomplete ? ( - handleUpdateAddress(address as Address) - } + onSelect={(address) => { + handleUpdateAddress(address as Address); + }} + onOpenChange={setIsAutocompleteOpen} isLoading={ addressMatchesQuery?.isLoading || addressMatchesQuery?.isFetching } hasError={!!fieldState.error} + aria-required={requiredFields?.[`${sectionKey}AddressLine1`]} + disabled={isConfirmingCheckout} /> - ) : ( */} - - {/* )} */} + ) : ( + + )} - {/* TEMPORARY: Comment out validation error display - will be restored later */} - {/* {form?.formState?.errors?.[`${sectionKey}Valid`]?.message ? ( -

- {String(form.formState.errors[`${sectionKey}Valid`]?.message)} -

- ) : null} */}
)} /> @@ -656,6 +566,11 @@ export function AddressForm({ sectionKey }: { sectionKey: string }) { shouldValidate: true, }); + form.setValue(`${sectionKey}PostalCode`, "", { + shouldDirty: true, + shouldValidate: false, + }); + // Track region selection event track({ eventId: eventIds.changeRegion, @@ -679,6 +594,7 @@ export function AddressForm({ sectionKey }: { sectionKey: string }) { aria-required={ requiredFields?.[`${sectionKey}AdminArea1`] } + tabIndex={0} > @@ -732,27 +648,6 @@ export function AddressForm({ sectionKey }: { sectionKey: string }) { )} /> - {/* TEMPORARY: Comment out suggested address display - will be restored later */} - {/* {showSuggestedAddress ? ( -
- {t.shipping.addressSuggestion}{" "} - - {t.shipping.addressSuggestionEnd} -
- ) : null} */}
diff --git a/packages/react/src/components/checkout/address/country-region-data.ts b/packages/react/src/components/checkout/address/country-region-data.ts index d9c8e994..21d8024b 100644 --- a/packages/react/src/components/checkout/address/country-region-data.ts +++ b/packages/react/src/components/checkout/address/country-region-data.ts @@ -955,7 +955,6 @@ export const CL = [ ["Los Lagos", "LL"], ["Los Ríos", "LR"], ["Magallanes y Antartica Chilena", "MA"], - ["Marga-Marga", ""], ["Maule", "ML"], ["Ñuble", "NB"], ["Región Metropolitana de Santiago", "RM"], @@ -1102,18 +1101,18 @@ export const CK = [ "Cook Islands", "CK", [ - ["Aitutaki", "undefined"], - ["Atiu", "undefined"], - ["Avarua", "undefined"], - ["Mangaia", "undefined"], - ["Manihiki", "undefined"], - ["Ma'uke", "undefined"], - ["Mitiaro", "undefined"], - ["Nassau", "undefined"], - ["Palmerston", "undefined"], - ["Penrhyn", "undefined"], - ["Pukapuka", "undefined"], - ["Rakahanga", "undefined"], + ["Aitutaki", undefined], + ["Atiu", undefined], + ["Avarua", undefined], + ["Mangaia", undefined], + ["Manihiki", undefined], + ["Ma'uke", undefined], + ["Mitiaro", undefined], + ["Nassau", undefined], + ["Palmerston", undefined], + ["Penrhyn", undefined], + ["Pukapuka", undefined], + ["Rakahanga", undefined], ], ]; export const CR = [ @@ -1440,21 +1439,21 @@ export const ET = [ export const FK = [ "Falkland Islands (Islas Malvinas)", "FK", - [["Falkland Islands (Islas Malvinas)", "undefined"]], + [["Falkland Islands (Islas Malvinas)", undefined]], ]; export const FO = [ "Faroe Islands", "FO", [ - ["Bordoy", "undefined"], - ["Eysturoy", "undefined"], - ["Mykines", "undefined"], - ["Sandoy", "undefined"], - ["Skuvoy", "undefined"], - ["Streymoy", "undefined"], - ["Suduroy", "undefined"], - ["Tvoroyri", "undefined"], - ["Vagar", "undefined"], + ["Bordoy", undefined], + ["Eysturoy", undefined], + ["Mykines", undefined], + ["Sandoy", undefined], + ["Skuvoy", undefined], + ["Streymoy", undefined], + ["Suduroy", undefined], + ["Tvoroyri", undefined], + ["Vagar", undefined], ], ]; export const FJ = [ @@ -1535,26 +1534,26 @@ export const FR = [ ["Wallis-et-Futuna", "WF"], ], ]; -export const GF = ["French Guiana", "GF", [["French Guiana", "undefined"]]]; +export const GF = ["French Guiana", "GF", [["French Guiana", undefined]]]; export const PF = [ "French Polynesia", "PF", [ - ["Archipel des Marquises", "undefined"], - ["Archipel des Tuamotu", "undefined"], - ["Archipel des Tubuai", "undefined"], - ["Iles du Vent", "undefined"], - ["Iles Sous-le-Vent", "undefined"], + ["Archipel des Marquises", undefined], + ["Archipel des Tuamotu", undefined], + ["Archipel des Tubuai", undefined], + ["Iles du Vent", undefined], + ["Iles Sous-le-Vent", undefined], ], ]; export const TF = [ "French Southern and Antarctic Lands", "TF", [ - ["Adelie Land", "undefined"], - ["Ile Crozet", "undefined"], - ["Iles Kerguelen", "undefined"], - ["Iles Saint-Paul et Amsterdam", "undefined"], + ["Adelie Land", undefined], + ["Ile Crozet", undefined], + ["Iles Kerguelen", undefined], + ["Iles Saint-Paul et Amsterdam", undefined], ], ]; export const GA = [ @@ -1646,7 +1645,7 @@ export const GH = [ ["Western North", "WN"], ], ]; -export const GI = ["Gibraltar", "GI", [["Gibraltar", "undefined"]]]; +export const GI = ["Gibraltar", "GI", [["Gibraltar", undefined]]]; export const GR = [ "Greece", "GR", @@ -1690,8 +1689,8 @@ export const GD = [ ["Southern Grenadine Islands", "10"], ], ]; -export const GP = ["Guadeloupe", "GP", [["Guadeloupe", "undefined"]]]; -export const GU = ["Guam", "GU", [["Guam", "undefined"]]]; +export const GP = ["Guadeloupe", "GP", [["Guadeloupe", undefined]]]; +export const GU = ["Guam", "GU", [["Guam", undefined]]]; export const GT = [ "Guatemala", "GT", @@ -1724,16 +1723,16 @@ export const GG = [ "Guernsey", "GG", [ - ["Castel", "undefined"], - ["Forest", "undefined"], - ["St. Andrew", "undefined"], - ["St. Martin", "undefined"], - ["St. Peter Port", "undefined"], - ["St. Pierre du Bois", "undefined"], - ["St. Sampson", "undefined"], - ["St. Saviour", "undefined"], - ["Torteval", "undefined"], - ["Vale", "undefined"], + ["Castel", undefined], + ["Forest", undefined], + ["St. Andrew", undefined], + ["St. Martin", undefined], + ["St. Peter Port", undefined], + ["St. Pierre du Bois", undefined], + ["St. Sampson", undefined], + ["St. Saviour", undefined], + ["Torteval", undefined], + ["Vale", undefined], ], ]; export const GN = [ @@ -1800,7 +1799,7 @@ export const HT = [ export const HM = [ "Heard Island and McDonald Islands", "HM", - [["Heard Island and McDonald Islands", "undefined"]], + [["Heard Island and McDonald Islands", undefined]], ]; export const VA = [ "Holy See (Vatican City)", @@ -2069,7 +2068,7 @@ export const IE = [ ["Wicklow", "WW"], ], ]; -export const IM = ["Isle of Man", "IM", [["Isle of Man", "undefined"]]]; +export const IM = ["Isle of Man", "IM", [["Isle of Man", undefined]]]; export const IL = [ "Israel", "IL", @@ -2181,7 +2180,7 @@ export const JP = [ ["Yamanashi", "19"], ], ]; -export const JE = ["Jersey", "JE", [["Jersey", "undefined"]]]; +export const JE = ["Jersey", "JE", [["Jersey", undefined]]]; export const JO = [ "Jordan", "JO", @@ -2210,7 +2209,7 @@ export const KZ = [ ["Astana", "AST"], ["Atyrau", "ATY"], ["Batys Qazaqstan", "ZAP"], - ["Bayqongyr", "undefined"], + ["Bayqongyr", undefined], ["Mangghystau", "MAN"], ["Ongtustik Qazaqstan", "YUZ"], ["Pavlodar", "PAV"], @@ -2279,33 +2278,33 @@ export const KI = [ "Kiribati", "KI", [ - ["Abaiang", "undefined"], - ["Abemama", "undefined"], - ["Aranuka", "undefined"], - ["Arorae", "undefined"], - ["Banaba", "undefined"], - ["Beru", "undefined"], - ["Butaritari", "undefined"], - ["Central Gilberts", "undefined"], + ["Abaiang", undefined], + ["Abemama", undefined], + ["Aranuka", undefined], + ["Arorae", undefined], + ["Banaba", undefined], + ["Beru", undefined], + ["Butaritari", undefined], + ["Central Gilberts", undefined], ["Gilbert Islands", "G"], - ["Kanton", "undefined"], - ["Kiritimati", "undefined"], - ["Kuria", "undefined"], + ["Kanton", undefined], + ["Kiritimati", undefined], + ["Kuria", undefined], ["Line Islands", "L"], - ["Maiana", "undefined"], - ["Makin", "undefined"], - ["Marakei", "undefined"], - ["Nikunau", "undefined"], - ["Nonouti", "undefined"], - ["Northern Gilberts", "undefined"], - ["Onotoa", "undefined"], + ["Maiana", undefined], + ["Makin", undefined], + ["Marakei", undefined], + ["Nikunau", undefined], + ["Nonouti", undefined], + ["Northern Gilberts", undefined], + ["Onotoa", undefined], ["Phoenix Islands", "P"], - ["Southern Gilberts", "undefined"], - ["Tabiteuea", "undefined"], - ["Tabuaeran", "undefined"], - ["Tamana", "undefined"], - ["Tarawa", "undefined"], - ["Teraina", "undefined"], + ["Southern Gilberts", undefined], + ["Tabiteuea", undefined], + ["Tabuaeran", undefined], + ["Tamana", undefined], + ["Tarawa", undefined], + ["Teraina", undefined], ], ]; export const KP = [ @@ -2665,7 +2664,7 @@ export const LU = [ ["Wiltz", "WI"], ], ]; -export const MO = ["Macao", "MO", [["Macao", "undefined"]]]; +export const MO = ["Macao", "MO", [["Macao", undefined]]]; export const MK = [ "Macedonia, Republic of", "MK", @@ -2718,7 +2717,7 @@ export const MK = [ ["Plasnica", "61"], ["Prilep", "62"], ["Probištip", "63"], - ["Radoviš", ""], + ["Radoviš", "64"], ["Rankovce", "65"], ["Resen", "66"], ["Rosoman", "67"], @@ -2956,7 +2955,7 @@ export const MH = [ ["Wotje", "WTJ"], ], ]; -export const MQ = ["Martinique", "MQ", [["Martinique", "undefined"]]]; +export const MQ = ["Martinique", "MQ", [["Martinique", undefined]]]; export const MR = [ "Mauritania", "MR", @@ -3197,9 +3196,9 @@ export const MS = [ "Montserrat", "MS", [ - ["Saint Anthony", "undefined"], - ["Saint Georges", "undefined"], - ["Saint Peter's", "undefined"], + ["Saint Anthony", undefined], + ["Saint Georges", undefined], + ["Saint Peter's", undefined], ], ]; export const MA = [ @@ -3333,9 +3332,9 @@ export const NC = [ "New Caledonia", "NC", [ - ["Iles Loyaute", "undefined"], - ["Nord", "undefined"], - ["Sud", "undefined"], + ["Iles Loyaute", undefined], + ["Nord", undefined], + ["Sud", undefined], ], ]; export const NZ = [ @@ -3441,16 +3440,16 @@ export const NG = [ ["Zamfara", "ZA"], ], ]; -export const NU = ["Niue", "NU", [["Niue", "undefined"]]]; -export const NF = ["Norfolk Island", "NF", [["Norfolk Island", "undefined"]]]; +export const NU = ["Niue", "NU", [["Niue", undefined]]]; +export const NF = ["Norfolk Island", "NF", [["Norfolk Island", undefined]]]; export const MP = [ "Northern Mariana Islands", "MP", [ - ["Northern Islands", "undefined"], - ["Rota", "undefined"], - ["Saipan", "undefined"], - ["Tinian", "undefined"], + ["Northern Islands", undefined], + ["Rota", undefined], + ["Saipan", undefined], + ["Tinian", undefined], ], ]; export const NO = [ @@ -3681,7 +3680,7 @@ export const PH = [ ["Zamboanga Peninsula", "PH-09"], ], ]; -export const PN = ["Pitcairn", "PN", [["Pitcairn Islands", "undefined"]]]; +export const PN = ["Pitcairn", "PN", [["Pitcairn Islands", undefined]]]; export const PL = [ "Poland", "PL", @@ -3734,79 +3733,79 @@ export const PR = [ "Puerto Rico", "PR", [ - ["Adjuntas", "undefined"], - ["Aguada", "undefined"], - ["Aguadilla", "undefined"], - ["Aguas Buenas", "undefined"], - ["Aibonito", "undefined"], - ["Anasco", "undefined"], - ["Arecibo", "undefined"], - ["Arroyo", "undefined"], - ["Barceloneta", "undefined"], - ["Barranquitas", "undefined"], - ["Bayamon", "undefined"], - ["Cabo Rojo", "undefined"], - ["Caguas", "undefined"], - ["Camuy", "undefined"], - ["Canovanas", "undefined"], - ["Carolina", "undefined"], - ["Cat", "undefined"], - ["Ceiba", "undefined"], - ["Ciales", "undefined"], - ["Cidra", "undefined"], - ["Coamo", "undefined"], - ["Comerio", "undefined"], - ["Corozal", "undefined"], - ["Culebra", "undefined"], - ["Dorado", "undefined"], - ["Fajardo", "undefined"], - ["Florida", "undefined"], - ["Guanica", "undefined"], - ["Guayama", "undefined"], - ["Guayanilla", "undefined"], - ["Guaynabo", "undefined"], - ["Gurabo", "undefined"], - ["Hatillo", "undefined"], - ["Hormigueros", "undefined"], - ["Humacao", "undefined"], - ["Isabe", "undefined"], - ["Juana Diaz", "undefined"], - ["Juncos", "undefined"], - ["Lajas", "undefined"], - ["Lares", "undefined"], - ["Las Marias", "undefined"], - ["Las oiza", "undefined"], - ["Luquillo", "undefined"], - ["Manati", "undefined"], - ["Maricao", "undefined"], - ["Maunabo", "undefined"], - ["Mayaguez", "undefined"], - ["Moca", "undefined"], - ["Morovis", "undefined"], - ["Naguabo", "undefined"], - ["Naranjito", "undefined"], - ["Orocovis", "undefined"], - ["Patillas", "undefined"], - ["Penuelas", "undefined"], - ["Ponce", "undefined"], - ["Quebradillas", "undefined"], - ["Rincon", "undefined"], - ["Rio Grande", "undefined"], - ["Sabana linas", "undefined"], - ["San German", "undefined"], - ["San Juan", "undefined"], - ["San Lorenzo", "undefined"], - ["San Sebastian", "undefined"], - ["Santa Isabel", "undefined"], - ["Toa Alta", "undefined"], - ["Toa Baja", "undefined"], - ["Trujillo Alto", "undefined"], - ["Utuado", "undefined"], - ["Vega Alta", "undefined"], - ["Vega ues", "undefined"], - ["Villalba", "undefined"], - ["Yabucoa", "undefined"], - ["Yauco", "undefined"], + ["Adjuntas", undefined], + ["Aguada", undefined], + ["Aguadilla", undefined], + ["Aguas Buenas", undefined], + ["Aibonito", undefined], + ["Anasco", undefined], + ["Arecibo", undefined], + ["Arroyo", undefined], + ["Barceloneta", undefined], + ["Barranquitas", undefined], + ["Bayamon", undefined], + ["Cabo Rojo", undefined], + ["Caguas", undefined], + ["Camuy", undefined], + ["Canovanas", undefined], + ["Carolina", undefined], + ["Cat", undefined], + ["Ceiba", undefined], + ["Ciales", undefined], + ["Cidra", undefined], + ["Coamo", undefined], + ["Comerio", undefined], + ["Corozal", undefined], + ["Culebra", undefined], + ["Dorado", undefined], + ["Fajardo", undefined], + ["Florida", undefined], + ["Guanica", undefined], + ["Guayama", undefined], + ["Guayanilla", undefined], + ["Guaynabo", undefined], + ["Gurabo", undefined], + ["Hatillo", undefined], + ["Hormigueros", undefined], + ["Humacao", undefined], + ["Isabe", undefined], + ["Juana Diaz", undefined], + ["Juncos", undefined], + ["Lajas", undefined], + ["Lares", undefined], + ["Las Marias", undefined], + ["Las oiza", undefined], + ["Luquillo", undefined], + ["Manati", undefined], + ["Maricao", undefined], + ["Maunabo", undefined], + ["Mayaguez", undefined], + ["Moca", undefined], + ["Morovis", undefined], + ["Naguabo", undefined], + ["Naranjito", undefined], + ["Orocovis", undefined], + ["Patillas", undefined], + ["Penuelas", undefined], + ["Ponce", undefined], + ["Quebradillas", undefined], + ["Rincon", undefined], + ["Rio Grande", undefined], + ["Sabana linas", undefined], + ["San German", undefined], + ["San Juan", undefined], + ["San Lorenzo", undefined], + ["San Sebastian", undefined], + ["Santa Isabel", undefined], + ["Toa Alta", undefined], + ["Toa Baja", undefined], + ["Trujillo Alto", undefined], + ["Utuado", undefined], + ["Vega Alta", undefined], + ["Vega ues", undefined], + ["Villalba", undefined], + ["Yabucoa", undefined], + ["Yauco", undefined], ], ]; export const QA = [ @@ -3822,7 +3821,7 @@ export const QA = [ ["Umm Şalāl", "US"], ], ]; -export const RE = ["Réunion", "RE", [["Réunion", "undefined"]]]; +export const RE = ["Réunion", "RE", [["Réunion", undefined]]]; export const RO = [ "Romania", "RO", @@ -4012,13 +4011,13 @@ export const LC = [ ["Vieux Fort", "11"], ], ]; -export const MF = ["Saint Martin", "MF", [["Saint Martin", "undefined"]]]; +export const MF = ["Saint Martin", "MF", [["Saint Martin", undefined]]]; export const PM = [ "Saint Pierre and Miquelon", "PM", [ - ["Miquelon", "undefined"], - ["Saint Pierre", "undefined"], + ["Miquelon", undefined], + ["Saint Pierre", undefined], ], ]; export const VC = [ @@ -4203,7 +4202,7 @@ export const SG = [ export const SX = [ "Sint Maarten (Dutch part)", "SX", - [["Sint Maarten", "undefined"]], + [["Sint Maarten", undefined]], ]; export const SK = [ "Slovakia", @@ -4490,14 +4489,14 @@ export const GS = [ "South Georgia and South Sandwich Islands", "GS", [ - ["Bird Island", "undefined"], - ["Bristol Island", "undefined"], - ["Clerke Rocks", "undefined"], - ["Montagu Island", "undefined"], - ["Saunders Island", "undefined"], - ["South Georgia", "undefined"], - ["Southern Thule", "undefined"], - ["Traversay Islands", "undefined"], + ["Bird Island", undefined], + ["Bristol Island", undefined], + ["Clerke Rocks", undefined], + ["Montagu Island", undefined], + ["Saunders Island", undefined], + ["South Georgia", undefined], + ["Southern Thule", undefined], + ["Traversay Islands", undefined], ], ]; export const SS = [ @@ -4906,9 +4905,9 @@ export const TK = [ "Tokelau", "TK", [ - ["Atafu", "undefined"], - ["Fakaofo", "undefined"], - ["Nukunonu", "undefined"], + ["Atafu", undefined], + ["Fakaofo", undefined], + ["Nukunonu", undefined], ], ]; export const TO = [ @@ -5074,7 +5073,7 @@ export const TM = [ export const TC = [ "Turks and Caicos Islands", "TC", - [["Turks and Caicos Islands", "undefined"]], + [["Turks and Caicos Islands", undefined]], ]; export const TV = [ "Tuvalu", diff --git a/packages/react/src/components/checkout/address/get-country-region.ts b/packages/react/src/components/checkout/address/get-country-region.ts index ffaa4caf..2187d2da 100644 --- a/packages/react/src/components/checkout/address/get-country-region.ts +++ b/packages/react/src/components/checkout/address/get-country-region.ts @@ -32,8 +32,8 @@ export function getRegions( return []; } - return countryData[2].map((region: string[]) => ({ - label: region[0], - code: region[1], + return countryData[2].map((region: (string | undefined)[]) => ({ + label: region[0] ?? "", + code: region[1] ?? region[0] ?? "", })); } diff --git a/packages/react/src/components/checkout/address/utils/check-is-valid-address.ts b/packages/react/src/components/checkout/address/utils/check-is-valid-address.ts index 1dd74953..f5cb8b22 100644 --- a/packages/react/src/components/checkout/address/utils/check-is-valid-address.ts +++ b/packages/react/src/components/checkout/address/utils/check-is-valid-address.ts @@ -16,7 +16,7 @@ export function checkIsValidAddress( verifiedAddress?.addressLine1?.toLowerCase() && address.adminArea1?.toLowerCase() === verifiedAddress?.adminArea1?.toLowerCase() && - address.adminArea3?.toLowerCase() === + address.adminArea2?.toLowerCase() === verifiedAddress?.adminArea3?.toLowerCase() && address.postalCode?.toLowerCase() === verifiedAddress?.postalCode?.toLowerCase() && diff --git a/packages/react/src/components/checkout/address/utils/use-address-verification.ts b/packages/react/src/components/checkout/address/utils/use-address-verification.ts index 607c30f7..1a852f5a 100644 --- a/packages/react/src/components/checkout/address/utils/use-address-verification.ts +++ b/packages/react/src/components/checkout/address/utils/use-address-verification.ts @@ -35,11 +35,12 @@ export function useAddressVerification( const queryKey = [ "verifyAddressQuery", { - addressLine1: address.addressLine1.toLowerCase(), - postalCode: address.postalCode.toLowerCase(), - countryCode: address.countryCode.toLowerCase(), - city: address.adminArea2?.toLowerCase(), - state: address.adminArea1?.toLowerCase(), + sessionId: session?.id, + addressLine1: address?.addressLine1?.toLowerCase(), + postalCode: address?.postalCode?.toLowerCase(), + countryCode: address?.countryCode?.toLowerCase(), + city: address?.adminArea3?.toLowerCase(), + state: address?.adminArea1?.toLowerCase(), }, ]; @@ -49,9 +50,9 @@ export function useAddressVerification( enabled: options.enabled && !!session?.id && - !!address.addressLine1 && - !!address.postalCode && - !!address.countryCode, + !!address?.addressLine1 && + !!address?.postalCode && + !!address?.countryCode, select: (data) => data.verifyAddress, }); } diff --git a/packages/react/src/components/checkout/address/utils/use-clear-billing-address.ts b/packages/react/src/components/checkout/address/utils/use-clear-billing-address.ts new file mode 100644 index 00000000..207638ad --- /dev/null +++ b/packages/react/src/components/checkout/address/utils/use-clear-billing-address.ts @@ -0,0 +1,25 @@ +import { useTryUpdateDraftOrder } from "@/components/checkout/order/use-try-update-draft-order"; +import { useFormContext } from "react-hook-form"; + +export function useClearBillingAddress() { + const form = useFormContext(); + const tryUpdateDraftOrder = useTryUpdateDraftOrder(); + + return function clearBillingAddress() { + tryUpdateDraftOrder({ + billing: null, + }); + form.setValue("billingAddressLine1", ""); + form.setValue("billingAddressLine2", ""); + form.setValue("billingAddressLine3", ""); + form.setValue("billingAdminArea4", ""); + form.setValue("billingAdminArea3", ""); + form.setValue("billingAdminArea2", ""); + form.setValue("billingAdminArea1", ""); + form.setValue("billingPostalCode", ""); + form.setValue("billingCountryCode", ""); + form.setValue("billingFirstName", ""); + form.setValue("billingLastName", ""); + form.setValue("billingPhone", ""); + }; +} diff --git a/packages/react/src/components/checkout/address/utils/use-sync-billing-address.ts b/packages/react/src/components/checkout/address/utils/use-sync-billing-address.ts new file mode 100644 index 00000000..bf740d5c --- /dev/null +++ b/packages/react/src/components/checkout/address/utils/use-sync-billing-address.ts @@ -0,0 +1,79 @@ +import { useTryUpdateDraftOrder } from "@/components/checkout/order/use-try-update-draft-order"; +import { useFormContext } from "react-hook-form"; + +export function useSyncBillingAddressWithShippingAddress() { + const form = useFormContext(); + const tryUpdateDraftOrder = useTryUpdateDraftOrder(); + + return function syncBillingAddressWithShippingAddress() { + tryUpdateDraftOrder({ + billing: { + firstName: form.getValues("shippingFirstName"), + lastName: form.getValues("shippingLastName"), + phone: form.getValues("shippingPhone"), + address: { + // Use the shipping address fields for billing address + // This assumes that the form has these fields defined + // and they are correctly populated with shipping address data + addressLine1: form.getValues("shippingAddressLine1"), + addressLine2: form.getValues("shippingAddressLine2"), + addressLine3: form.getValues("shippingAddressLine3"), + adminArea4: form.getValues("shippingAdminArea4"), + adminArea3: form.getValues("shippingAdminArea3"), + adminArea2: form.getValues("shippingAdminArea2"), + adminArea1: form.getValues("shippingAdminArea1"), + postalCode: form.getValues("shippingPostalCode"), + countryCode: form.getValues("shippingCountryCode"), + }, + }, + }); + form.setValue("billingFirstName", form.getValues("shippingFirstName"), { + shouldValidate: true, + }); + form.setValue("billingLastName", form.getValues("shippingLastName"), { + shouldValidate: true, + }); + form.setValue("billingPhone", form.getValues("shippingPhone"), { + shouldValidate: true, + }); + form.setValue( + "billingAddressLine1", + form.getValues("shippingAddressLine1"), + { + shouldValidate: true, + }, + ); + form.setValue( + "billingAddressLine2", + form.getValues("shippingAddressLine2"), + { + shouldValidate: true, + }, + ); + form.setValue( + "billingAddressLine3", + form.getValues("shippingAddressLine3"), + { + shouldValidate: true, + }, + ); + form.setValue("billingAdminArea4", form.getValues("shippingAdminArea4"), { + shouldValidate: true, + }); + form.setValue("billingAdminArea3", form.getValues("shippingAdminArea3"), { + shouldValidate: true, + }); + form.setValue("billingAdminArea2", form.getValues("shippingAdminArea2"), { + shouldValidate: true, + }); + form.setValue("billingAdminArea1", form.getValues("shippingAdminArea1"), { + shouldValidate: true, + }); + form.setValue("billingPostalCode", form.getValues("shippingPostalCode"), { + shouldValidate: true, + }); + form.setValue("billingCountryCode", form.getValues("shippingCountryCode"), { + shouldValidate: true, + }); + }; +} \ No newline at end of file diff --git a/packages/react/src/components/checkout/checkout.tsx b/packages/react/src/components/checkout/checkout.tsx index 9e22c168..e40f3c1e 100644 --- a/packages/react/src/components/checkout/checkout.tsx +++ b/packages/react/src/components/checkout/checkout.tsx @@ -7,6 +7,7 @@ import { getRequiredFieldsFromSchema } from "@/components/checkout/form/utils/ge import { type GoDaddyVariables, useGoDaddyContext } from "@/godaddy-provider"; import { type Theme, useTheme } from "@/hooks/use-theme"; import { useVariables } from "@/hooks/use-variables"; +import type { TrackingProperties } from "@/tracking/event-properties"; import { TrackingProvider } from "@/tracking/tracking-provider"; import type { CheckoutSession } from "@/types"; import React, { type ReactNode } from "react"; @@ -17,7 +18,9 @@ import type { Target } from "./target/target"; // Utility function for redirecting to success URL after checkout export function redirectToSuccessUrl(successUrl?: string): void { if (successUrl && typeof window !== "undefined") { - window.location.href = successUrl; + setTimeout(() => { + window.location.href = successUrl; + }, 1000); } } @@ -218,6 +221,7 @@ export interface CheckoutProps { direction?: "ltr" | "rtl"; showStoreHours?: boolean; enableTracking?: boolean; + trackingProperties?: TrackingProperties; targets?: Partial ReactNode>>; checkoutFormSchema?: CheckoutFormSchema; defaultValues?: Pick; @@ -228,6 +232,7 @@ export function Checkout(props: CheckoutProps) { session, checkoutFormSchema, enableTracking = false, + trackingProperties, stripeConfig, godaddyPaymentsConfig, squareConfig, @@ -504,6 +509,7 @@ export function Checkout(props: CheckoutProps) { checkIsValidPhone(phone), [phone]); // Check if phone value differs from order value @@ -241,7 +262,7 @@ export function PhoneInput({ {t.shipping.phone} { diff --git a/packages/react/src/components/checkout/delivery/delivery-method.tsx b/packages/react/src/components/checkout/delivery/delivery-method.tsx index c157c731..05a30d2b 100644 --- a/packages/react/src/components/checkout/delivery/delivery-method.tsx +++ b/packages/react/src/components/checkout/delivery/delivery-method.tsx @@ -2,8 +2,7 @@ import { type CheckoutFormData, useCheckoutContext, } from "@/components/checkout/checkout"; -import { useApplyDeliveryMethod } from "@/components/checkout/delivery/utils/use-apply-delivery-method"; -import { useRemoveShippingMethod } from "@/components/checkout/shipping/utils/use-remove-shipping-method"; +import { useIsPaymentDisabled } from "@/components/checkout/payment/utils/use-is-payment-disabled"; import { FormControl, FormField, FormItem } from "@/components/ui/form"; import { Label } from "@/components/ui/label"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; @@ -57,19 +56,12 @@ export function DeliveryMethodForm() { const { t } = useGoDaddyContext(); const form = useFormContext(); const { session, isConfirmingCheckout } = useCheckoutContext(); - const removeShippingMethod = useRemoveShippingMethod(); - const applyDeliveryMethod = useApplyDeliveryMethod(); - const shippingMethod = form.watch("shippingMethod"); + const isPaymentDisabled = useIsPaymentDisabled(); const handleDeliveryMethodChange = (value: DeliveryMethods) => { form.setValue("deliveryMethod", value); if (value === DeliveryMethods.PICKUP) { - if (shippingMethod) { - removeShippingMethod.mutate(shippingMethod); - form.setValue("shippingMethod", undefined); - } - } else { - applyDeliveryMethod.mutate(value); + form.setValue("shippingMethod", undefined); } track({ eventId: "change_delivery_method.click", @@ -119,7 +111,7 @@ export function DeliveryMethodForm() { defaultValue={field.value || DeliveryMethods.SHIP} onValueChange={handleDeliveryMethodChange} required - disabled={isConfirmingCheckout} + disabled={isConfirmingCheckout || isPaymentDisabled} > {availableMethods.map((method, index) => (