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 }