mirror of
https://github.com/vercel/commerce.git
synced 2025-06-09 01:36:57 +00:00
add useAddShippingAddress hook + add phone and region fields in address
Signed-off-by: Loan Laux <loan@outgrow.io>
This commit is contained in:
parent
fb1fa865ac
commit
2943168803
@ -144,12 +144,21 @@ const PaymentMethodView: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={s.fieldset}>
|
<div className={s.fieldset}>
|
||||||
<label className={s.label}>Country/Region</label>
|
<label className={s.label}>Region</label>
|
||||||
|
<input
|
||||||
|
className={s.input}
|
||||||
|
name='region'
|
||||||
|
onChange={updateAddressData}
|
||||||
|
value={address.region}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={s.fieldset}>
|
||||||
|
<label className={s.label}>Country</label>
|
||||||
<select
|
<select
|
||||||
className={s.select}
|
className={s.select}
|
||||||
name='countryOrRegion'
|
name='country'
|
||||||
onChange={updateAddressData}
|
onChange={updateAddressData}
|
||||||
value={address.countryOrRegion}
|
value={address.country}
|
||||||
>
|
>
|
||||||
{countries.map((country) => (
|
{countries.map((country) => (
|
||||||
<option
|
<option
|
||||||
|
@ -1,13 +1,22 @@
|
|||||||
import { FC, useState } from 'react'
|
import { FC } from 'react'
|
||||||
import cn from 'classnames'
|
import cn from 'classnames'
|
||||||
import s from './ShippingView.module.css'
|
import s from './ShippingView.module.css'
|
||||||
import Button from '@components/ui/Button'
|
import Button from '@components/ui/Button'
|
||||||
import { useUI } from '@components/ui/context'
|
import { useUI } from '@components/ui/context'
|
||||||
import SidebarLayout from '@components/common/SidebarLayout'
|
import SidebarLayout from '@components/common/SidebarLayout'
|
||||||
import countries from '@lib/countries'
|
import countries from '@lib/countries'
|
||||||
|
import useAddShippingAddress from '@framework/cart/use-add-shipping-address'
|
||||||
|
|
||||||
const PaymentMethodView: FC = () => {
|
const PaymentMethodView: FC = () => {
|
||||||
const { paymentMethodDetails, setShippingAddress, setSidebarView, setUseBillingAddressForShipping, shippingAddress, useBillingAddressForShipping } = useUI()
|
const addShippingAddress = useAddShippingAddress()
|
||||||
|
const {
|
||||||
|
paymentMethodDetails,
|
||||||
|
setShippingAddress,
|
||||||
|
setSidebarView,
|
||||||
|
setUseBillingAddressForShipping,
|
||||||
|
shippingAddress,
|
||||||
|
useBillingAddressForShipping,
|
||||||
|
} = useUI()
|
||||||
|
|
||||||
const handleUseBillingAddressForShipping = (event) => {
|
const handleUseBillingAddressForShipping = (event) => {
|
||||||
setUseBillingAddressForShipping(event.target.value === 'true')
|
setUseBillingAddressForShipping(event.target.value === 'true')
|
||||||
@ -21,7 +30,7 @@ const PaymentMethodView: FC = () => {
|
|||||||
addressLine2: paymentMethodDetails.address?.addressLine2,
|
addressLine2: paymentMethodDetails.address?.addressLine2,
|
||||||
postalCode: paymentMethodDetails.address?.postalCode,
|
postalCode: paymentMethodDetails.address?.postalCode,
|
||||||
city: paymentMethodDetails.address?.city,
|
city: paymentMethodDetails.address?.city,
|
||||||
countryOrRegion: paymentMethodDetails.address?.countryOrRegion,
|
country: paymentMethodDetails.address?.country,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -32,7 +41,11 @@ const PaymentMethodView: FC = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarLayout handleBack={() => setSidebarView('CHECKOUT_VIEW')}>
|
<SidebarLayout handleBack={async () => {
|
||||||
|
// add shipping address to cart
|
||||||
|
await addShippingAddress({ address: shippingAddress })
|
||||||
|
setSidebarView('CHECKOUT_VIEW')
|
||||||
|
}}>
|
||||||
<div className="px-4 sm:px-6 flex-1">
|
<div className="px-4 sm:px-6 flex-1">
|
||||||
<h2 className="pt-1 pb-8 text-2xl font-semibold tracking-wide cursor-pointer inline-block">
|
<h2 className="pt-1 pb-8 text-2xl font-semibold tracking-wide cursor-pointer inline-block">
|
||||||
Shipping
|
Shipping
|
||||||
@ -87,6 +100,17 @@ const PaymentMethodView: FC = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={s.fieldset}>
|
||||||
|
<label className={s.label}>Phone Number</label>
|
||||||
|
<input
|
||||||
|
className={s.input}
|
||||||
|
name='phone'
|
||||||
|
onChange={updateAddressData}
|
||||||
|
value={shippingAddress.phone}
|
||||||
|
disabled={useBillingAddressForShipping}
|
||||||
|
type='tel'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className={s.fieldset}>
|
<div className={s.fieldset}>
|
||||||
<label className={s.label}>Company (Optional)</label>
|
<label className={s.label}>Company (Optional)</label>
|
||||||
<input
|
<input
|
||||||
@ -140,12 +164,22 @@ const PaymentMethodView: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={s.fieldset}>
|
<div className={s.fieldset}>
|
||||||
<label className={s.label}>Country/Region</label>
|
<label className={s.label}>Region</label>
|
||||||
|
<input
|
||||||
|
className={s.input}
|
||||||
|
name='region'
|
||||||
|
onChange={updateAddressData}
|
||||||
|
value={shippingAddress.region}
|
||||||
|
disabled={useBillingAddressForShipping}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={s.fieldset}>
|
||||||
|
<label className={s.label}>Country</label>
|
||||||
<select
|
<select
|
||||||
className={s.select}
|
className={s.select}
|
||||||
name="countryOrRegion"
|
name="country"
|
||||||
onChange={updateAddressData}
|
onChange={updateAddressData}
|
||||||
value={shippingAddress.countryOrRegion}
|
value={shippingAddress.country}
|
||||||
disabled={useBillingAddressForShipping}
|
disabled={useBillingAddressForShipping}
|
||||||
|
|
||||||
>
|
>
|
||||||
|
@ -28,7 +28,8 @@ export const initialState = {
|
|||||||
addressLine2: '',
|
addressLine2: '',
|
||||||
postalCode: '',
|
postalCode: '',
|
||||||
city: '',
|
city: '',
|
||||||
countryOrRegion: '',
|
country: '',
|
||||||
|
region: '',
|
||||||
},
|
},
|
||||||
paymentMethod: null,
|
paymentMethod: null,
|
||||||
},
|
},
|
||||||
@ -40,7 +41,9 @@ export const initialState = {
|
|||||||
addressLine2: '',
|
addressLine2: '',
|
||||||
postalCode: '',
|
postalCode: '',
|
||||||
city: '',
|
city: '',
|
||||||
countryOrRegion: '',
|
country: '',
|
||||||
|
region: '',
|
||||||
|
phone: '',
|
||||||
},
|
},
|
||||||
useBillingAddressForShipping: true,
|
useBillingAddressForShipping: true,
|
||||||
}
|
}
|
||||||
|
20
framework/commerce/cart/use-add-shipping-address.tsx
Normal file
20
framework/commerce/cart/use-add-shipping-address.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { useHook, useMutationHook } from '../utils/use-hook'
|
||||||
|
import { mutationFetcher } from '../utils/default-fetcher'
|
||||||
|
import type { HookFetcherFn, MutationHook } from '../utils/types'
|
||||||
|
import type { AddShippingAddressHook } from '../types/cart'
|
||||||
|
import type { Provider } from '..'
|
||||||
|
|
||||||
|
export type UseAddShippingAddress<
|
||||||
|
H extends MutationHook<AddShippingAddressHook<any>> = MutationHook<AddShippingAddressHook>
|
||||||
|
> = ReturnType<H['useHook']>
|
||||||
|
|
||||||
|
export const fetcher: HookFetcherFn<AddShippingAddressHook> = mutationFetcher
|
||||||
|
|
||||||
|
const fn = (provider: Provider) => provider.cart?.useAddShippingAddress!
|
||||||
|
|
||||||
|
const useRemoveItem: UseAddShippingAddress = (input) => {
|
||||||
|
const hook = useHook(fn)
|
||||||
|
return useMutationHook({ fetcher, ...hook })(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useRemoveItem
|
@ -26,6 +26,7 @@ export type Provider = CommerceConfig & {
|
|||||||
cart?: {
|
cart?: {
|
||||||
useCart?: SWRHook<Cart.GetCartHook>
|
useCart?: SWRHook<Cart.GetCartHook>
|
||||||
useAddItem?: MutationHook<Cart.AddItemHook>
|
useAddItem?: MutationHook<Cart.AddItemHook>
|
||||||
|
useAddShippingAddress?: MutationHook<Cart.AddShippingAddressHook>
|
||||||
useUpdateItem?: MutationHook<Cart.UpdateItemHook>
|
useUpdateItem?: MutationHook<Cart.UpdateItemHook>
|
||||||
useRemoveItem?: MutationHook<Cart.RemoveItemHook>
|
useRemoveItem?: MutationHook<Cart.RemoveItemHook>
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,20 @@ export type CartItemBody = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Address = {
|
||||||
|
cardholderName: string
|
||||||
|
firstName: string
|
||||||
|
lastName: string
|
||||||
|
company: string
|
||||||
|
addressLine1: string
|
||||||
|
addressLine2: string
|
||||||
|
postalCode: string
|
||||||
|
city: string
|
||||||
|
region: string
|
||||||
|
country: string
|
||||||
|
phone: string
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hooks schema
|
* Hooks schema
|
||||||
*/
|
*/
|
||||||
@ -104,6 +118,7 @@ export type CartTypes = {
|
|||||||
cart?: Cart
|
cart?: Cart
|
||||||
item: LineItem
|
item: LineItem
|
||||||
itemBody: CartItemBody
|
itemBody: CartItemBody
|
||||||
|
address: Address
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CartHooks<T extends CartTypes = CartTypes> = {
|
export type CartHooks<T extends CartTypes = CartTypes> = {
|
||||||
@ -144,6 +159,14 @@ export type RemoveItemHook<T extends CartTypes = CartTypes> = {
|
|||||||
actionInput: { id: string }
|
actionInput: { id: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AddShippingAddressHook<T extends CartTypes = CartTypes> = {
|
||||||
|
data: T['cart'] | null
|
||||||
|
input: { address?: T['address'] }
|
||||||
|
fetcherInput: { address: Address }
|
||||||
|
body: { itemId: string }
|
||||||
|
actionInput: { id: string }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API Schema
|
* API Schema
|
||||||
*/
|
*/
|
||||||
|
@ -95,14 +95,13 @@ const addItem: CartEndpoint['handlers']['addItem'] = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (anonymousCartToken && reactionCustomerToken) {
|
if (anonymousCartToken && reactionCustomerToken) {
|
||||||
console.log('reconciliating carts')(
|
console.log('reconciliating carts')
|
||||||
({ _id: cartId } = await reconcileCarts({
|
({ _id: cartId } = await reconcileCarts({
|
||||||
config,
|
config,
|
||||||
cartId,
|
cartId,
|
||||||
anonymousCartToken,
|
anonymousCartToken,
|
||||||
reactionCustomerToken,
|
reactionCustomerToken,
|
||||||
}))
|
}))
|
||||||
)
|
|
||||||
|
|
||||||
// Clear the anonymous cart token cookie and update cart ID cookie
|
// Clear the anonymous cart token cookie and update cart ID cookie
|
||||||
res.setHeader('Set-Cookie', [
|
res.setHeader('Set-Cookie', [
|
||||||
@ -135,7 +134,7 @@ const addItem: CartEndpoint['handlers']['addItem'] = async ({
|
|||||||
headers: {
|
headers: {
|
||||||
...authorizationHeaderParam,
|
...authorizationHeaderParam,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
console.log('updatedCart', updatedCart)
|
console.log('updatedCart', updatedCart)
|
||||||
|
97
framework/reactioncommerce/cart/use-add-shipping-address.tsx
Normal file
97
framework/reactioncommerce/cart/use-add-shipping-address.tsx
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
|
||||||
|
import type {
|
||||||
|
MutationHookContext,
|
||||||
|
HookFetcherContext,
|
||||||
|
} from '@commerce/utils/types'
|
||||||
|
|
||||||
|
import { ValidationError } from '@commerce/utils/errors'
|
||||||
|
|
||||||
|
import useAddShippingAddress, {
|
||||||
|
AddShippingAddressInput as AddShippingAddressInputBase,
|
||||||
|
UseAddShippingAddress,
|
||||||
|
} from '@commerce/cart/use-add-shipping-address'
|
||||||
|
|
||||||
|
import useCart from './use-cart'
|
||||||
|
import {
|
||||||
|
setShippingAddressOnCartMutation,
|
||||||
|
getAnonymousCartToken,
|
||||||
|
getAnonymousCartId,
|
||||||
|
normalizeCart,
|
||||||
|
} from '../utils'
|
||||||
|
import { Cart, LineItem } from '../types'
|
||||||
|
import { Mutation, MutationUpdateCartItemsQuantityArgs } from '../schema'
|
||||||
|
import { AddShippingAddressBody } from '@commerce/types'
|
||||||
|
|
||||||
|
export type AddShippingAddressFn<T = any> = T extends LineItem
|
||||||
|
? (input?: AddShippingAddressInput<T>) => Promise<Cart | null>
|
||||||
|
: (input: AddShippingAddressInput<T>) => Promise<Cart | null>
|
||||||
|
|
||||||
|
export type AddShippingAddressInput<T = any> = T extends LineItem
|
||||||
|
? Partial<AddShippingAddressInputBase>
|
||||||
|
: AddShippingAddressInputBase
|
||||||
|
|
||||||
|
export default useAddShippingAddress as UseAddShippingAddress<typeof handler>
|
||||||
|
|
||||||
|
export const handler = {
|
||||||
|
fetchOptions: {
|
||||||
|
query: setShippingAddressOnCartMutation,
|
||||||
|
},
|
||||||
|
async fetcher({
|
||||||
|
input: { address },
|
||||||
|
options,
|
||||||
|
fetch,
|
||||||
|
}: HookFetcherContext<AddShippingAddressBody>) {
|
||||||
|
const { setShippingAddressOnCart } = await fetch<
|
||||||
|
Mutation,
|
||||||
|
MutationUpdateCartItemsQuantityArgs
|
||||||
|
>({
|
||||||
|
...options,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
cartId: getAnonymousCartId(),
|
||||||
|
cartToken: getAnonymousCartToken(),
|
||||||
|
address: {
|
||||||
|
address1: address.addressLine1,
|
||||||
|
address2: address.addressLine2,
|
||||||
|
city: address.city,
|
||||||
|
company: address.company,
|
||||||
|
country: address.country,
|
||||||
|
firstName: address.firstName,
|
||||||
|
lastName: address.lastName,
|
||||||
|
fullName: `${address.firstName} ${address.lastName}`,
|
||||||
|
phone: address.phone,
|
||||||
|
postal: address.postalCode,
|
||||||
|
region: address.region,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return normalizeCart(setShippingAddressOnCart?.cart)
|
||||||
|
},
|
||||||
|
useHook: ({
|
||||||
|
fetch,
|
||||||
|
}: MutationHookContext<Cart | null, AddShippingAddressBody>) => <
|
||||||
|
T extends LineItem | undefined = undefined
|
||||||
|
>(
|
||||||
|
ctx: { address?: T } = {}
|
||||||
|
) => {
|
||||||
|
const { mutate } = useCart()
|
||||||
|
const addShippingAddress: AddShippingAddressFn<LineItem> = async (input) => {
|
||||||
|
const address = input?.address ?? ctx.address
|
||||||
|
|
||||||
|
console.log('addShippingAddress input', input)
|
||||||
|
if (!address) {
|
||||||
|
throw new ValidationError({
|
||||||
|
message: 'Invalid input used for this operation',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await fetch({ input: { address } })
|
||||||
|
await mutate(data, false)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
return useCallback(addShippingAddress as AddShippingAddressFn<T>, [fetch, mutate])
|
||||||
|
},
|
||||||
|
}
|
@ -5,6 +5,7 @@ import {
|
|||||||
|
|
||||||
import { handler as useCart } from './cart/use-cart'
|
import { handler as useCart } from './cart/use-cart'
|
||||||
import { handler as useAddItem } from './cart/use-add-item'
|
import { handler as useAddItem } from './cart/use-add-item'
|
||||||
|
import { handler as useAddShippingAddress } from './cart/use-add-shipping-address'
|
||||||
import { handler as useUpdateItem } from './cart/use-update-item'
|
import { handler as useUpdateItem } from './cart/use-update-item'
|
||||||
import { handler as useRemoveItem } from './cart/use-remove-item'
|
import { handler as useRemoveItem } from './cart/use-remove-item'
|
||||||
|
|
||||||
@ -22,7 +23,13 @@ export const reactionCommerceProvider = {
|
|||||||
anonymousCartTokenCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
anonymousCartTokenCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
||||||
cartIdCookie: REACTION_CART_ID_COOKIE,
|
cartIdCookie: REACTION_CART_ID_COOKIE,
|
||||||
fetcher,
|
fetcher,
|
||||||
cart: { useCart, useAddItem, useUpdateItem, useRemoveItem },
|
cart: {
|
||||||
|
useCart,
|
||||||
|
useAddItem,
|
||||||
|
useAddShippingAddress,
|
||||||
|
useUpdateItem,
|
||||||
|
useRemoveItem,
|
||||||
|
},
|
||||||
customer: { useCustomer },
|
customer: { useCustomer },
|
||||||
products: { useSearch },
|
products: { useSearch },
|
||||||
auth: { useLogin, useLogout, useSignup },
|
auth: { useLogin, useLogout, useSignup },
|
||||||
|
@ -4,4 +4,5 @@ export { default as createCartMutation } from './create-cart'
|
|||||||
export { default as authenticateMutation } from './authenticate'
|
export { default as authenticateMutation } from './authenticate'
|
||||||
export { default as logoutMutation } from './logout'
|
export { default as logoutMutation } from './logout'
|
||||||
export { default as removeCartItemsMutation } from './remove-cart-items'
|
export { default as removeCartItemsMutation } from './remove-cart-items'
|
||||||
|
export { default as setShippingAddressOnCartMutation } from './set-shipping-address-on-cart'
|
||||||
export { default as updateCartItemsQuantityMutation } from './update-cart-items-quantity'
|
export { default as updateCartItemsQuantityMutation } from './update-cart-items-quantity'
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
import { cartPayloadFragment } from '@framework/utils/queries/get-cart-query'
|
||||||
|
|
||||||
|
const setShippingAddressOnCartMutation = `
|
||||||
|
mutation setShippingAddressOnCartMutation($input: SetShippingAddressOnCartInput!) {
|
||||||
|
setShippingAddressOnCart(input: $input) {
|
||||||
|
cart {
|
||||||
|
${cartPayloadFragment}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default setShippingAddressOnCartMutation
|
Loading…
x
Reference in New Issue
Block a user