Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Update checkout payment methods design. #3439

Merged
merged 58 commits into from Feb 2, 2021
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
879f273
Add left vertical bar to payments methods step.
budzanowski Nov 5, 2020
492b700
Remove horizontal borders around order notes.
budzanowski Nov 5, 2020
71de601
Add class to order notes component.
budzanowski Nov 5, 2020
ae81e10
Update padding on order notes checkbox to match desing.
budzanowski Nov 5, 2020
9b81c48
Remove full stop to match the design.
budzanowski Nov 5, 2020
bd5343a
Add label for not saved payment methods option.
budzanowski Nov 5, 2020
ae84e6b
Remove use new payment radio.
budzanowski Nov 5, 2020
a8b7c25
Always show new ayment methods selector
budzanowski Nov 5, 2020
923fb35
Remove editor context for now.
budzanowski Nov 6, 2020
d275256
Add accordion component skeleton.
budzanowski Nov 6, 2020
7d09cc7
Small component refactor.
budzanowski Nov 6, 2020
bdf579b
Use accordion for new payment options.
budzanowski Nov 6, 2020
a8f2669
Fix jsdoc.
budzanowski Nov 6, 2020
0795f36
Add styling.
budzanowski Nov 6, 2020
22f2525
Add input styling.
budzanowski Nov 7, 2020
3f5ebbc
Hide label if we don't have saved methods.
budzanowski Nov 7, 2020
61bbe0c
Cleanup.
budzanowski Nov 7, 2020
c04d4e8
Cleanup and styling.
budzanowski Nov 7, 2020
a6c805a
Add target class to aid with alignment.
budzanowski Nov 10, 2020
122b9be
Merge branch 'trunk' into update/checkout-payment-methods-design
budzanowski Nov 23, 2020
105ab41
Update use new payments label styling.
budzanowski Nov 23, 2020
eb2012c
Update Place Order button location.
budzanowski Nov 23, 2020
a35f101
Merge branch 'trunk' into update/checkout-payment-methods-design
budzanowski Nov 23, 2020
21d4532
add full stop to payment method copy
haszari Nov 23, 2020
5381cfc
ensure that there is always a (default) selected payment method:
haszari Nov 25, 2020
6b55b10
use tab-based payment UI for 2 or fewer payment methods:
haszari Nov 26, 2020
e09dd48
experimental - styling tweaks for single payment tab (remove "tab" UI)
haszari Nov 27, 2020
994f4e9
Merge branch 'trunk' into update/checkout-payment-methods-design
budzanowski Dec 3, 2020
338ca04
Merge branch 'trunk' into update/checkout-payment-methods-design
budzanowski Dec 3, 2020
df4f0bc
Revert "experimental - styling tweaks for single payment tab (remove …
budzanowski Dec 4, 2020
4d5b94c
Add single payment method UI.
budzanowski Dec 4, 2020
72b5c1c
Adjust single method styling.
budzanowski Dec 4, 2020
fd73938
Merge branch 'trunk' into update/checkout-payment-methods-design
budzanowski Dec 14, 2020
ef4f8db
Add outline and margin to two methods version.
budzanowski Dec 14, 2020
6f101d9
Fix gap for order notes on/off option.
budzanowski Dec 14, 2020
27d5294
Update Order button spacing CSS.
budzanowski Dec 14, 2020
6bcd3b4
Merge branch 'trunk' into update/checkout-payment-methods-design
budzanowski Dec 21, 2020
3ec3f7d
Reuse computed values.
budzanowski Dec 22, 2020
e1e16f6
Merge branch 'trunk' into update/checkout-payment-methods-design
budzanowski Dec 22, 2020
c44dca5
Remove tabs and single payment option.
budzanowski Jan 13, 2021
a8d45c8
Merge branch 'trunk' into update/checkout-payment-methods-design
budzanowski Jan 13, 2021
73e479f
We no longer need this test as the UI was changed.
budzanowski Jan 14, 2021
195a2a2
Merge branch 'trunk' into update/checkout-payment-methods-design
budzanowski Jan 16, 2021
987ac57
Fix payment methods labels height.
budzanowski Jan 25, 2021
906a3d8
Simplify.
budzanowski Jan 25, 2021
cde05f9
Remove not needed import.
budzanowski Jan 25, 2021
60a047d
Typecheck an option.
budzanowski Jan 25, 2021
186343e
Refactor code.
budzanowski Jan 25, 2021
ad62724
Rename.
budzanowski Jan 25, 2021
3e6ee75
Rename.
budzanowski Jan 25, 2021
c680c17
Merge branch 'trunk' into update/checkout-payment-methods-design
budzanowski Jan 25, 2021
405a04e
Update typdefs.
budzanowski Jan 25, 2021
bec3dcd
Merge branch '01-trunk' into update/checkout-payment-methods-design
nerrad Jan 29, 2021
aff8f68
Merge branch 'trunk' into update/checkout-payment-methods-design
budzanowski Jan 31, 2021
49a1a6a
Remove border for add order notes.
budzanowski Jan 31, 2021
531c80f
Correct spacing for radio-button and label.
budzanowski Jan 31, 2021
a57ccdf
Add simple test. Switch to payment method.
budzanowski Feb 1, 2021
17250c1
Update style.
budzanowski Feb 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 0 additions & 4 deletions assets/js/base/components/cart-checkout/form-step/style.scss
Expand Up @@ -94,8 +94,4 @@
left: -$gap-larger/2;
top: 0;
}

&:last-of-type .wc-block-components-checkout-step__container::after {
content: none;
}
}
Expand Up @@ -16,17 +16,16 @@ import PropTypes from 'prop-types';
import PaymentMethodErrorBoundary from './payment-method-error-boundary';

/**
* Component used to render the contents of a payment method tab.
* Component used to render the contents of a payment method card.
*
* @param {Object} props Incoming props for the component.
* @param {boolean} props.showSaveOption Whether that payment method allows saving
* the data for future purchases and should
* display the checkbox to do so.
* @param {Object} props.children Content of the payment method tab.
* the data for future purchases.
* @param {Object} props.children Content of the payment method card.
*
* @return {*} The rendered component.
*/
const PaymentMethodTab = ( { children, showSaveOption } ) => {
const PaymentMethodCard = ( { children, showSaveOption } ) => {
const { isEditor } = useEditorContext();
const {
shouldSavePayment,
Expand Down Expand Up @@ -54,9 +53,9 @@ const PaymentMethodTab = ( { children, showSaveOption } ) => {
);
};

PaymentMethodTab.propTypes = {
PaymentMethodCard.propTypes = {
showSaveOption: PropTypes.bool,
children: PropTypes.node,
};

export default PaymentMethodTab;
export default PaymentMethodCard;
95 changes: 49 additions & 46 deletions assets/js/base/components/payment-methods/payment-method-options.js
Expand Up @@ -8,17 +8,17 @@ import {
useEmitResponse,
} from '@woocommerce/base-hooks';
import { cloneElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import {
useEditorContext,
usePaymentMethodDataContext,
} from '@woocommerce/base-context';
import classNames from 'classnames';

/**
* Internal dependencies
*/
import Tabs from '../tabs';
import PaymentMethodTab from './payment-method-tab';
import PaymentMethodCard from './payment-method-card';
import RadioControlAccordion from '../radio-control-accordion';

/**
* Component used to render all non-saved payment method options.
Expand All @@ -28,7 +28,10 @@ import PaymentMethodTab from './payment-method-tab';
const PaymentMethodOptions = () => {
const {
setActivePaymentMethod,
activeSavedToken,
setActiveSavedToken,
expressPaymentMethods,
customerPaymentMethods,
} = usePaymentMethodDataContext();
const { paymentMethods } = usePaymentMethods();
const {
Expand All @@ -42,50 +45,50 @@ const PaymentMethodOptions = () => {
const { removeNotice } = useStoreNotices();
const { isEditor } = useEditorContext();

const options = Object.keys( paymentMethods ).map( ( name ) => {
const { edit, content, label, supports } = paymentMethods[ name ];
const component = isEditor ? edit : content;
return {
value: name,
label:
typeof label === 'string'
? label
: cloneElement( label, {
components: paymentMethodInterface.components,
} ),
name: `wc-saved-payment-method-token-${ name }`,
content: (
<PaymentMethodCard allowsSaving={ supports.savePaymentInfo }>
{ cloneElement( component, {
activePaymentMethod,
...paymentMethodInterface,
} ) }
</PaymentMethodCard>
),
};
} );

const updateToken = ( value ) => {
setActivePaymentMethod( value );
setActiveSavedToken( '' );
removeNotice( 'wc-payment-error', noticeContexts.PAYMENTS );
};

const isSinglePaymentMethod =
Object.keys( customerPaymentMethods ).length === 0 &&
Object.keys( paymentMethods ).length === 1;

const singleOptionClass = classNames( {
'disable-radio-control': isSinglePaymentMethod,
} );

return expressPaymentMethodActive ? null : (
<Tabs
className="wc-block-components-checkout-payment-methods"
onSelect={ ( tabName ) => {
setActivePaymentMethod( tabName );
removeNotice( 'wc-payment-error', noticeContexts.PAYMENTS );
} }
tabs={ Object.keys( paymentMethods ).map( ( name ) => {
const {
ariaLabel,
edit,
content,
label,
supports,
} = paymentMethods[ name ];
const component = isEditor ? edit : content;
return {
name,
title:
typeof label === 'string'
? label
: cloneElement( label, {
components:
paymentMethodInterface.components,
} ),
ariaLabel,
content: (
<PaymentMethodTab
showSaveOption={ supports.showSaveOption }
>
{ cloneElement( component, {
activePaymentMethod,
...paymentMethodInterface,
} ) }
</PaymentMethodTab>
),
};
} ) }
initialTabName={ activePaymentMethod }
ariaLabel={ __(
'Payment Methods',
'woo-gutenberg-products-block'
) }
id="wc-block-payment-methods"
<RadioControlAccordion
id={ 'wc-payment-method-options' }
className={ singleOptionClass }
selected={ activeSavedToken ? null : activePaymentMethod }
onChange={ updateToken }
options={ options }
/>
);
};
Expand Down
36 changes: 24 additions & 12 deletions assets/js/base/components/payment-methods/payment-methods.js
Expand Up @@ -2,7 +2,9 @@
* External dependencies
*/
import { usePaymentMethods } from '@woocommerce/base-hooks';
import { useCallback, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import Label from '@woocommerce/base-components/label';
import { usePaymentMethodDataContext } from '@woocommerce/base-context';

/**
* Internal dependencies
Expand All @@ -18,24 +20,34 @@ import SavedPaymentMethodOptions from './saved-payment-method-options';
*/
const PaymentMethods = () => {
const { isInitialized, paymentMethods } = usePaymentMethods();
const [ showNewPaymentMethods, setShowNewPaymentMethods ] = useState(
true
);
const onChange = useCallback(
( token ) => {
setShowNewPaymentMethods( token === '0' );
},
[ setShowNewPaymentMethods ]
);
const { customerPaymentMethods } = usePaymentMethodDataContext();

if ( isInitialized && Object.keys( paymentMethods ).length === 0 ) {
return <NoPaymentMethods />;
}

return (
<>
<SavedPaymentMethodOptions onChange={ onChange } />
{ showNewPaymentMethods && <PaymentMethodOptions /> }
<SavedPaymentMethodOptions />
{ Object.keys( customerPaymentMethods ).length > 0 && (
<Label
label={ __(
'Use another payment method.',
'woo-gutenberg-products-block'
) }
screenReaderLabel={ __(
'Other available payment methods',
'woo-gutenberg-products-block'
) }
wrapperElement="p"
wrapperProps={ {
className: [
'wc-block-components-checkout-step__description wc-block-components-checkout-step__description-payments-aligned',
],
} }
/>
) }
<PaymentMethodOptions />
</>
);
};
Expand Down
@@ -1,15 +1,11 @@
/**
* External dependencies
*/
import { useEffect, useState, useRef, useCallback } from '@wordpress/element';
import { useEffect, useRef, useCallback } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import {
useEditorContext,
usePaymentMethodDataContext,
} from '@woocommerce/base-context';
import { usePaymentMethodDataContext } from '@woocommerce/base-context';
import RadioControl from '@woocommerce/base-components/radio-control';
import { getPaymentMethods } from '@woocommerce/blocks-registry';
import PropTypes from 'prop-types';

/**
* @typedef {import('@woocommerce/type-defs/contexts').CustomerPaymentMethod} CustomerPaymentMethod
Expand Down Expand Up @@ -88,14 +84,15 @@ const getDefaultPaymentMethodOptions = (
};
};

const SavedPaymentMethodOptions = ( { onChange } ) => {
const { isEditor } = useEditorContext();
const SavedPaymentMethodOptions = () => {
const {
setPaymentStatus,
customerPaymentMethods,
activePaymentMethod,
setActivePaymentMethod,
activeSavedToken,
setActiveSavedToken,
} = usePaymentMethodDataContext();
const [ selectedToken, setSelectedToken ] = useState( '' );
const standardMethods = getPaymentMethods();

/**
Expand All @@ -109,10 +106,9 @@ const SavedPaymentMethodOptions = ( { onChange } ) => {
if ( token === '0' ) {
setPaymentStatus().started();
}
setSelectedToken( token );
onChange( token );
setActiveSavedToken( token );
},
[ onChange, setSelectedToken, setPaymentStatus ]
[ setActiveSavedToken, setPaymentStatus ]
);

useEffect( () => {
Expand All @@ -133,7 +129,11 @@ const SavedPaymentMethodOptions = ( { onChange } ) => {
setActivePaymentMethod,
setPaymentStatus
);
if ( paymentMethod.is_default && selectedToken === '' ) {
if (
! activePaymentMethod &&
paymentMethod.is_default &&
activeSavedToken === ''
) {
updateToken( paymentMethod.tokenId + '' );
option.onChange( paymentMethod.tokenId );
}
Expand All @@ -145,31 +145,21 @@ const SavedPaymentMethodOptions = ( { onChange } ) => {
}, [
customerPaymentMethods,
updateToken,
selectedToken,
activeSavedToken,
activePaymentMethod,
setActivePaymentMethod,
setPaymentStatus,
standardMethods,
] );

// In the editor, show `Use a new payment method` option as selected.
const selectedOption = isEditor ? '0' : selectedToken + '';
const newPaymentMethodOption = {
value: '0',
label: __( 'Use a new payment method', 'woo-gutenberg-product-blocks' ),
name: `wc-saved-payment-method-token-new`,
};
return currentOptions.current.length > 0 ? (
<RadioControl
id={ 'wc-payment-method-saved-tokens' }
selected={ selectedOption }
selected={ activeSavedToken }
onChange={ updateToken }
options={ [ ...currentOptions.current, newPaymentMethodOption ] }
options={ currentOptions.current }
/>
) : null;
};

SavedPaymentMethodOptions.propTypes = {
onChange: PropTypes.func.isRequired,
};

export default SavedPaymentMethodOptions;
64 changes: 64 additions & 0 deletions assets/js/base/components/payment-methods/style.scss
Expand Up @@ -183,3 +183,67 @@
margin-left: $gap-smaller;
}
}

.wc-block-components-radio-control__option-checked.wc-block-components-radio-control__option-checked {
font-weight: bold;
}

.wc-block-checkout__payment-method {
.wc-block-components-radio-control__option {
padding-left: 44px;
&::after {
content: none;
}

.wc-block-components-radio-control__input {
left: 16px;
}
}

.wc-block-components-radio-control__option:last-child,
.wc-block-components-radio-control-accordion-option:last-child {
border-width: 1px;
}

.wc-block-components-radio-control-accordion-option,
.wc-block-components-radio-control__option {
border-width: 1px 1px 0 1px;
border-style: solid;
border-color: $gray-200;
}

.wc-block-components-radio-control-accordion-option {
.wc-block-components-radio-control__option {
border-width: 0;
}
.wc-block-components-radio-control__label img {
height: 24px;
}
}

.wc-block-components-radio-control.disable-radio-control {
.wc-block-components-radio-control__option {
padding-left: 16px;
}

.wc-block-components-radio-control__input {
display: none;
}
}

.wc-block-components-checkout-step__description-payments-aligned {
padding-top: 14px;
height: 28px;
}

}

.wc-block-components-radio-control-accordion-content {
padding: 8px 16px 16px 16px;
}

.wc-block-checkout__order-notes {
.wc-block-components-checkout-step__content {
padding-bottom: 0;
}
}