From d65b2efe9aa206a9256ad10564453d52b24926ab Mon Sep 17 00:00:00 2001 From: Gonzalo Pozzo Date: Mon, 6 Dec 2021 18:45:54 -0300 Subject: [PATCH] Custom checkout improvements (#590) * Add context for storing checkout information * Remove unused useState --- .../checkout/ShippingView/ShippingView.tsx | 4 +- components/checkout/context.tsx | 111 ++++++++++++++++++ components/common/Layout/Layout.tsx | 5 +- framework/commerce/types/checkout.ts | 8 +- 4 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 components/checkout/context.tsx diff --git a/components/checkout/ShippingView/ShippingView.tsx b/components/checkout/ShippingView/ShippingView.tsx index ed82bc8a2..571730ed5 100644 --- a/components/checkout/ShippingView/ShippingView.tsx +++ b/components/checkout/ShippingView/ShippingView.tsx @@ -22,7 +22,7 @@ interface Form extends HTMLFormElement { country: HTMLSelectElement } -const PaymentMethodView: FC = () => { +const ShippingView: FC = () => { const { setSidebarView } = useUI() const addAddress = useAddAddress() @@ -115,4 +115,4 @@ const PaymentMethodView: FC = () => { ) } -export default PaymentMethodView +export default ShippingView diff --git a/components/checkout/context.tsx b/components/checkout/context.tsx new file mode 100644 index 000000000..b53b45a5d --- /dev/null +++ b/components/checkout/context.tsx @@ -0,0 +1,111 @@ +import React, { + FC, + useCallback, + useMemo, + useReducer, + useContext, + createContext, +} from 'react' +import type { CardFields } from '@commerce/types/customer/card' +import type { AddressFields } from '@commerce/types/customer/address' + +export type State = { + cardFields: CardFields + addressFields: AddressFields +} + +type CheckoutContextType = State & { + setCardFields: (cardFields: CardFields) => void + setAddressFields: (addressFields: AddressFields) => void + clearCheckoutFields: () => void +} + +type Action = + | { + type: 'SET_CARD_FIELDS' + card: CardFields + } + | { + type: 'SET_ADDRESS_FIELDS' + address: AddressFields + } + | { + type: 'CLEAR_CHECKOUT_FIELDS' + } + +const initialState: State = { + cardFields: {} as CardFields, + addressFields: {} as AddressFields, +} + +export const CheckoutContext = createContext(initialState) + +CheckoutContext.displayName = 'CheckoutContext' + +const checkoutReducer = (state: State, action: Action): State => { + switch (action.type) { + case 'SET_CARD_FIELDS': + return { + ...state, + cardFields: action.card, + } + case 'SET_ADDRESS_FIELDS': + return { + ...state, + addressFields: action.address, + } + case 'CLEAR_CHECKOUT_FIELDS': + return { + ...state, + cardFields: initialState.cardFields, + addressFields: initialState.addressFields, + } + default: + return state + } +} + +export const CheckoutProvider: FC = (props) => { + const [state, dispatch] = useReducer(checkoutReducer, initialState) + + const setCardFields = useCallback( + (card: CardFields) => dispatch({ type: 'SET_CARD_FIELDS', card }), + [dispatch] + ) + + const setAddressFields = useCallback( + (address: AddressFields) => + dispatch({ type: 'SET_ADDRESS_FIELDS', address }), + [dispatch] + ) + + const clearCheckoutFields = useCallback( + () => dispatch({ type: 'CLEAR_CHECKOUT_FIELDS' }), + [dispatch] + ) + + const cardFields = useMemo(() => state.cardFields, [state.cardFields]) + + const addressFields = useMemo(() => state.addressFields, [state.addressFields]) + + const value = useMemo( + () => ({ + cardFields, + addressFields, + setCardFields, + setAddressFields, + clearCheckoutFields, + }), + [cardFields, addressFields, setCardFields, setAddressFields, clearCheckoutFields] + ) + + return +} + +export const useCheckoutContext = () => { + const context = useContext(CheckoutContext) + if (context === undefined) { + throw new Error(`useCheckoutContext must be used within a CheckoutProvider`) + } + return context +} diff --git a/components/common/Layout/Layout.tsx b/components/common/Layout/Layout.tsx index 5ee6ea530..a69cd7536 100644 --- a/components/common/Layout/Layout.tsx +++ b/components/common/Layout/Layout.tsx @@ -13,6 +13,7 @@ import { useAcceptCookies } from '@lib/hooks/useAcceptCookies' import { Sidebar, Button, LoadingDots } from '@components/ui' import PaymentMethodView from '@components/checkout/PaymentMethodView' import CheckoutSidebarView from '@components/checkout/CheckoutSidebarView' +import { CheckoutProvider } from '@components/checkout/context' import MenuSidebarView, { Link } from '../UserNav/MenuSidebarView' import LoginView from '@components/auth/LoginView' @@ -120,7 +121,9 @@ const Layout: FC = ({
{children}