Skip to content

Commit d65b2ef

Browse files
authored
Custom checkout improvements (vercel#590)
* Add context for storing checkout information * Remove unused useState
1 parent 950a763 commit d65b2ef

File tree

4 files changed

+121
-7
lines changed

4 files changed

+121
-7
lines changed

components/checkout/ShippingView/ShippingView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ interface Form extends HTMLFormElement {
2222
country: HTMLSelectElement
2323
}
2424

25-
const PaymentMethodView: FC = () => {
25+
const ShippingView: FC = () => {
2626
const { setSidebarView } = useUI()
2727
const addAddress = useAddAddress()
2828

@@ -115,4 +115,4 @@ const PaymentMethodView: FC = () => {
115115
)
116116
}
117117

118-
export default PaymentMethodView
118+
export default ShippingView

components/checkout/context.tsx

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import React, {
2+
FC,
3+
useCallback,
4+
useMemo,
5+
useReducer,
6+
useContext,
7+
createContext,
8+
} from 'react'
9+
import type { CardFields } from '@commerce/types/customer/card'
10+
import type { AddressFields } from '@commerce/types/customer/address'
11+
12+
export type State = {
13+
cardFields: CardFields
14+
addressFields: AddressFields
15+
}
16+
17+
type CheckoutContextType = State & {
18+
setCardFields: (cardFields: CardFields) => void
19+
setAddressFields: (addressFields: AddressFields) => void
20+
clearCheckoutFields: () => void
21+
}
22+
23+
type Action =
24+
| {
25+
type: 'SET_CARD_FIELDS'
26+
card: CardFields
27+
}
28+
| {
29+
type: 'SET_ADDRESS_FIELDS'
30+
address: AddressFields
31+
}
32+
| {
33+
type: 'CLEAR_CHECKOUT_FIELDS'
34+
}
35+
36+
const initialState: State = {
37+
cardFields: {} as CardFields,
38+
addressFields: {} as AddressFields,
39+
}
40+
41+
export const CheckoutContext = createContext<State | any>(initialState)
42+
43+
CheckoutContext.displayName = 'CheckoutContext'
44+
45+
const checkoutReducer = (state: State, action: Action): State => {
46+
switch (action.type) {
47+
case 'SET_CARD_FIELDS':
48+
return {
49+
...state,
50+
cardFields: action.card,
51+
}
52+
case 'SET_ADDRESS_FIELDS':
53+
return {
54+
...state,
55+
addressFields: action.address,
56+
}
57+
case 'CLEAR_CHECKOUT_FIELDS':
58+
return {
59+
...state,
60+
cardFields: initialState.cardFields,
61+
addressFields: initialState.addressFields,
62+
}
63+
default:
64+
return state
65+
}
66+
}
67+
68+
export const CheckoutProvider: FC = (props) => {
69+
const [state, dispatch] = useReducer(checkoutReducer, initialState)
70+
71+
const setCardFields = useCallback(
72+
(card: CardFields) => dispatch({ type: 'SET_CARD_FIELDS', card }),
73+
[dispatch]
74+
)
75+
76+
const setAddressFields = useCallback(
77+
(address: AddressFields) =>
78+
dispatch({ type: 'SET_ADDRESS_FIELDS', address }),
79+
[dispatch]
80+
)
81+
82+
const clearCheckoutFields = useCallback(
83+
() => dispatch({ type: 'CLEAR_CHECKOUT_FIELDS' }),
84+
[dispatch]
85+
)
86+
87+
const cardFields = useMemo(() => state.cardFields, [state.cardFields])
88+
89+
const addressFields = useMemo(() => state.addressFields, [state.addressFields])
90+
91+
const value = useMemo(
92+
() => ({
93+
cardFields,
94+
addressFields,
95+
setCardFields,
96+
setAddressFields,
97+
clearCheckoutFields,
98+
}),
99+
[cardFields, addressFields, setCardFields, setAddressFields, clearCheckoutFields]
100+
)
101+
102+
return <CheckoutContext.Provider value={value} {...props} />
103+
}
104+
105+
export const useCheckoutContext = () => {
106+
const context = useContext<CheckoutContextType>(CheckoutContext)
107+
if (context === undefined) {
108+
throw new Error(`useCheckoutContext must be used within a CheckoutProvider`)
109+
}
110+
return context
111+
}

components/common/Layout/Layout.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { useAcceptCookies } from '@lib/hooks/useAcceptCookies'
1313
import { Sidebar, Button, LoadingDots } from '@components/ui'
1414
import PaymentMethodView from '@components/checkout/PaymentMethodView'
1515
import CheckoutSidebarView from '@components/checkout/CheckoutSidebarView'
16+
import { CheckoutProvider } from '@components/checkout/context'
1617
import MenuSidebarView, { Link } from '../UserNav/MenuSidebarView'
1718

1819
import LoginView from '@components/auth/LoginView'
@@ -120,7 +121,9 @@ const Layout: FC<Props> = ({
120121
<main className="fit">{children}</main>
121122
<Footer pages={pageProps.pages} />
122123
<ModalUI />
123-
<SidebarUI links={navBarlinks} />
124+
<CheckoutProvider>
125+
<SidebarUI links={navBarlinks} />
126+
</CheckoutProvider>
124127
<FeatureBar
125128
title="This site uses cookies to improve your experience. By clicking, you agree to our Privacy Policy."
126129
hide={acceptedCookies}

framework/commerce/types/checkout.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import type { UseSubmitCheckout } from '../checkout/use-submit-checkout'
2-
import type { Address } from './customer/address'
3-
import type { Card } from './customer/card'
2+
import type { Address, AddressFields } from './customer/address'
3+
import type { Card, CardFields } from './customer/card'
44

55
// Index
66
export type Checkout = any
77

88
export type CheckoutTypes = {
9-
card?: Card
10-
address?: Address
9+
card?: Card | CardFields
10+
address?: Address | AddressFields
1111
checkout?: Checkout
1212
hasPayment?: boolean
1313
hasShipping?: boolean

0 commit comments

Comments
 (0)