* Revert "Add new buttonAttributes API to style express checkout buttons coherently (#47899)"
This reverts commit 006fbc6714
.
* Add changefile(s) from automation for the following project(s): woocommerce-blocks, woocommerce
* Update changelog
* Add changefile(s) from automation for the following project(s): woocommerce-blocks, woocommerce
---------
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
parent
42e943dc0e
commit
cda0f8a3f8
|
@ -140,7 +140,7 @@ The options you feed the configuration instance are the same as those for expres
|
||||||
A big part of the payment method integration is the interface that is exposed for payment methods to use via props when the node provided is cloned and rendered on block mount. While all the props are listed below, you can find more details about what the props reference, their types etc via the [typedefs described in this file](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/assets/js/types/type-defs/payment-method-interface.ts).
|
A big part of the payment method integration is the interface that is exposed for payment methods to use via props when the node provided is cloned and rendered on block mount. While all the props are listed below, you can find more details about what the props reference, their types etc via the [typedefs described in this file](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/assets/js/types/type-defs/payment-method-interface.ts).
|
||||||
|
|
||||||
| Property | Type | Description | Values |
|
| Property | Type | Description | Values |
|
||||||
| ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `activePaymentMethod` | String | The slug of the current active payment method in the checkout. | - |
|
| `activePaymentMethod` | String | The slug of the current active payment method in the checkout. | - |
|
||||||
| `billing` | Object | Contains everything related to billing. | `billingAddress`, `cartTotal`, `currency`, `cartTotalItems`, `displayPricesIncludingTax`, `appliedCoupons`, `customerId` |
|
| `billing` | Object | Contains everything related to billing. | `billingAddress`, `cartTotal`, `currency`, `cartTotalItems`, `displayPricesIncludingTax`, `appliedCoupons`, `customerId` |
|
||||||
| `cartData` | Object | Data exposed from the cart including items, fees, and any registered extension data. Note that this data should be treated as immutable (should not be modified/mutated) or it will result in errors in your application. | `cartItems`, `cartFees`, `extensions` |
|
| `cartData` | Object | Data exposed from the cart including items, fees, and any registered extension data. Note that this data should be treated as immutable (should not be modified/mutated) or it will result in errors in your application. | `cartItems`, `cartFees`, `extensions` |
|
||||||
|
@ -151,7 +151,6 @@ A big part of the payment method integration is the interface that is exposed fo
|
||||||
| `onClick` | Function | **Provided to express payment methods** that should be triggered when the payment method button is clicked (which will signal to checkout the payment method has taken over payment processing) | - |
|
| `onClick` | Function | **Provided to express payment methods** that should be triggered when the payment method button is clicked (which will signal to checkout the payment method has taken over payment processing) | - |
|
||||||
| `onClose` | Function | **Provided to express payment methods** that should be triggered when the express payment method modal closes and control is returned to checkout. | - |
|
| `onClose` | Function | **Provided to express payment methods** that should be triggered when the express payment method modal closes and control is returned to checkout. | - |
|
||||||
| `onSubmit` | Function | Submits the checkout and begins processing | - |
|
| `onSubmit` | Function | Submits the checkout and begins processing | - |
|
||||||
| `buttonAttributes` | Object | Styles set by the merchant that should be respected by all express payment buttons | `height, borderRadius, darkMode` |
|
|
||||||
| `paymentStatus` | Object | Various payment status helpers. Note, your payment method does not have to handle setting this status client side. Checkout will handle this via the responses your payment method gives from observers registered to [checkout event emitters](./checkout-flow-and-events.md). | `isPristine`, `isStarted`, `isProcessing`, `isFinished`, `hasError`, `hasFailed`, `isSuccessful` (see below for explanation) |
|
| `paymentStatus` | Object | Various payment status helpers. Note, your payment method does not have to handle setting this status client side. Checkout will handle this via the responses your payment method gives from observers registered to [checkout event emitters](./checkout-flow-and-events.md). | `isPristine`, `isStarted`, `isProcessing`, `isFinished`, `hasError`, `hasFailed`, `isSuccessful` (see below for explanation) |
|
||||||
| `setExpressPaymentError` | Function | Receives a string and allows express payment methods to set an error notice for the express payment area on demand. This can be necessary because some express payment method processing might happen outside of checkout events. | - |
|
| `setExpressPaymentError` | Function | Receives a string and allows express payment methods to set an error notice for the express payment area on demand. This can be necessary because some express payment method processing might happen outside of checkout events. | - |
|
||||||
| `shippingData` | Object | Contains all shipping related data (outside of the shipping status). | `shippingRates`, `shippingRatesLoading`, `selectedRates`, `setSelectedRates`, `isSelectingRate`, `shippingAddress`, `setShippingAddress`, and `needsShipping` |
|
| `shippingData` | Object | Contains all shipping related data (outside of the shipping status). | `shippingRates`, `shippingRatesLoading`, `selectedRates`, `setSelectedRates`, `isSelectingRate`, `shippingAddress`, `setShippingAddress`, and `needsShipping` |
|
||||||
|
@ -168,33 +167,6 @@ A big part of the payment method integration is the interface that is exposed fo
|
||||||
|
|
||||||
Any registered `savedTokenComponent` node will also receive a `token` prop which includes the id for the selected saved token in case your payment method needs to use it for some internal logic. However, keep in mind, this is just the id representing this token in the database (and the value of the radio input the shopper checked), not the actual customer payment token (since processing using that usually happens on the server for security).
|
Any registered `savedTokenComponent` node will also receive a `token` prop which includes the id for the selected saved token in case your payment method needs to use it for some internal logic. However, keep in mind, this is just the id representing this token in the database (and the value of the radio input the shopper checked), not the actual customer payment token (since processing using that usually happens on the server for security).
|
||||||
|
|
||||||
### Button Attributes for Express Payment Methods
|
|
||||||
|
|
||||||
This API provides a way to synchronise the look and feel of the express payment buttons for a coherent shopper experience. Express Payment Methods must prefer the values provided in the `buttonAttributes`, and use it's own configuration settings as backup when the buttons are rendered somewhere other than the Cart or Checkout block.
|
|
||||||
|
|
||||||
For example, in your button component, you would do something like this:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// Get your extension specific settings and set defaults if not available
|
|
||||||
let {
|
|
||||||
theme = 'dark',
|
|
||||||
borderRadius = '4',
|
|
||||||
height = '48',
|
|
||||||
} = getButtonSettingsFromConfig();
|
|
||||||
|
|
||||||
// In a cart & checkout block context, we receive `buttonAttributes` as a prop which overwrite the extension specific settings
|
|
||||||
if ( typeof buttonAttributes !== 'undefined' ) {
|
|
||||||
height = buttonAttributes.height;
|
|
||||||
borderRadius = buttonAttributes.borderRadius;
|
|
||||||
theme = buttonAttributes.darkMode ? 'light' : 'dark';
|
|
||||||
}
|
|
||||||
...
|
|
||||||
|
|
||||||
return <button style={height: `${height}px`, borderRadius: `${borderRadius}px`} data-theme={theme} />
|
|
||||||
```
|
|
||||||
|
|
||||||
Note the `height` and `borderRadius` properties should always be respected. The `darkMode` is an optional property that may be used by an extension as a clue to help identify what colour button would be best rendered, given the user's theme.
|
|
||||||
|
|
||||||
## Server Side Integration
|
## Server Side Integration
|
||||||
|
|
||||||
### Processing Payment
|
### Processing Payment
|
||||||
|
|
|
@ -180,7 +180,7 @@
|
||||||
"menu_title": "Payment Method Integration",
|
"menu_title": "Payment Method Integration",
|
||||||
"tags": "reference",
|
"tags": "reference",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md",
|
||||||
"hash": "dd8caf9a8f79bb0806887bb41f64f9e32da5542e1c4cabdf0057c7e17f4208b5",
|
"hash": "f60acaaea4a6ac4adf637bc7069c966e01db089f9dfaa937def91165a71a4255",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md",
|
||||||
"id": "c9a763b6976ecf03aeb961577c17c31f1ac7c420",
|
"id": "c9a763b6976ecf03aeb961577c17c31f1ac7c420",
|
||||||
"links": {
|
"links": {
|
||||||
|
@ -1016,7 +1016,7 @@
|
||||||
"menu_title": "DOM Events",
|
"menu_title": "DOM Events",
|
||||||
"tags": "how-to",
|
"tags": "how-to",
|
||||||
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/product-collection-block/dom-events.md",
|
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/product-collection-block/dom-events.md",
|
||||||
"hash": "fbad20bc55cc569161e80478c0789db3c34cf35513e669554af36db1de967a26",
|
"hash": "78bce4ab5b5e902232b5ff73fd7a7c197e4f4417a490ccb45c9a27400d003787",
|
||||||
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/product-collection-block/dom-events.md",
|
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/product-collection-block/dom-events.md",
|
||||||
"id": "c8d247b91472740075871e6b57a9583d893ac650"
|
"id": "c8d247b91472740075871e6b57a9583d893ac650"
|
||||||
}
|
}
|
||||||
|
@ -1706,5 +1706,5 @@
|
||||||
"categories": []
|
"categories": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hash": "7c588f43c6f82a8f916b4ab0ff8046539685db971ad9c6ccb26da9a8dfef0fa4"
|
"hash": "402a928bfa0399c09151423796f98caeb8f99a70f8a4cf009db6703ec7949468"
|
||||||
}
|
}
|
|
@ -15,31 +15,16 @@ import {
|
||||||
import { useEditorContext } from '@woocommerce/base-context';
|
import { useEditorContext } from '@woocommerce/base-context';
|
||||||
import deprecated from '@wordpress/deprecated';
|
import deprecated from '@wordpress/deprecated';
|
||||||
import { useDispatch, useSelect } from '@wordpress/data';
|
import { useDispatch, useSelect } from '@wordpress/data';
|
||||||
import { useCheckoutBlockContext } from '@woocommerce/blocks/checkout/context';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import PaymentMethodErrorBoundary from './payment-method-error-boundary';
|
import PaymentMethodErrorBoundary from './payment-method-error-boundary';
|
||||||
import { STORE_KEY as PAYMENT_STORE_KEY } from '../../../data/payment/constants';
|
import { STORE_KEY as PAYMENT_STORE_KEY } from '../../../data/payment/constants';
|
||||||
import { useExpressCheckoutContext } from '../../checkout/inner-blocks/checkout-express-payment-block/context';
|
|
||||||
|
|
||||||
const ExpressPaymentMethods = () => {
|
const ExpressPaymentMethods = () => {
|
||||||
const { isEditor } = useEditorContext();
|
const { isEditor } = useEditorContext();
|
||||||
|
|
||||||
const { hasDarkControls } = useCheckoutBlockContext();
|
|
||||||
const { showButtonStyles, buttonHeight, buttonBorderRadius } =
|
|
||||||
useExpressCheckoutContext();
|
|
||||||
|
|
||||||
// API for passing styles to express payment buttons
|
|
||||||
const buttonAttributes = showButtonStyles
|
|
||||||
? {
|
|
||||||
height: buttonHeight,
|
|
||||||
borderRadius: buttonBorderRadius,
|
|
||||||
darkMode: hasDarkControls,
|
|
||||||
}
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const { activePaymentMethod, paymentMethodData } = useSelect(
|
const { activePaymentMethod, paymentMethodData } = useSelect(
|
||||||
( select ) => {
|
( select ) => {
|
||||||
const store = select( PAYMENT_STORE_KEY );
|
const store = select( PAYMENT_STORE_KEY );
|
||||||
|
@ -142,20 +127,6 @@ const ExpressPaymentMethods = () => {
|
||||||
[ __internalSetExpressPaymentError, onExpressPaymentError ]
|
[ __internalSetExpressPaymentError, onExpressPaymentError ]
|
||||||
);
|
);
|
||||||
|
|
||||||
// In the editor, we apply styles to the button containers to show the changes of the height and border-radius controls,
|
|
||||||
// which would be passed to the payment APIs on the front-end
|
|
||||||
const stylesForButtonContainers = isEditor
|
|
||||||
? {
|
|
||||||
height: `${ showButtonStyles ? buttonHeight : '48' }px`,
|
|
||||||
borderRadius: `${
|
|
||||||
showButtonStyles ? buttonBorderRadius : '4'
|
|
||||||
}px`,
|
|
||||||
pointerEvents: 'none',
|
|
||||||
userSelect: 'none',
|
|
||||||
ariaDisabled: true,
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo Find a way to Memoize Express Payment Method Content
|
* @todo Find a way to Memoize Express Payment Method Content
|
||||||
*
|
*
|
||||||
|
@ -171,11 +142,7 @@ const ExpressPaymentMethods = () => {
|
||||||
? paymentMethod.edit
|
? paymentMethod.edit
|
||||||
: paymentMethod.content;
|
: paymentMethod.content;
|
||||||
return isValidElement( expressPaymentMethod ) ? (
|
return isValidElement( expressPaymentMethod ) ? (
|
||||||
<li
|
<li key={ id } id={ `express-payment-method-${ id }` }>
|
||||||
key={ id }
|
|
||||||
id={ `express-payment-method-${ id }` }
|
|
||||||
style={ stylesForButtonContainers }
|
|
||||||
>
|
|
||||||
{ cloneElement( expressPaymentMethod, {
|
{ cloneElement( expressPaymentMethod, {
|
||||||
...paymentMethodInterface,
|
...paymentMethodInterface,
|
||||||
onClick: onExpressPaymentClick( id ),
|
onClick: onExpressPaymentClick( id ),
|
||||||
|
@ -183,7 +150,6 @@ const ExpressPaymentMethods = () => {
|
||||||
onError: onExpressPaymentError,
|
onError: onExpressPaymentError,
|
||||||
setExpressPaymentError:
|
setExpressPaymentError:
|
||||||
deprecatedSetExpressPaymentError,
|
deprecatedSetExpressPaymentError,
|
||||||
buttonAttributes,
|
|
||||||
} ) }
|
} ) }
|
||||||
</li>
|
</li>
|
||||||
) : null;
|
) : null;
|
|
@ -1,2 +1,2 @@
|
||||||
export { default as CartExpressPayment } from './cart-express-payment.js';
|
export { default as CartExpressPayment } from './cart-express-payment.js';
|
||||||
export { default as CheckoutExpressPayment } from './checkout-express-payment';
|
export { default as CheckoutExpressPayment } from './checkout-express-payment.js';
|
||||||
|
|
|
@ -14,11 +14,10 @@ $border-width: 1px;
|
||||||
> li {
|
> li {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
> img {
|
> img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: 48px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
// This needs to be defined in a separate file because we are mocking an import.
|
|
||||||
// The only way to do this is to define the mock and import it BEFORE the module being mocked.
|
|
||||||
export default jest.fn( () => ( { isEditor: false } ) );
|
|
|
@ -1,188 +0,0 @@
|
||||||
// This is the shape of the API exposed to the express payment methods via props
|
|
||||||
// Note that this is a public API!
|
|
||||||
export const getExpectedExpressPaymentProps = ( name: string ) => ( {
|
|
||||||
activePaymentMethod: undefined,
|
|
||||||
billing: {
|
|
||||||
appliedCoupons: [],
|
|
||||||
billingAddress: {
|
|
||||||
address_1: '',
|
|
||||||
address_2: '',
|
|
||||||
city: '',
|
|
||||||
company: '',
|
|
||||||
country: '',
|
|
||||||
first_name: '',
|
|
||||||
last_name: '',
|
|
||||||
phone: '',
|
|
||||||
postcode: '',
|
|
||||||
state: '',
|
|
||||||
},
|
|
||||||
billingData: {
|
|
||||||
address_1: '',
|
|
||||||
address_2: '',
|
|
||||||
city: '',
|
|
||||||
company: '',
|
|
||||||
country: '',
|
|
||||||
first_name: '',
|
|
||||||
last_name: '',
|
|
||||||
phone: '',
|
|
||||||
postcode: '',
|
|
||||||
state: '',
|
|
||||||
},
|
|
||||||
cartTotal: {
|
|
||||||
label: 'Total',
|
|
||||||
value: 0,
|
|
||||||
},
|
|
||||||
cartTotalItems: [
|
|
||||||
{
|
|
||||||
key: 'total_items',
|
|
||||||
label: 'Subtotal:',
|
|
||||||
value: 0,
|
|
||||||
valueWithTax: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'total_fees',
|
|
||||||
label: 'Fees:',
|
|
||||||
value: 0,
|
|
||||||
valueWithTax: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'total_discount',
|
|
||||||
label: 'Discount:',
|
|
||||||
value: 0,
|
|
||||||
valueWithTax: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'total_tax',
|
|
||||||
label: 'Taxes:',
|
|
||||||
value: 0,
|
|
||||||
valueWithTax: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'total_shipping',
|
|
||||||
label: 'Shipping:',
|
|
||||||
value: 0,
|
|
||||||
valueWithTax: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
currency: {
|
|
||||||
code: 'USD',
|
|
||||||
decimalSeparator: '.',
|
|
||||||
minorUnit: 2,
|
|
||||||
prefix: '$',
|
|
||||||
suffix: '',
|
|
||||||
symbol: '$',
|
|
||||||
thousandSeparator: ',',
|
|
||||||
},
|
|
||||||
customerId: 1,
|
|
||||||
displayPricesIncludingTax: false,
|
|
||||||
},
|
|
||||||
buttonAttributes: {
|
|
||||||
borderRadius: '4',
|
|
||||||
darkMode: false,
|
|
||||||
height: '48',
|
|
||||||
},
|
|
||||||
cartData: {
|
|
||||||
cartFees: [],
|
|
||||||
cartItems: [],
|
|
||||||
extensions: {},
|
|
||||||
},
|
|
||||||
checkoutStatus: {
|
|
||||||
isCalculating: false,
|
|
||||||
isComplete: false,
|
|
||||||
isIdle: true,
|
|
||||||
isProcessing: false,
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
LoadingMask: expect.any( Function ),
|
|
||||||
PaymentMethodIcons: expect.any( Function ),
|
|
||||||
PaymentMethodLabel: expect.any( Function ),
|
|
||||||
ValidationInputError: expect.any( Function ),
|
|
||||||
},
|
|
||||||
emitResponse: {
|
|
||||||
noticeContexts: {
|
|
||||||
BILLING_ADDRESS: 'wc/checkout/billing-address',
|
|
||||||
CART: 'wc/cart',
|
|
||||||
CHECKOUT: 'wc/checkout',
|
|
||||||
CHECKOUT_ACTIONS: 'wc/checkout/checkout-actions',
|
|
||||||
CONTACT_INFORMATION: 'wc/checkout/contact-information',
|
|
||||||
EXPRESS_PAYMENTS: 'wc/checkout/express-payments',
|
|
||||||
ORDER_INFORMATION: 'wc/checkout/additional-information',
|
|
||||||
PAYMENTS: 'wc/checkout/payments',
|
|
||||||
SHIPPING_ADDRESS: 'wc/checkout/shipping-address',
|
|
||||||
SHIPPING_METHODS: 'wc/checkout/shipping-methods',
|
|
||||||
},
|
|
||||||
responseTypes: {
|
|
||||||
ERROR: 'error',
|
|
||||||
FAIL: 'failure',
|
|
||||||
SUCCESS: 'success',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
eventRegistration: {
|
|
||||||
onCheckoutAfterProcessingWithError: expect.any( Function ),
|
|
||||||
onCheckoutAfterProcessingWithSuccess: expect.any( Function ),
|
|
||||||
onCheckoutBeforeProcessing: expect.any( Function ),
|
|
||||||
onCheckoutFail: expect.any( Function ),
|
|
||||||
onCheckoutSuccess: expect.any( Function ),
|
|
||||||
onCheckoutValidation: expect.any( Function ),
|
|
||||||
onCheckoutValidationBeforeProcessing: expect.any( Function ),
|
|
||||||
onPaymentProcessing: expect.any( Function ),
|
|
||||||
onPaymentSetup: expect.any( Function ),
|
|
||||||
onShippingRateFail: expect.any( Function ),
|
|
||||||
onShippingRateSelectFail: expect.any( Function ),
|
|
||||||
onShippingRateSelectSuccess: expect.any( Function ),
|
|
||||||
onShippingRateSuccess: expect.any( Function ),
|
|
||||||
},
|
|
||||||
name,
|
|
||||||
onClick: expect.any( Function ),
|
|
||||||
onClose: expect.any( Function ),
|
|
||||||
onError: expect.any( Function ),
|
|
||||||
onSubmit: expect.any( Function ),
|
|
||||||
paymentStatus: {
|
|
||||||
hasError: false,
|
|
||||||
hasFailed: false,
|
|
||||||
isDoingExpressPayment: false,
|
|
||||||
isFinished: false,
|
|
||||||
isIdle: true,
|
|
||||||
isPristine: true,
|
|
||||||
isProcessing: false,
|
|
||||||
isReady: false,
|
|
||||||
isStarted: false,
|
|
||||||
isSuccessful: false,
|
|
||||||
},
|
|
||||||
setExpressPaymentError: expect.any( Function ),
|
|
||||||
shippingData: {
|
|
||||||
isSelectingRate: false,
|
|
||||||
needsShipping: true,
|
|
||||||
selectedRates: {},
|
|
||||||
setSelectedRates: expect.any( Function ),
|
|
||||||
setShippingAddress: expect.any( Function ),
|
|
||||||
shippingAddress: {
|
|
||||||
address_1: '',
|
|
||||||
address_2: '',
|
|
||||||
city: '',
|
|
||||||
company: '',
|
|
||||||
country: '',
|
|
||||||
first_name: '',
|
|
||||||
last_name: '',
|
|
||||||
phone: '',
|
|
||||||
postcode: '',
|
|
||||||
state: '',
|
|
||||||
},
|
|
||||||
shippingRates: [],
|
|
||||||
shippingRatesLoading: false,
|
|
||||||
},
|
|
||||||
shippingStatus: {
|
|
||||||
shippingErrorStatus: {
|
|
||||||
hasError: false,
|
|
||||||
hasInvalidAddress: false,
|
|
||||||
isPristine: true,
|
|
||||||
isValid: false,
|
|
||||||
},
|
|
||||||
shippingErrorTypes: {
|
|
||||||
INVALID_ADDRESS: 'invalid_address',
|
|
||||||
NONE: 'none',
|
|
||||||
UNKNOWN: 'unknown_error',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
shouldSavePayment: false,
|
|
||||||
} );
|
|
|
@ -1,122 +0,0 @@
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { render, screen } from '@testing-library/react';
|
|
||||||
import { PAYMENT_STORE_KEY } from '@woocommerce/block-data';
|
|
||||||
import {
|
|
||||||
registerExpressPaymentMethod,
|
|
||||||
__experimentalDeRegisterExpressPaymentMethod,
|
|
||||||
} from '@woocommerce/blocks-registry';
|
|
||||||
import { dispatch } from '@wordpress/data';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import mockEditorContext from './__mocks__/editor-context';
|
|
||||||
import { getExpectedExpressPaymentProps } from './__mocks__/express-payment-props';
|
|
||||||
import ExpressPaymentMethods from '../express-payment-methods';
|
|
||||||
jest.mock( '@woocommerce/base-context', () => ( {
|
|
||||||
useEditorContext: mockEditorContext,
|
|
||||||
} ) );
|
|
||||||
|
|
||||||
const mockExpressPaymentMethodNames = [ 'paypal', 'google pay', 'apple pay' ];
|
|
||||||
|
|
||||||
const MockExpressButton = jest.fn( ( { name } ) => (
|
|
||||||
<div className="boo">{ `${ name } button` }</div>
|
|
||||||
) );
|
|
||||||
|
|
||||||
const MockEditorExpressButton = jest.fn( ( { name } ) => (
|
|
||||||
<div>{ `${ name } preview` }</div>
|
|
||||||
) );
|
|
||||||
|
|
||||||
const registerMockExpressPaymentMethods = () => {
|
|
||||||
mockExpressPaymentMethodNames.forEach( ( name ) => {
|
|
||||||
registerExpressPaymentMethod( {
|
|
||||||
name,
|
|
||||||
paymentMethodId: name,
|
|
||||||
content: <MockExpressButton name={ name } />,
|
|
||||||
edit: <MockEditorExpressButton name={ name } />,
|
|
||||||
canMakePayment: () => true,
|
|
||||||
supports: {
|
|
||||||
features: [ 'products' ],
|
|
||||||
},
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
dispatch( PAYMENT_STORE_KEY ).__internalUpdateAvailablePaymentMethods();
|
|
||||||
};
|
|
||||||
|
|
||||||
const deregisterMockExpressPaymentMethods = () => {
|
|
||||||
mockExpressPaymentMethodNames.forEach( ( name ) => {
|
|
||||||
__experimentalDeRegisterExpressPaymentMethod( name );
|
|
||||||
} );
|
|
||||||
};
|
|
||||||
|
|
||||||
describe( 'Express payment methods', () => {
|
|
||||||
afterAll( () => {
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
} );
|
|
||||||
describe( 'No payment methods available', () => {
|
|
||||||
it( 'should display no registered payment methods', () => {
|
|
||||||
render( <ExpressPaymentMethods /> );
|
|
||||||
|
|
||||||
const noPaymentMethods = screen.queryAllByText(
|
|
||||||
/No registered Payment Methods/
|
|
||||||
);
|
|
||||||
expect( noPaymentMethods.length ).toEqual( 1 );
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
|
|
||||||
describe( 'Payment methods available', () => {
|
|
||||||
beforeAll( () => {
|
|
||||||
registerMockExpressPaymentMethods();
|
|
||||||
} );
|
|
||||||
afterAll( () => {
|
|
||||||
deregisterMockExpressPaymentMethods();
|
|
||||||
} );
|
|
||||||
describe( 'In a frontend context', () => {
|
|
||||||
it( 'should display the element provided by paymentMethods.content', () => {
|
|
||||||
render( <ExpressPaymentMethods /> );
|
|
||||||
mockExpressPaymentMethodNames.forEach( ( name ) => {
|
|
||||||
const btn = screen.getByText( `${ name } button` );
|
|
||||||
expect( btn ).toBeVisible();
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
it( 'should pass the correct properties to the rendered element', () => {
|
|
||||||
render( <ExpressPaymentMethods /> );
|
|
||||||
mockExpressPaymentMethodNames.forEach( ( name ) => {
|
|
||||||
expect( MockExpressButton ).toHaveBeenCalledWith(
|
|
||||||
getExpectedExpressPaymentProps( name ),
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
} );
|
|
||||||
// Expect some deprecation warnings
|
|
||||||
expect( console ).toHaveWarnedWith(
|
|
||||||
'isPristine is deprecated since version 9.6.0. Please use isIdle instead. See: https://github.com/woocommerce/woocommerce-blocks/pull/8110'
|
|
||||||
);
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
describe( 'In an editor context', () => {
|
|
||||||
beforeEach( () => {
|
|
||||||
mockEditorContext.mockImplementation( () => ( {
|
|
||||||
isEditor: true,
|
|
||||||
} ) );
|
|
||||||
} );
|
|
||||||
it( 'should display the element provided by paymentMethods.edit', () => {
|
|
||||||
render( <ExpressPaymentMethods /> );
|
|
||||||
mockExpressPaymentMethodNames.forEach( ( name ) => {
|
|
||||||
const btn = screen.getByText( `${ name } preview` );
|
|
||||||
expect( btn ).toBeVisible();
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
it( 'should pass the correct properties to the rendered element', () => {
|
|
||||||
render( <ExpressPaymentMethods /> );
|
|
||||||
mockExpressPaymentMethodNames.forEach( ( name ) => {
|
|
||||||
expect( MockEditorExpressButton ).toHaveBeenCalledWith(
|
|
||||||
getExpectedExpressPaymentProps( name ),
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
} );
|
|
|
@ -32,20 +32,3 @@
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Center images rendered in place of buttons in the editor
|
|
||||||
.wc-block-components-express-payment {
|
|
||||||
.wc-block-components-express-payment__event-buttons {
|
|
||||||
> li {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
> img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -65,7 +65,6 @@ const Checkout = ( {
|
||||||
requireApartmentField,
|
requireApartmentField,
|
||||||
showPhoneField,
|
showPhoneField,
|
||||||
requirePhoneField,
|
requirePhoneField,
|
||||||
hasDarkControls,
|
|
||||||
showFormStepNumbers,
|
showFormStepNumbers,
|
||||||
} = attributes;
|
} = attributes;
|
||||||
|
|
||||||
|
@ -99,7 +98,6 @@ const Checkout = ( {
|
||||||
requireApartmentField,
|
requireApartmentField,
|
||||||
showPhoneField,
|
showPhoneField,
|
||||||
requirePhoneField,
|
requirePhoneField,
|
||||||
hasDarkControls,
|
|
||||||
showFormStepNumbers,
|
showFormStepNumbers,
|
||||||
} as Attributes
|
} as Attributes
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ export type CheckoutBlockContextProps = {
|
||||||
showReturnToCart: boolean;
|
showReturnToCart: boolean;
|
||||||
cartPageId: number;
|
cartPageId: number;
|
||||||
showRateAfterTaxName: boolean;
|
showRateAfterTaxName: boolean;
|
||||||
hasDarkControls: boolean;
|
|
||||||
showFormStepNumbers: boolean;
|
showFormStepNumbers: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,7 +38,6 @@ export const CheckoutBlockContext: React.Context< CheckoutBlockContextProps > =
|
||||||
showReturnToCart: true,
|
showReturnToCart: true,
|
||||||
cartPageId: 0,
|
cartPageId: 0,
|
||||||
showRateAfterTaxName: false,
|
showRateAfterTaxName: false,
|
||||||
hasDarkControls: false,
|
|
||||||
showFormStepNumbers: false,
|
showFormStepNumbers: false,
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
|
@ -13,18 +13,6 @@
|
||||||
"lock": false
|
"lock": false
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"showButtonStyles": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"buttonHeight": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "48"
|
|
||||||
},
|
|
||||||
"buttonBorderRadius": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "4"
|
|
||||||
},
|
|
||||||
"className": {
|
"className": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": ""
|
"default": ""
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { CheckoutExpressPayment } from '../../../cart-checkout-shared/payment-me
|
||||||
|
|
||||||
const Block = ( { className }: { className?: string } ): JSX.Element | null => {
|
const Block = ( { className }: { className?: string } ): JSX.Element | null => {
|
||||||
const { cartNeedsPayment } = useStoreCart();
|
const { cartNeedsPayment } = useStoreCart();
|
||||||
|
|
||||||
if ( ! cartNeedsPayment ) {
|
if ( ! cartNeedsPayment ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { useContext, createContext } from '@wordpress/element';
|
|
||||||
|
|
||||||
type ExpressCheckoutContextProps = {
|
|
||||||
showButtonStyles: boolean;
|
|
||||||
buttonHeight: string;
|
|
||||||
buttonBorderRadius: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ExpressCheckoutContext: React.Context< ExpressCheckoutContextProps > =
|
|
||||||
createContext< ExpressCheckoutContextProps >( {
|
|
||||||
showButtonStyles: true,
|
|
||||||
buttonHeight: '48',
|
|
||||||
buttonBorderRadius: '4',
|
|
||||||
} );
|
|
||||||
|
|
||||||
export const useExpressCheckoutContext = () => {
|
|
||||||
return useContext( ExpressCheckoutContext );
|
|
||||||
};
|
|
|
@ -1,18 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
|
import { useBlockProps } from '@wordpress/block-editor';
|
||||||
import {
|
|
||||||
PanelBody,
|
|
||||||
RadioControl,
|
|
||||||
ToggleControl,
|
|
||||||
Notice,
|
|
||||||
TextControl,
|
|
||||||
} from '@wordpress/components';
|
|
||||||
import ExternalLinkCard from '@woocommerce/editor-components/external-link-card';
|
|
||||||
import { ADMIN_URL } from '@woocommerce/settings';
|
|
||||||
import { useExpressPaymentMethods } from '@woocommerce/base-context/hooks';
|
import { useExpressPaymentMethods } from '@woocommerce/base-context/hooks';
|
||||||
import { __ } from '@wordpress/i18n';
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,15 +10,17 @@ import clsx from 'clsx';
|
||||||
*/
|
*/
|
||||||
import Block from './block';
|
import Block from './block';
|
||||||
import './editor.scss';
|
import './editor.scss';
|
||||||
import { ExpressCheckoutAttributes } from './types';
|
|
||||||
import { ExpressCheckoutContext } from './context';
|
|
||||||
|
|
||||||
export const Edit = ( {
|
export const Edit = ( {
|
||||||
attributes,
|
attributes,
|
||||||
setAttributes,
|
|
||||||
}: {
|
}: {
|
||||||
attributes: ExpressCheckoutAttributes;
|
attributes: {
|
||||||
setAttributes: ( attributes: Record< string, unknown > ) => undefined;
|
className?: string;
|
||||||
|
lock: {
|
||||||
|
move: boolean;
|
||||||
|
remove: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
} ): JSX.Element | null => {
|
} ): JSX.Element | null => {
|
||||||
const { paymentMethods, isInitialized } = useExpressPaymentMethods();
|
const { paymentMethods, isInitialized } = useExpressPaymentMethods();
|
||||||
const hasExpressPaymentMethods = Object.keys( paymentMethods ).length > 0;
|
const hasExpressPaymentMethods = Object.keys( paymentMethods ).length > 0;
|
||||||
|
@ -47,88 +39,9 @@ export const Edit = ( {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { buttonHeight, buttonBorderRadius, showButtonStyles } = attributes;
|
|
||||||
|
|
||||||
const buttonStyleControls = (
|
|
||||||
<>
|
|
||||||
<RadioControl
|
|
||||||
label={ __( 'Button Size', 'woocommerce' ) }
|
|
||||||
selected={ buttonHeight }
|
|
||||||
options={ [
|
|
||||||
{ label: 'Small (40px)', value: '40' },
|
|
||||||
{ label: 'Medium (48px)', value: '48' },
|
|
||||||
{ label: 'Large (55px)', value: '55' },
|
|
||||||
] }
|
|
||||||
onChange={ ( newValue: string ) =>
|
|
||||||
setAttributes( { buttonHeight: newValue } )
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<div className="border-radius-control-container">
|
|
||||||
<TextControl
|
|
||||||
label={ __( 'Button Border Radius', 'woocommerce' ) }
|
|
||||||
value={ buttonBorderRadius }
|
|
||||||
onChange={ ( newValue: string ) =>
|
|
||||||
setAttributes( {
|
|
||||||
buttonBorderRadius: newValue,
|
|
||||||
} )
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<span className="border-radius-control-px">px</span>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
const showControls = () => {
|
|
||||||
if ( showButtonStyles ) {
|
|
||||||
return buttonStyleControls;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Notice
|
|
||||||
status="info"
|
|
||||||
isDismissible={ false }
|
|
||||||
className="show-button-styles-notice"
|
|
||||||
>
|
|
||||||
<p className="wc-block-checkout__controls-text">
|
|
||||||
{ __(
|
|
||||||
'You can change the appearance of individual buttons in the respective payment extension settings page',
|
|
||||||
'woocommerce'
|
|
||||||
) }
|
|
||||||
</p>
|
|
||||||
<ExternalLinkCard
|
|
||||||
href={ `${ ADMIN_URL }admin.php?page=wc-settings&tab=checkout` }
|
|
||||||
title="Payment Settings"
|
|
||||||
/>
|
|
||||||
</Notice>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div { ...blockProps }>
|
<div { ...blockProps }>
|
||||||
<InspectorControls>
|
|
||||||
<PanelBody title={ __( 'Button Settings', 'woocommerce' ) }>
|
|
||||||
<p className="wc-block-checkout__controls-text">
|
|
||||||
{ __(
|
|
||||||
'These settings will override the plugin specific styles for these buttons',
|
|
||||||
'woocommerce'
|
|
||||||
) }
|
|
||||||
</p>
|
|
||||||
<ToggleControl
|
|
||||||
label={ __( 'Express Button Styles', 'woocommerce' ) }
|
|
||||||
checked={ showButtonStyles }
|
|
||||||
onChange={ () =>
|
|
||||||
setAttributes( {
|
|
||||||
showButtonStyles: ! showButtonStyles,
|
|
||||||
} )
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{ showControls() }
|
|
||||||
</PanelBody>
|
|
||||||
</InspectorControls>
|
|
||||||
<ExpressCheckoutContext.Provider
|
|
||||||
value={ { showButtonStyles, buttonHeight, buttonBorderRadius } }
|
|
||||||
>
|
|
||||||
<Block />
|
<Block />
|
||||||
</ExpressCheckoutContext.Provider>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,37 +27,3 @@
|
||||||
margin: 0 0 1em;
|
margin: 0 0 1em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.show-button-styles-notice {
|
|
||||||
/* stylelint-disable scss/operator-no-unspaced */
|
|
||||||
margin: 0 -$gap;
|
|
||||||
/* stylelint-enable scss/operator-no-unspaced */
|
|
||||||
}
|
|
||||||
|
|
||||||
.border-radius-control-container {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.border-radius-control-px {
|
|
||||||
position: absolute;
|
|
||||||
top: 29px;
|
|
||||||
right: 12px;
|
|
||||||
color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Center images rendered in place of buttons in the editor
|
|
||||||
.wc-block-components-express-payment {
|
|
||||||
.wc-block-components-express-payment__event-buttons {
|
|
||||||
> li {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
> img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { getValidBlockAttributes } from '@woocommerce/base-utils';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import Block from './block';
|
|
||||||
import { ExpressCheckoutContext } from './context';
|
|
||||||
import metadata from './block.json';
|
|
||||||
import { ExpressCheckoutAttributes } from './types';
|
|
||||||
|
|
||||||
const FrontendBlock = ( attributes: ExpressCheckoutAttributes ) => {
|
|
||||||
const validAttributes = getValidBlockAttributes(
|
|
||||||
metadata.attributes,
|
|
||||||
attributes
|
|
||||||
);
|
|
||||||
|
|
||||||
const { showButtonStyles, buttonHeight, buttonBorderRadius } =
|
|
||||||
validAttributes;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ExpressCheckoutContext.Provider
|
|
||||||
value={ { showButtonStyles, buttonHeight, buttonBorderRadius } }
|
|
||||||
>
|
|
||||||
<Block />
|
|
||||||
</ExpressCheckoutContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FrontendBlock;
|
|
|
@ -1,10 +0,0 @@
|
||||||
export type ExpressCheckoutAttributes = {
|
|
||||||
className?: string;
|
|
||||||
buttonHeight: string;
|
|
||||||
showButtonStyles: boolean;
|
|
||||||
buttonBorderRadius: string;
|
|
||||||
lock: {
|
|
||||||
move: boolean;
|
|
||||||
remove: boolean;
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -33,7 +33,7 @@ registerCheckoutBlock( {
|
||||||
component: lazy(
|
component: lazy(
|
||||||
() =>
|
() =>
|
||||||
import(
|
import(
|
||||||
/* webpackChunkName: "checkout-blocks/express-payment" */ './checkout-express-payment-block/frontend'
|
/* webpackChunkName: "checkout-blocks/express-payment" */ './checkout-express-payment-block/block'
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
Significance: minor
|
|
||||||
Type: add
|
|
||||||
|
|
||||||
Adds unified styles for the express checkout block
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: patch
|
||||||
|
Type: update
|
||||||
|
|
||||||
|
Reverting the new `buttonAttributes` API. This will be included in a later release
|
Loading…
Reference in New Issue