2021-07-22 11:03:00 +00:00
/ * *
* External dependencies
* /
import { __ } from '@wordpress/i18n' ;
import classnames from 'classnames' ;
import { createInterpolateElement , useEffect } from '@wordpress/element' ;
import { useStoreCart , useStoreNotices } from '@woocommerce/base-context/hooks' ;
import {
useCheckoutContext ,
useValidationContext ,
ValidationContextProvider ,
StoreNoticesProvider ,
CheckoutProvider ,
} from '@woocommerce/base-context' ;
import { StoreSnackbarNoticesProvider } from '@woocommerce/base-context/providers' ;
import BlockErrorBoundary from '@woocommerce/base-components/block-error-boundary' ;
import { SidebarLayout } from '@woocommerce/base-components/sidebar-layout' ;
import { CURRENT_USER_IS_ADMIN , getSetting } from '@woocommerce/settings' ;
import { SlotFillProvider } from '@woocommerce/blocks-checkout' ;
import withScrollToTop from '@woocommerce/base-hocs/with-scroll-to-top' ;
/ * *
* Internal dependencies
* /
import './styles/style.scss' ;
import EmptyCart from './empty-cart' ;
import CheckoutOrderError from './checkout-order-error' ;
import { LOGIN_TO_CHECKOUT_URL , isLoginRequired , reloadPage } from './utils' ;
import type { Attributes } from './types' ;
import { CheckoutBlockContext } from './context' ;
const LoginPrompt = ( ) = > {
return (
< >
{ __ (
'You must be logged in to checkout. ' ,
'woo-gutenberg-products-block'
) }
< a href = { LOGIN_TO_CHECKOUT_URL } >
{ __ (
'Click here to log in.' ,
'woo-gutenberg-products-block'
) }
< / a >
< / >
) ;
} ;
const Checkout = ( {
attributes ,
children ,
} : {
attributes : Attributes ;
children : React.ReactChildren ;
} ) : JSX . Element = > {
const { hasOrder , customerId } = useCheckoutContext ( ) ;
const { cartItems , cartIsLoading } = useStoreCart ( ) ;
const {
allowCreateAccount ,
showCompanyField ,
requireCompanyField ,
showApartmentField ,
showPhoneField ,
requirePhoneField ,
} = attributes ;
if ( ! cartIsLoading && cartItems . length === 0 ) {
return < EmptyCart / > ;
}
if ( ! hasOrder ) {
return < CheckoutOrderError / > ;
}
if (
isLoginRequired ( customerId ) &&
allowCreateAccount &&
getSetting ( 'checkoutAllowsSignup' , false )
) {
< LoginPrompt / > ;
}
return (
< CheckoutBlockContext.Provider
value = { {
allowCreateAccount ,
showCompanyField ,
requireCompanyField ,
showApartmentField ,
showPhoneField ,
requirePhoneField ,
} }
>
{ children }
< / CheckoutBlockContext.Provider >
) ;
} ;
const ScrollOnError = ( {
scrollToTop ,
} : {
scrollToTop : ( props : Record < string , unknown > ) = > void ;
} ) : null = > {
const { hasNoticesOfType } = useStoreNotices ( ) ;
const {
hasError : checkoutHasError ,
isIdle : checkoutIsIdle ,
} = useCheckoutContext ( ) ;
const {
hasValidationErrors ,
showAllValidationErrors ,
} = useValidationContext ( ) ;
const hasErrorsToDisplay =
checkoutIsIdle &&
checkoutHasError &&
( hasValidationErrors || hasNoticesOfType ( 'default' ) ) ;
useEffect ( ( ) = > {
if ( hasErrorsToDisplay ) {
showAllValidationErrors ( ) ;
2021-07-23 13:21:59 +00:00
scrollToTop ( {
focusableSelector : 'input:invalid, .has-error input' ,
} ) ;
2021-07-22 11:03:00 +00:00
}
} , [ hasErrorsToDisplay , scrollToTop , showAllValidationErrors ] ) ;
return null ;
} ;
const Block = ( {
attributes ,
children ,
scrollToTop ,
} : {
attributes : Attributes ;
children : React.ReactChildren ;
scrollToTop : ( props : Record < string , unknown > ) = > void ;
} ) : JSX . Element = > (
< BlockErrorBoundary
header = { __ ( 'Something went wrong…' , 'woo-gutenberg-products-block' ) }
text = { createInterpolateElement (
__ (
'The checkout has encountered an unexpected error. <button>Try reloading the page</button>. If the error persists, please get in touch with us so we can assist.' ,
'woo-gutenberg-products-block'
) ,
{
button : (
< button
className = "wc-block-link-button"
onClick = { reloadPage }
/ >
) ,
}
) }
showErrorMessage = { CURRENT_USER_IS_ADMIN }
>
< StoreSnackbarNoticesProvider context = "wc/checkout" >
< StoreNoticesProvider context = "wc/checkout" >
< ValidationContextProvider >
2021-07-23 14:08:29 +00:00
{ /* SlotFillProvider need to be defined before CheckoutProvider so fills have the SlotFill context ready when they mount. */ }
< SlotFillProvider >
< CheckoutProvider >
2021-07-22 11:03:00 +00:00
< SidebarLayout
className = { classnames ( 'wc-block-checkout' , {
'has-dark-controls' :
attributes . hasDarkControls ,
} ) }
>
< Checkout attributes = { attributes } >
{ children }
< / Checkout >
< ScrollOnError scrollToTop = { scrollToTop } / >
< / SidebarLayout >
2021-07-23 14:08:29 +00:00
< / CheckoutProvider >
< / SlotFillProvider >
2021-07-22 11:03:00 +00:00
< / ValidationContextProvider >
< / StoreNoticesProvider >
< / StoreSnackbarNoticesProvider >
< / BlockErrorBoundary >
) ;
export default withScrollToTop ( Block ) ;