mirror of
https://github.com/vercel/commerce.git
synced 2025-05-17 15:06:59 +00:00
Polish checkout view
Signed-off-by: Chloe <pinkcloudvnn@gmail.com>
This commit is contained in:
parent
9bbd1b29a7
commit
630b4ba486
@ -61,6 +61,7 @@ const addItem: CustomerAddressEndpoint['handlers']['addItem'] = async ({
|
|||||||
updateFulfillmentOptionsForGroup.cart.checkout.fulfillmentGroups[0]
|
updateFulfillmentOptionsForGroup.cart.checkout.fulfillmentGroups[0]
|
||||||
._id,
|
._id,
|
||||||
fulfillmentMethodId:
|
fulfillmentMethodId:
|
||||||
|
item.shippingMethodId ||
|
||||||
updateFulfillmentOptionsForGroup.cart.checkout.fulfillmentGroups[0]
|
updateFulfillmentOptionsForGroup.cart.checkout.fulfillmentGroups[0]
|
||||||
.availableFulfillmentOptions[0].fulfillmentMethod._id,
|
.availableFulfillmentOptions[0].fulfillmentMethod._id,
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import type { CustomerAddressSchema } from '../../../../types/customer/address'
|
import type {
|
||||||
|
CustomerAddressSchema,
|
||||||
|
CustomerAddressTypes,
|
||||||
|
} from '../../../../types/customer/address'
|
||||||
import type { OpenCommerceAPI } from '../../..'
|
import type { OpenCommerceAPI } from '../../..'
|
||||||
|
|
||||||
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
|
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
|
||||||
@ -11,7 +14,7 @@ import removeItem from './remove-item'
|
|||||||
|
|
||||||
export type CustomerAddressAPI = GetAPISchema<
|
export type CustomerAddressAPI = GetAPISchema<
|
||||||
OpenCommerceAPI,
|
OpenCommerceAPI,
|
||||||
CustomerAddressSchema
|
CustomerAddressSchema<CustomerAddressTypes>
|
||||||
>
|
>
|
||||||
export type CustomerAddressEndpoint = CustomerAddressAPI['endpoint']
|
export type CustomerAddressEndpoint = CustomerAddressAPI['endpoint']
|
||||||
|
|
||||||
|
@ -1,8 +1,33 @@
|
|||||||
|
import selectFulfillmentOptions from '../../../mutations/select-fulfillment-options'
|
||||||
import type { CustomerAddressEndpoint } from '.'
|
import type { CustomerAddressEndpoint } from '.'
|
||||||
|
|
||||||
const updateItem: CustomerAddressEndpoint['handlers']['updateItem'] = async ({
|
const updateItem: CustomerAddressEndpoint['handlers']['updateItem'] = async ({
|
||||||
res,
|
res,
|
||||||
|
body: { item, cartId },
|
||||||
|
config: { fetch, anonymousCartTokenCookie },
|
||||||
|
req: { cookies },
|
||||||
}) => {
|
}) => {
|
||||||
|
// Return an error if no cart is present
|
||||||
|
if (!cartId) {
|
||||||
|
return res.status(400).json({
|
||||||
|
data: null,
|
||||||
|
errors: [{ message: 'Cookie not found' }],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.shippingMethod) {
|
||||||
|
await fetch(selectFulfillmentOptions, {
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
cartId,
|
||||||
|
cartToken: cookies[anonymousCartTokenCookie],
|
||||||
|
fulfillmentGroupId: item.shippingMethod.fulfillmentGroupId,
|
||||||
|
fulfillmentMethodId: item.shippingMethod.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return res.status(200).json({ data: null, errors: [] })
|
return res.status(200).json({ data: null, errors: [] })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,11 @@ import { useMemo } from 'react'
|
|||||||
import { SWRHook } from '@vercel/commerce/utils/types'
|
import { SWRHook } from '@vercel/commerce/utils/types'
|
||||||
import useCart, { UseCart } from '@vercel/commerce/cart/use-cart'
|
import useCart, { UseCart } from '@vercel/commerce/cart/use-cart'
|
||||||
import type { GetCartHook } from '@vercel/commerce/types/cart'
|
import type { GetCartHook } from '@vercel/commerce/types/cart'
|
||||||
|
import { CartTypes } from '../types/cart'
|
||||||
|
|
||||||
export default useCart as UseCart<typeof handler>
|
export default useCart as UseCart<typeof handler>
|
||||||
|
|
||||||
export const handler: SWRHook<GetCartHook> = {
|
export const handler: SWRHook<GetCartHook<CartTypes>> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/cart',
|
url: '/api/cart',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
@ -7,6 +7,7 @@ import useCheckout, {
|
|||||||
} from '@vercel/commerce/checkout/use-checkout'
|
} from '@vercel/commerce/checkout/use-checkout'
|
||||||
import useSubmitCheckout from './use-submit-checkout'
|
import useSubmitCheckout from './use-submit-checkout'
|
||||||
import { useCheckoutContext } from '@components/checkout/context'
|
import { useCheckoutContext } from '@components/checkout/context'
|
||||||
|
import { useCart } from '../cart'
|
||||||
|
|
||||||
export default useCheckout as UseCheckout<typeof handler>
|
export default useCheckout as UseCheckout<typeof handler>
|
||||||
|
|
||||||
@ -17,13 +18,23 @@ export const handler: SWRHook<GetCheckoutHook> = {
|
|||||||
},
|
},
|
||||||
useHook: () =>
|
useHook: () =>
|
||||||
function useHook() {
|
function useHook() {
|
||||||
|
const { data: cart } = useCart()
|
||||||
|
const hasShippingMethods = !!(
|
||||||
|
cart?.checkout?.fulfillmentGroups &&
|
||||||
|
cart.checkout.fulfillmentGroups.find(
|
||||||
|
(group) => group?.type === 'shipping'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
const { cardFields, addressFields } = useCheckoutContext()
|
const { cardFields, addressFields } = useCheckoutContext()
|
||||||
|
|
||||||
|
const { shippingMethod, ...restAddressFields } = addressFields
|
||||||
|
|
||||||
// Basic validation - check that at least one field has a value.
|
// Basic validation - check that at least one field has a value.
|
||||||
const hasEnteredCard = Object.values(cardFields).some(
|
const hasEnteredCard = Object.values(cardFields).some(
|
||||||
(fieldValue) => !!fieldValue
|
(fieldValue) => !!fieldValue
|
||||||
)
|
)
|
||||||
const hasEnteredAddress = Object.values(addressFields).some(
|
const hasEnteredAddress = Object.values(restAddressFields).some(
|
||||||
(fieldValue) => !!fieldValue
|
(fieldValue) => !!fieldValue
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,6 +43,8 @@ export const handler: SWRHook<GetCheckoutHook> = {
|
|||||||
data: {
|
data: {
|
||||||
hasPayment: hasEnteredCard,
|
hasPayment: hasEnteredCard,
|
||||||
hasShipping: hasEnteredAddress,
|
hasShipping: hasEnteredAddress,
|
||||||
|
hasShippingMethods,
|
||||||
|
hasSelectedShippingMethod: !!shippingMethod?.id,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[hasEnteredCard, hasEnteredAddress]
|
[hasEnteredCard, hasEnteredAddress]
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export { default as useAddItem } from './use-add-item'
|
export { default as useAddItem } from './use-add-item'
|
||||||
|
export { default as useUpdateItem } from './use-update-item'
|
||||||
|
@ -5,10 +5,11 @@ import useAddItem, {
|
|||||||
UseAddItem,
|
UseAddItem,
|
||||||
} from '@vercel/commerce/customer/address/use-add-item'
|
} from '@vercel/commerce/customer/address/use-add-item'
|
||||||
import { useCheckoutContext } from '@components/checkout/context'
|
import { useCheckoutContext } from '@components/checkout/context'
|
||||||
|
import { CustomerAddressTypes } from '../../types/customer/address'
|
||||||
|
|
||||||
export default useAddItem as UseAddItem<typeof handler>
|
export default useAddItem as UseAddItem<typeof handler>
|
||||||
|
|
||||||
export const handler: MutationHook<AddItemHook> = {
|
export const handler: MutationHook<AddItemHook<CustomerAddressTypes>> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/customer/address',
|
url: '/api/customer/address',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -23,11 +24,11 @@ export const handler: MutationHook<AddItemHook> = {
|
|||||||
},
|
},
|
||||||
useHook: ({ fetch }) =>
|
useHook: ({ fetch }) =>
|
||||||
function useHook() {
|
function useHook() {
|
||||||
const { setAddressFields } = useCheckoutContext()
|
const { setAddressFields, addressFields } = useCheckoutContext()
|
||||||
return useCallback(
|
return useCallback(
|
||||||
async function addItem(input) {
|
async function addItem(input) {
|
||||||
await fetch({ input })
|
await fetch({ input })
|
||||||
setAddressFields(input)
|
setAddressFields({ ...addressFields, ...input })
|
||||||
return undefined
|
return undefined
|
||||||
},
|
},
|
||||||
[setAddressFields]
|
[setAddressFields]
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
import type { UpdateItemHook } from '@vercel/commerce/types/customer/address'
|
||||||
|
import type {
|
||||||
|
MutationHook,
|
||||||
|
MutationHookContext,
|
||||||
|
} from '@vercel/commerce/utils/types'
|
||||||
|
import { useCallback } from 'react'
|
||||||
|
import useUpdateItem, {
|
||||||
|
UseUpdateItem,
|
||||||
|
} from '@vercel/commerce/customer/address/use-update-item'
|
||||||
|
import { useCheckoutContext } from '@components/checkout/context'
|
||||||
|
import { CustomerAddressTypes } from '../../types/customer/address'
|
||||||
|
|
||||||
|
export default useUpdateItem as UseUpdateItem<typeof handler>
|
||||||
|
|
||||||
|
export const handler: MutationHook<UpdateItemHook<CustomerAddressTypes>> = {
|
||||||
|
fetchOptions: {
|
||||||
|
url: '/api/customer/address',
|
||||||
|
method: 'PUT',
|
||||||
|
},
|
||||||
|
async fetcher({ input: { item, itemId }, options, fetch }) {
|
||||||
|
const data = await fetch({
|
||||||
|
...options,
|
||||||
|
body: { item, itemId },
|
||||||
|
})
|
||||||
|
|
||||||
|
return data
|
||||||
|
},
|
||||||
|
useHook: ({ fetch }) =>
|
||||||
|
function useHook() {
|
||||||
|
const { setAddressFields, addressFields } = useCheckoutContext()
|
||||||
|
return useCallback(
|
||||||
|
async function updateItem(input) {
|
||||||
|
const { id, ...rest } = input
|
||||||
|
await fetch({ input: { item: rest, itemId: id } })
|
||||||
|
setAddressFields({
|
||||||
|
...addressFields,
|
||||||
|
shippingMethod: rest.shippingMethod,
|
||||||
|
})
|
||||||
|
return undefined
|
||||||
|
},
|
||||||
|
[setAddressFields]
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
@ -13,6 +13,7 @@ import { handler as useSubmitCheckout } from './checkout/use-submit-checkout'
|
|||||||
import { handler as useAddCardItem } from './customer/card/use-add-item'
|
import { handler as useAddCardItem } from './customer/card/use-add-item'
|
||||||
import { handler as useCards } from './customer/card/use-cards'
|
import { handler as useCards } from './customer/card/use-cards'
|
||||||
import { handler as useAddAddressItem } from './customer/address/use-add-item'
|
import { handler as useAddAddressItem } from './customer/address/use-add-item'
|
||||||
|
import { handler as useUpdateAddressItem } from './customer/address/use-update-item'
|
||||||
|
|
||||||
export const openCommerceProvider = {
|
export const openCommerceProvider = {
|
||||||
locale: 'en-us',
|
locale: 'en-us',
|
||||||
@ -24,6 +25,7 @@ export const openCommerceProvider = {
|
|||||||
card: { useCards, useAddItem: useAddCardItem },
|
card: { useCards, useAddItem: useAddCardItem },
|
||||||
address: {
|
address: {
|
||||||
useAddItem: useAddAddressItem,
|
useAddItem: useAddAddressItem,
|
||||||
|
useUpdateItem: useUpdateAddressItem,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
products: { useSearch },
|
products: { useSearch },
|
||||||
|
@ -15,6 +15,7 @@ export type CartItemBody = Core.CartItemBody & {
|
|||||||
|
|
||||||
export type CartTypes = Core.CartTypes & {
|
export type CartTypes = Core.CartTypes & {
|
||||||
itemBody: CartItemBody
|
itemBody: CartItemBody
|
||||||
|
cart?: Cart
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CartSchema = Core.CartSchema<CartTypes>
|
export type CartSchema = Core.CartSchema<CartTypes>
|
||||||
|
@ -1 +1,14 @@
|
|||||||
|
import * as Core from '@vercel/commerce/types/customer/address'
|
||||||
|
|
||||||
export * from '@vercel/commerce/types/customer/address'
|
export * from '@vercel/commerce/types/customer/address'
|
||||||
|
|
||||||
|
export type AddressFields = Core.AddressFields & {
|
||||||
|
shippingMethod?: {
|
||||||
|
id: string
|
||||||
|
fulfillmentGroupId: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CustomerAddressTypes = Core.CustomerAddressTypes & {
|
||||||
|
fields: AddressFields
|
||||||
|
}
|
||||||
|
@ -10,9 +10,11 @@ import useCheckout from '@framework/checkout/use-checkout'
|
|||||||
import useSubmitCheckout from '@framework/checkout/use-submit-checkout'
|
import useSubmitCheckout from '@framework/checkout/use-submit-checkout'
|
||||||
import ShippingWidget from '../ShippingWidget'
|
import ShippingWidget from '../ShippingWidget'
|
||||||
import PaymentWidget from '../PaymentWidget'
|
import PaymentWidget from '../PaymentWidget'
|
||||||
import s from './CheckoutSidebarView.module.css'
|
import ShippingMethodWidget from '../ShippingMethodWidget'
|
||||||
import { useCheckoutContext } from '../context'
|
import { useCheckoutContext } from '../context'
|
||||||
|
|
||||||
|
import s from './CheckoutSidebarView.module.css'
|
||||||
|
|
||||||
const CheckoutSidebarView: FC = () => {
|
const CheckoutSidebarView: FC = () => {
|
||||||
const [loadingSubmit, setLoadingSubmit] = useState(false)
|
const [loadingSubmit, setLoadingSubmit] = useState(false)
|
||||||
const { setSidebarView, closeSidebar } = useUI()
|
const { setSidebarView, closeSidebar } = useUI()
|
||||||
@ -76,6 +78,13 @@ const CheckoutSidebarView: FC = () => {
|
|||||||
onClick={() => setSidebarView('SHIPPING_VIEW')}
|
onClick={() => setSidebarView('SHIPPING_VIEW')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{checkoutData?.hasShippingMethods && (
|
||||||
|
<ShippingMethodWidget
|
||||||
|
isValid={checkoutData?.hasSelectedShippingMethod}
|
||||||
|
onClick={() => setSidebarView('SHIPPING_METHOD_VIEW')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<ul className={s.lineItemsList}>
|
<ul className={s.lineItemsList}>
|
||||||
{cartData!.lineItems.map((item: any) => (
|
{cartData!.lineItems.map((item: any) => (
|
||||||
<CartItem
|
<CartItem
|
||||||
@ -101,10 +110,19 @@ const CheckoutSidebarView: FC = () => {
|
|||||||
<span>Taxes</span>
|
<span>Taxes</span>
|
||||||
<span>Calculated at checkout</span>
|
<span>Calculated at checkout</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex justify-between py-1">
|
{checkoutData?.hasSelectedShippingMethod ? (
|
||||||
<span>Shipping</span>
|
<li className="flex justify-between py-1">
|
||||||
<span className="font-bold tracking-wide">FREE</span>
|
<span>Shipping</span>
|
||||||
</li>
|
<span>
|
||||||
|
{cartData?.checkout?.summary.fulfillmentTotal?.displayAmount}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
) : (
|
||||||
|
<li className="flex justify-between py-1">
|
||||||
|
<span>Shipping</span>
|
||||||
|
<span className="font-bold tracking-wide">FREE</span>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
<div className="flex justify-between border-t border-accent-2 py-3 font-bold mb-2">
|
<div className="flex justify-between border-t border-accent-2 py-3 font-bold mb-2">
|
||||||
<span>Total</span>
|
<span>Total</span>
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
import useCart from '@framework/cart/use-cart'
|
||||||
|
import useUpdateUpdateAddress from '@framework/customer/address/use-update-item'
|
||||||
|
import SidebarLayout from '@components/common/SidebarLayout'
|
||||||
|
import { useUI } from '@components/ui/context'
|
||||||
|
import { Button } from '@components/ui'
|
||||||
|
import { useCheckoutContext } from '../context'
|
||||||
|
|
||||||
|
const ShippingMethod = () => {
|
||||||
|
const { setSidebarView } = useUI()
|
||||||
|
|
||||||
|
const { data: cart } = useCart()
|
||||||
|
const { addressFields } = useCheckoutContext()
|
||||||
|
|
||||||
|
const updateShippingMethod = useUpdateUpdateAddress()
|
||||||
|
const shippingGroup = cart?.checkout?.fulfillmentGroups.find(
|
||||||
|
(group) => group?.type === 'shipping'
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleSubmit = async (event: React.ChangeEvent<HTMLFormElement>) => {
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
await updateShippingMethod({
|
||||||
|
id: cart!.id,
|
||||||
|
...addressFields,
|
||||||
|
shippingMethod: {
|
||||||
|
fulfillmentGroupId:
|
||||||
|
cart!.checkout?.fulfillmentGroups[0]?._id ?? 'groupId',
|
||||||
|
id: event.target.shippingMethod.value,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
setSidebarView('CHECKOUT_VIEW')
|
||||||
|
}
|
||||||
|
|
||||||
|
return shippingGroup ? (
|
||||||
|
<form className="h-full" onSubmit={handleSubmit}>
|
||||||
|
<SidebarLayout handleBack={() => setSidebarView('CHECKOUT_VIEW')}>
|
||||||
|
<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">
|
||||||
|
Shipping Methods
|
||||||
|
</h2>
|
||||||
|
<div>
|
||||||
|
{shippingGroup.availableFulfillmentOptions.map((option) => (
|
||||||
|
<div
|
||||||
|
className="flex flex-row my-3 items-center justify-between"
|
||||||
|
key={option?.fulfillmentMethod?._id}
|
||||||
|
>
|
||||||
|
<fieldset className="flex flex-row items-center">
|
||||||
|
<input
|
||||||
|
name="shippingMethod"
|
||||||
|
className="bg-black"
|
||||||
|
type="radio"
|
||||||
|
value={option?.fulfillmentMethod?._id}
|
||||||
|
defaultChecked={
|
||||||
|
shippingGroup.selectedFulfillmentOption?.fulfillmentMethod
|
||||||
|
?._id === option?.fulfillmentMethod?._id
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<span className="ml-3 text-sm">
|
||||||
|
{option?.fulfillmentMethod?.displayName ||
|
||||||
|
'Shipping Method'}
|
||||||
|
</span>
|
||||||
|
</fieldset>
|
||||||
|
<span>{option?.price.displayAmount}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="sticky z-20 bottom-0 w-full right-0 left-0 py-12 bg-accent-0 border-t border-accent-2 px-6">
|
||||||
|
<Button type="submit" width="100%" variant="ghost">
|
||||||
|
Continue
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</SidebarLayout>
|
||||||
|
</form>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ShippingMethod
|
1
site/components/checkout/ShippingMethodView/index.ts
Normal file
1
site/components/checkout/ShippingMethodView/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './ShippingMethodView'
|
@ -0,0 +1,4 @@
|
|||||||
|
.root {
|
||||||
|
@apply border border-accent-2 px-6 py-5 mb-4 text-center
|
||||||
|
flex items-center cursor-pointer hover:border-accent-4;
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
import { FC } from 'react'
|
||||||
|
import s from './ShippingMethodWidget.module.css'
|
||||||
|
import { ChevronRight, CreditCard, Check } from '@components/icons'
|
||||||
|
|
||||||
|
interface ComponentProps {
|
||||||
|
onClick?: () => any
|
||||||
|
isValid?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const ShippingMethodWidget: FC<ComponentProps> = ({ onClick, isValid }) => {
|
||||||
|
/* Shipping Method Widget
|
||||||
|
Only available with checkout set to true and cart has some available shipping methods
|
||||||
|
This means that the provider does offer checkout functionality. */
|
||||||
|
return (
|
||||||
|
<div onClick={onClick} className={s.root}>
|
||||||
|
<div className="flex flex-1 items-center">
|
||||||
|
<CreditCard className="w-5 flex" />
|
||||||
|
<span className="ml-5 text-sm text-center font-medium">
|
||||||
|
Add Shipping Method
|
||||||
|
</span>
|
||||||
|
{/* <span>VISA #### #### #### 2345</span> */}
|
||||||
|
</div>
|
||||||
|
<div>{isValid ? <Check /> : <ChevronRight />}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ShippingMethodWidget
|
1
site/components/checkout/ShippingMethodWidget/index.ts
Normal file
1
site/components/checkout/ShippingMethodWidget/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './ShippingMethodWidget'
|
@ -5,9 +5,9 @@ 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 useAddAddress from '@framework/customer/address/use-add-item'
|
import useAddAddress from '@framework/customer/address/use-add-item'
|
||||||
|
import { useCheckoutContext } from '../context'
|
||||||
|
|
||||||
import s from './ShippingView.module.css'
|
import s from './ShippingView.module.css'
|
||||||
import { useCheckoutContext } from '../context'
|
|
||||||
|
|
||||||
interface Form extends HTMLFormElement {
|
interface Form extends HTMLFormElement {
|
||||||
cardHolder: HTMLInputElement
|
cardHolder: HTMLInputElement
|
||||||
@ -21,6 +21,7 @@ interface Form extends HTMLFormElement {
|
|||||||
zipCode: HTMLInputElement
|
zipCode: HTMLInputElement
|
||||||
city: HTMLInputElement
|
city: HTMLInputElement
|
||||||
country: HTMLSelectElement
|
country: HTMLSelectElement
|
||||||
|
shippingMethod?: HTMLInputElement
|
||||||
}
|
}
|
||||||
|
|
||||||
const ShippingView: FC = () => {
|
const ShippingView: FC = () => {
|
||||||
@ -64,6 +65,7 @@ const ShippingView: FC = () => {
|
|||||||
Use a different shipping address
|
Use a different shipping address
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr className="border-accent-2 my-6" />
|
<hr className="border-accent-2 my-6" />
|
||||||
<div className="grid gap-3 grid-flow-row grid-cols-12">
|
<div className="grid gap-3 grid-flow-row grid-cols-12">
|
||||||
<div className={cn(s.fieldset, 'col-span-6')}>
|
<div className={cn(s.fieldset, 'col-span-6')}>
|
||||||
|
@ -7,7 +7,7 @@ import React, {
|
|||||||
createContext,
|
createContext,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import type { CardFields } from '@commerce/types/customer/card'
|
import type { CardFields } from '@commerce/types/customer/card'
|
||||||
import type { AddressFields } from '@commerce/types/customer/address'
|
import type { AddressFields } from '@framework/types/customer/address'
|
||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
cardFields: CardFields
|
cardFields: CardFields
|
||||||
@ -86,7 +86,10 @@ export const CheckoutProvider: FC = (props) => {
|
|||||||
|
|
||||||
const cardFields = useMemo(() => state.cardFields, [state.cardFields])
|
const cardFields = useMemo(() => state.cardFields, [state.cardFields])
|
||||||
|
|
||||||
const addressFields = useMemo(() => state.addressFields, [state.addressFields])
|
const addressFields = useMemo(
|
||||||
|
() => state.addressFields,
|
||||||
|
[state.addressFields]
|
||||||
|
)
|
||||||
|
|
||||||
const value = useMemo(
|
const value = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@ -96,7 +99,13 @@ export const CheckoutProvider: FC = (props) => {
|
|||||||
setAddressFields,
|
setAddressFields,
|
||||||
clearCheckoutFields,
|
clearCheckoutFields,
|
||||||
}),
|
}),
|
||||||
[cardFields, addressFields, setCardFields, setAddressFields, clearCheckoutFields]
|
[
|
||||||
|
cardFields,
|
||||||
|
addressFields,
|
||||||
|
setCardFields,
|
||||||
|
setAddressFields,
|
||||||
|
clearCheckoutFields,
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
return <CheckoutContext.Provider value={value} {...props} />
|
return <CheckoutContext.Provider value={value} {...props} />
|
||||||
|
@ -12,6 +12,7 @@ import { useAcceptCookies } from '@lib/hooks/useAcceptCookies'
|
|||||||
import { Sidebar, Button, LoadingDots } from '@components/ui'
|
import { Sidebar, Button, LoadingDots } from '@components/ui'
|
||||||
import PaymentMethodView from '@components/checkout/PaymentMethodView'
|
import PaymentMethodView from '@components/checkout/PaymentMethodView'
|
||||||
import CheckoutSidebarView from '@components/checkout/CheckoutSidebarView'
|
import CheckoutSidebarView from '@components/checkout/CheckoutSidebarView'
|
||||||
|
import ShippingMethodView from '@components/checkout/ShippingMethodView'
|
||||||
import { CheckoutProvider } from '@components/checkout/context'
|
import { CheckoutProvider } from '@components/checkout/context'
|
||||||
import { MenuSidebarView } from '@components/common/UserNav'
|
import { MenuSidebarView } from '@components/common/UserNav'
|
||||||
import type { Page } from '@commerce/types/page'
|
import type { Page } from '@commerce/types/page'
|
||||||
@ -87,6 +88,7 @@ const SidebarView: React.FC<{
|
|||||||
{sidebarView === 'CART_VIEW' && <CartSidebarView />}
|
{sidebarView === 'CART_VIEW' && <CartSidebarView />}
|
||||||
{sidebarView === 'SHIPPING_VIEW' && <ShippingView />}
|
{sidebarView === 'SHIPPING_VIEW' && <ShippingView />}
|
||||||
{sidebarView === 'PAYMENT_VIEW' && <PaymentMethodView />}
|
{sidebarView === 'PAYMENT_VIEW' && <PaymentMethodView />}
|
||||||
|
{sidebarView === 'SHIPPING_METHOD_VIEW' && <ShippingMethodView />}
|
||||||
{sidebarView === 'CHECKOUT_VIEW' && <CheckoutSidebarView />}
|
{sidebarView === 'CHECKOUT_VIEW' && <CheckoutSidebarView />}
|
||||||
{sidebarView === 'MOBILE_MENU_VIEW' && <MenuSidebarView links={links} />}
|
{sidebarView === 'MOBILE_MENU_VIEW' && <MenuSidebarView links={links} />}
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
@ -18,7 +18,7 @@ const SubItem = ({ subItem, level = 0 }: SubItemProps) => {
|
|||||||
<a
|
<a
|
||||||
className={`block rounded ml-${
|
className={`block rounded ml-${
|
||||||
level * 2
|
level * 2
|
||||||
} py-[10px] px-4 text-sm text-secondary`}
|
} py-[10px] px-4 text-sm text-black`}
|
||||||
>
|
>
|
||||||
{subItem.label}
|
{subItem.label}
|
||||||
</a>
|
</a>
|
||||||
@ -28,7 +28,7 @@ const SubItem = ({ subItem, level = 0 }: SubItemProps) => {
|
|||||||
href={subItem.url}
|
href={subItem.url}
|
||||||
className={`block rounded ml-${
|
className={`block rounded ml-${
|
||||||
level * 2
|
level * 2
|
||||||
} py-[10px] px-4 text-sm text-secondary`}
|
} py-[10px] px-4 text-sm text-black`}
|
||||||
target={subItem.shouldOpenInNewWindow ? '_blank' : ''}
|
target={subItem.shouldOpenInNewWindow ? '_blank' : ''}
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
|
@ -29,16 +29,19 @@ const Navbar: FC<NavbarProps> = ({ links, customNavigation }) => (
|
|||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<nav className={s.navMenu}>
|
<nav className={s.navMenu}>
|
||||||
<Link href="/search">
|
{process.env.COMMERCE_CUSTOMNAVIGATION_ENABLED ? (
|
||||||
<a className={s.link}>All</a>
|
|
||||||
</Link>
|
|
||||||
{links?.map((l) => (
|
|
||||||
<Link href={l.href} key={l.href}>
|
|
||||||
<a className={s.link}>{l.label}</a>
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
{process.env.COMMERCE_CUSTOMNAVIGATION_ENABLED && (
|
|
||||||
<CustomNavbar links={customNavigation} />
|
<CustomNavbar links={customNavigation} />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Link href="/search">
|
||||||
|
<a className={s.link}>All</a>
|
||||||
|
</Link>
|
||||||
|
{links?.map((l) => (
|
||||||
|
<Link href={l.href} key={l.href}>
|
||||||
|
<a className={s.link}>{l.label}</a>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user