Skip to content

Commit

Permalink
Merge pull request #450 from commercelayer/feat/customize-countries-a…
Browse files Browse the repository at this point in the history
…nd-states-on-addresses

Override countries and states and preselect a default country
  • Loading branch information
malessani committed Apr 5, 2024
2 parents d4b0b8a + e0d0c27 commit 171b3ef
Show file tree
Hide file tree
Showing 12 changed files with 529 additions and 58 deletions.
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,67 @@ In the case of digital product purchases (i.e. SKUs with the `do_not_ship` flag

If the order has the attribute `shipping_country_code_lock` set, customers can select only the specified country code in the shipping address form. If they select a different country for the billing address, the shipping address section will open automatically with the country code already selected and disabled.

#### Custom list of countries and states

You can configure a custom list of countries and/or states for billing and shipping address forms, along with specifying a default country preselected at the organization level of the Provisioning API. This can be achieved by setting the config attribute in the following manner:

```json
{
"mfe": {
"default": {
"checkout": {
"default_country": "IT",
"billing_countries": [
{
"value": "ES",
"label": "Espana"
},
{
"value": "IT",
"label": "Italia"
},
{
"value": "US",
"label": "Unites States of America"
}
],
"billing_states": {
"US": [
{
"value": "CA",
"label": "California"
},
{
"value": "TX",
"label": "Texas"
}
],
"IT": [
{
"value": "FI",
"label": "Firenze"
},
{
"value": "PO",
"label": "Prato"
},
{
"value": "LI",
"label": "Livorno"
}
]
}
}
}
}
}
```

On the example above billing form will have just three countries, custom provinces/states for Italy and USA and the default country preselected for both billing and shipping forms set to Italy.

You can use `default_country`, `billing_countries`, `billing_states`, `shipping_countries` and `shipping_states` as keys. The option can also be customized per market in scope. You can read more about the organization config [here](https://docs.commercelayer.io/provisioning/api-reference/organizations#micro-frontends-configuration).


### Delivery step

Here is where customers select a shipping method for each shipment of their order. [External shipping cost](https://docs.commercelayer.io/core/external-resources/external-shipping-costs) are partially supported by the Checkout application at the moment.
Expand Down
27 changes: 18 additions & 9 deletions components/composite/StepCustomer/AddressInputGroup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import AddressCountrySelector from "@commercelayer/react-components/addresses/Ad
import AddressInput from "@commercelayer/react-components/addresses/AddressInput"
import AddressStateSelector from "@commercelayer/react-components/addresses/AddressStateSelector"
import { Errors } from "@commercelayer/react-components/errors/Errors"
import { ChangeEvent, useContext, useEffect, useState } from "react"
import {
Country,
States,
} from "@commercelayer/react-components/lib/esm/utils/countryStateCity"
import { ChangeEvent, useContext } from "react"
import { useTranslation } from "react-i18next"
import styled from "styled-components"
import tw from "twin.macro"
Expand Down Expand Up @@ -31,6 +35,9 @@ interface Props {
resource: TResource
required?: boolean
value?: string
countries?: Country[] | undefined
defaultCountry?: string
states?: States[]
pattern?: React.ComponentProps<typeof AddressInput>["pattern"]
openShippingAddress?: (props: ShippingToggleProps) => void
}
Expand All @@ -41,6 +48,9 @@ export const AddressInputGroup: React.FC<Props> = ({
required,
type,
pattern,
countries,
defaultCountry,
states,
value,
openShippingAddress,
}) => {
Expand Down Expand Up @@ -83,8 +93,6 @@ export const AddressInputGroup: React.FC<Props> = ({

const label = t(`addressForm.${fieldName}`)

const [valueStatus, setValueStatus] = useState(value)

const isCountry =
fieldName === "shipping_address_country_code" ||
fieldName === "billing_address_country_code"
Expand All @@ -93,10 +101,6 @@ export const AddressInputGroup: React.FC<Props> = ({
fieldName === "shipping_address_state_code" ||
fieldName === "billing_address_state_code"

useEffect(() => {
setValueStatus(value || "")
}, [value])

const handleChange = (event: ChangeEvent<HTMLSelectElement>) => {
if (isCountry && fieldName === "billing_address_country_code") {
const countryCode = event.target.value
Expand All @@ -122,11 +126,14 @@ export const AddressInputGroup: React.FC<Props> = ({
value: "",
}}
onChange={handleChange}
countries={countries}
value={
shippingCountryCodeLock &&
fieldName === "shipping_address_country_code"
? shippingCountryCodeLock
: value
: value === "" || value == null
? defaultCountry
: value
}
disabled={Boolean(
shippingCountryCodeLock &&
Expand All @@ -144,6 +151,8 @@ export const AddressInputGroup: React.FC<Props> = ({
selectClassName="form-select"
inputClassName="form-input"
data-testid={`input_${fieldName}`}
// @ts-expect-error missing
states={states}
name={fieldName}
value={value}
/>
Expand All @@ -160,7 +169,7 @@ export const AddressInputGroup: React.FC<Props> = ({
name={fieldName}
type={type}
pattern={pattern}
value={valueStatus}
value={value}
className="form-input"
/>
<Label htmlFor={fieldName}>{label}</Label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import tw from "twin.macro"
import { ShippingToggleProps } from "components/composite/StepCustomer"
import { AddressInputGroup } from "components/composite/StepCustomer/AddressInputGroup"
import { AppContext } from "components/data/AppProvider"
import { useSettingsOrInvalid } from "components/hooks/useSettingsOrInvalid"

interface Props {
billingAddress: NullableType<Address>
Expand All @@ -17,13 +18,18 @@ export const BillingAddressFormNew: React.FC<Props> = ({
openShippingAddress,
}: Props) => {
const appCtx = useContext(AppContext)
const { settings } = useSettingsOrInvalid()

if (!appCtx) {
if (!appCtx || !settings) {
return null
}

const { requiresBillingInfo } = appCtx

const countries = settings?.config?.checkout?.billing_countries
const states = settings?.config?.checkout?.billing_states
const defaultCountry = settings?.config?.checkout?.default_country

return (
<Wrapper>
<Grid>
Expand Down Expand Up @@ -64,6 +70,9 @@ export const BillingAddressFormNew: React.FC<Props> = ({
fieldName="billing_address_country_code"
resource="billing_address"
type="text"
// @ts-expect-error missing type
countries={countries}
defaultCountry={defaultCountry}
openShippingAddress={openShippingAddress}
value={billingAddress?.country_code || ""}
/>
Expand All @@ -72,6 +81,8 @@ export const BillingAddressFormNew: React.FC<Props> = ({
<AddressInputGroup
fieldName="billing_address_state_code"
resource="billing_address"
// @ts-expect-error missing type
states={states}
type="text"
value={billingAddress?.state_code || ""}
/>
Expand Down
16 changes: 16 additions & 0 deletions components/composite/StepCustomer/ShippingAddressFormNew/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import styled from "styled-components"
import tw from "twin.macro"

import { AddressInputGroup } from "components/composite/StepCustomer/AddressInputGroup"
import { useSettingsOrInvalid } from "components/hooks/useSettingsOrInvalid"

interface Props {
shippingAddress: NullableType<Address>
Expand All @@ -12,6 +13,16 @@ interface Props {
export const ShippingAddressFormNew: React.FC<Props> = ({
shippingAddress,
}: Props) => {
const { settings } = useSettingsOrInvalid()

if (!settings) {
return null
}

const countries = settings?.config?.checkout?.shipping_countries
const states = settings?.config?.checkout?.shipping_states
const defaultCountry = settings?.config?.checkout?.default_country

return (
<Fragment>
<Grid>
Expand Down Expand Up @@ -56,6 +67,9 @@ export const ShippingAddressFormNew: React.FC<Props> = ({
<AddressInputGroup
fieldName="shipping_address_country_code"
resource="shipping_address"
// @ts-expect-error missing type
countries={countries}
defaultCountry={defaultCountry}
type="text"
value={shippingAddress?.country_code || ""}
/>
Expand All @@ -65,6 +79,8 @@ export const ShippingAddressFormNew: React.FC<Props> = ({
<AddressInputGroup
fieldName="shipping_address_state_code"
resource="shipping_address"
// @ts-expect-error missing type
states={states}
type="text"
value={shippingAddress?.state_code || ""}
/>
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"lint:fix": "eslint ./ --ext .tsx,.ts --fix",
"test": "playwright test",
"test:debug": "PWDEBUG=1 playwright test",
"test:ui": "NEXT_PUBLIC_BASE_PATH=http://localhost:3000 playwright test --ui",
"serve": "serve -l tcp://localhost:$PORT/ -n -s out/dist",
"dep:upgrade:major": "pnpm exec npm-check-updates -u",
"dep:upgrade:minor": "pnpm dep:upgrade:major -t minor"
Expand Down Expand Up @@ -82,7 +83,6 @@
"@playwright/test": "1.41.2",
"@tailwindcss/forms": "^0.5.7",
"@types/async-retry": "1.4.8",
"@types/jsonwebtoken": "^9.0.6",
"@types/node": "^20.12.3",
"@types/react": "^18.2.74",
"@types/react-gtm-module": "^2.0.3",
Expand Down Expand Up @@ -122,7 +122,7 @@
"eslint": "^8.57.0",
"eslint-config-next": "^14.1.4",
"eslint-config-prettier": "^9.1.0",
"eslint-config-standard": "^17.1",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-node": "^11.1.0",
Expand Down
11 changes: 1 addition & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 171b3ef

Please sign in to comment.