Option to 'use shipping address for billing': add attribute and make it work in the frontend (https://github.com/woocommerce/woocommerce-blocks/pull/1857)
* Create useShippingAsBilling attribute * Fix missing prop * Refactor FormStep so stepNumber is generated by CSS instead of being passed as a prop * Add billing address form * Add text before controls * Remove old @todo comment
This commit is contained in:
parent
e2f769eedf
commit
2544ffd7d1
|
@ -4,13 +4,31 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
import PropTypes from 'prop-types';
|
||||
import TextInput from '@woocommerce/base-components/text-input';
|
||||
import { ShippingCountryInput } from '@woocommerce/base-components/country-input';
|
||||
import { ShippingStateInput } from '@woocommerce/base-components/state-input';
|
||||
import {
|
||||
BillingCountryInput,
|
||||
ShippingCountryInput,
|
||||
} from '@woocommerce/base-components/country-input';
|
||||
import {
|
||||
BillingStateInput,
|
||||
ShippingStateInput,
|
||||
} from '@woocommerce/base-components/state-input';
|
||||
import {
|
||||
COUNTRY_LOCALE,
|
||||
DEFAULT_ADDRESS_FIELDS,
|
||||
} from '@woocommerce/block-settings';
|
||||
|
||||
const defaultFieldNames = [
|
||||
'first_name',
|
||||
'last_name',
|
||||
'company',
|
||||
'address_1',
|
||||
'address_2',
|
||||
'country',
|
||||
'city',
|
||||
'postcode',
|
||||
'state',
|
||||
];
|
||||
|
||||
const defaultFieldValues = {
|
||||
first_name: {
|
||||
autocomplete: 'given-name',
|
||||
|
@ -43,18 +61,9 @@ const defaultFieldValues = {
|
|||
};
|
||||
|
||||
const AddressForm = ( {
|
||||
fields = [
|
||||
'first_name',
|
||||
'last_name',
|
||||
'company',
|
||||
'address_1',
|
||||
'address_2',
|
||||
'country',
|
||||
'city',
|
||||
'postcode',
|
||||
'state',
|
||||
],
|
||||
fields = defaultFieldNames,
|
||||
onChange,
|
||||
type = 'shipping',
|
||||
values,
|
||||
} ) => {
|
||||
const countryLocale = COUNTRY_LOCALE[ values.country ] || {};
|
||||
|
@ -75,8 +84,12 @@ const AddressForm = ( {
|
|||
return null;
|
||||
}
|
||||
if ( addressField.key === 'country' ) {
|
||||
const Tag =
|
||||
type === 'shipping'
|
||||
? ShippingCountryInput
|
||||
: BillingCountryInput;
|
||||
return (
|
||||
<ShippingCountryInput
|
||||
<Tag
|
||||
key={ addressField.key }
|
||||
label={ __(
|
||||
'Country / Region',
|
||||
|
@ -96,8 +109,12 @@ const AddressForm = ( {
|
|||
);
|
||||
}
|
||||
if ( addressField.key === 'state' ) {
|
||||
const Tag =
|
||||
type === 'shipping'
|
||||
? ShippingStateInput
|
||||
: BillingStateInput;
|
||||
return (
|
||||
<ShippingStateInput
|
||||
<Tag
|
||||
key={ addressField.key }
|
||||
country={ values.country }
|
||||
label={ addressField.label }
|
||||
|
@ -139,7 +156,8 @@ const AddressForm = ( {
|
|||
AddressForm.propTypes = {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
values: PropTypes.object.isRequired,
|
||||
fields: PropTypes.arrayOf( PropTypes.string ),
|
||||
fields: PropTypes.arrayOf( PropTypes.oneOf( defaultFieldNames ) ),
|
||||
type: PropTypes.oneOf( [ 'billing', 'shipping' ] ),
|
||||
};
|
||||
|
||||
export default AddressForm;
|
||||
|
|
|
@ -3,32 +3,12 @@
|
|||
*/
|
||||
import classnames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Label from '../../label';
|
||||
import './style.scss';
|
||||
|
||||
const StepNumber = ( { stepNumber } ) => {
|
||||
return (
|
||||
<div className="wc-block-checkout-step__number">
|
||||
<Label
|
||||
label={ stepNumber }
|
||||
screenReaderLabel={ sprintf(
|
||||
__(
|
||||
// translators: %s is a step number (1, 2, 3...)
|
||||
'Step %d',
|
||||
'woo-gutenberg-products-block'
|
||||
),
|
||||
stepNumber
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const StepHeading = ( { title, stepHeadingContent } ) => (
|
||||
<div className="wc-block-checkout-step__heading">
|
||||
<h4 aria-hidden="true" className="wc-block-checkout-step__title">
|
||||
|
@ -43,7 +23,6 @@ const StepHeading = ( { title, stepHeadingContent } ) => (
|
|||
const FormStep = ( {
|
||||
id,
|
||||
className,
|
||||
stepNumber,
|
||||
title,
|
||||
legend,
|
||||
description,
|
||||
|
@ -56,7 +35,6 @@ const FormStep = ( {
|
|||
id={ id }
|
||||
>
|
||||
<legend className="screen-reader-text">{ legend || title }</legend>
|
||||
<StepNumber stepNumber={ stepNumber } />
|
||||
<StepHeading
|
||||
title={ title }
|
||||
stepHeadingContent={ stepHeadingContent() }
|
||||
|
@ -72,11 +50,11 @@ const FormStep = ( {
|
|||
FormStep.propTypes = {
|
||||
id: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
stepNumber: PropTypes.number,
|
||||
title: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
stepHeadingContent: PropTypes.func,
|
||||
legend: PropTypes.string,
|
||||
};
|
||||
|
||||
export default FormStep;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
$circle-size: 24px;
|
||||
$line-offset-from-circle-size: 8px;
|
||||
|
||||
.wc-block-checkout-form {
|
||||
counter-reset: checkout-step;
|
||||
}
|
||||
|
||||
.wc-block-checkout-form fieldset.wc-block-checkout-step {
|
||||
position: relative;
|
||||
border: none;
|
||||
|
@ -50,7 +54,22 @@ $line-offset-from-circle-size: 8px;
|
|||
margin-bottom: $gap-large;
|
||||
}
|
||||
|
||||
.wc-block-checkout-step__number {
|
||||
// because themes can register different background colors, we can't always
|
||||
// relay on using white border to offest the step left line,
|
||||
.wc-block-checkout-step::before {
|
||||
content: "";
|
||||
// 1 Circle size + offset of the first circle and next circle.
|
||||
height: calc(100% - #{$circle-size + $line-offset-from-circle-size * 2});
|
||||
width: 1px;
|
||||
background-color: $gray-10;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: $circle-size + $line-offset-from-circle-size;
|
||||
}
|
||||
|
||||
.wc-block-checkout-step::after {
|
||||
counter-increment: checkout-step;
|
||||
content: counter(checkout-step);
|
||||
position: absolute;
|
||||
width: $circle-size;
|
||||
height: $circle-size;
|
||||
|
@ -64,16 +83,3 @@ $line-offset-from-circle-size: 8px;
|
|||
border-radius: $circle-size / 2;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
// because themes can register different background colors, we can't always
|
||||
// relay on using white border to offest the step left line,
|
||||
.wc-block-checkout-step::before {
|
||||
content: "";
|
||||
// 1 Circle size + offset of the first circle and next circle.
|
||||
height: calc(100% - #{$circle-size + $line-offset-from-circle-size * 2});
|
||||
width: 1px;
|
||||
background-color: $gray-10;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: $circle-size + $line-offset-from-circle-size;
|
||||
}
|
||||
|
|
|
@ -28,11 +28,15 @@ import { decodeEntities } from '@wordpress/html-entities';
|
|||
import './style.scss';
|
||||
import '../../../payment-methods-demo';
|
||||
|
||||
const Block = ( { shippingRates = [], isEditor = false } ) => {
|
||||
const Block = ( { attributes, isEditor = false, shippingRates = [] } ) => {
|
||||
const [ selectedShippingRate, setSelectedShippingRate ] = useState( {} );
|
||||
const [ contactFields, setContactFields ] = useState( {} );
|
||||
const [ shouldSavePayment, setShouldSavePayment ] = useState( true );
|
||||
const [ shippingFields, setShippingFields ] = useState( {} );
|
||||
const [ billingFields, setBillingFields ] = useState( {} );
|
||||
const [ useShippingAsBilling, setUseShippingAsBilling ] = useState(
|
||||
attributes.useShippingAsBilling
|
||||
);
|
||||
|
||||
const renderShippingRatesControlOption = ( option ) => ( {
|
||||
label: decodeEntities( option.name ),
|
||||
|
@ -47,13 +51,19 @@ const Block = ( { shippingRates = [], isEditor = false } ) => {
|
|||
secondaryDescription: decodeEntities( option.delivery_time ),
|
||||
} );
|
||||
|
||||
const useShippingAddressAsBilling = isEditor
|
||||
? attributes.useShippingAsBilling
|
||||
: useShippingAsBilling;
|
||||
const showBillingFields =
|
||||
! SHIPPING_ENABLED || ! useShippingAddressAsBilling;
|
||||
|
||||
return (
|
||||
<CheckoutProvider>
|
||||
<ExpressCheckoutFormControl />
|
||||
<CheckoutForm>
|
||||
<FormStep
|
||||
id="billing-fields"
|
||||
className="wc-block-checkout__billing-fields"
|
||||
id="contact-fields"
|
||||
className="wc-block-checkout__contact-fields"
|
||||
title={ __(
|
||||
'Contact information',
|
||||
'woo-gutenberg-products-block'
|
||||
|
@ -62,7 +72,6 @@ const Block = ( { shippingRates = [], isEditor = false } ) => {
|
|||
"We'll use this email to send you details and updates about your order.",
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
stepNumber={ 1 }
|
||||
stepHeadingContent={ () => (
|
||||
<Fragment>
|
||||
{ __(
|
||||
|
@ -121,7 +130,6 @@ const Block = ( { shippingRates = [], isEditor = false } ) => {
|
|||
'Enter the physical address where you want us to deliver your order.',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
stepNumber={ 2 }
|
||||
>
|
||||
<AddressForm
|
||||
onChange={ setShippingFields }
|
||||
|
@ -149,13 +157,46 @@ const Block = ( { shippingRates = [], isEditor = false } ) => {
|
|||
'Use same address for billing',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
checked={ shippingFields.useSameForBilling }
|
||||
onChange={ () =>
|
||||
setShippingFields( {
|
||||
...shippingFields,
|
||||
useSameForBilling: ! shippingFields.useSameForBilling,
|
||||
checked={ useShippingAddressAsBilling }
|
||||
onChange={ ( isChecked ) =>
|
||||
setUseShippingAsBilling( isChecked )
|
||||
}
|
||||
/>
|
||||
</FormStep>
|
||||
) }
|
||||
{ showBillingFields && (
|
||||
<FormStep
|
||||
id="billing-fields"
|
||||
className="wc-block-checkout__billing-fields"
|
||||
title={ __(
|
||||
'Billing address',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
description={ __(
|
||||
'Enter the address that matches your card or payment method.',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
>
|
||||
<AddressForm
|
||||
onChange={ setBillingFields }
|
||||
type="billing"
|
||||
values={ billingFields }
|
||||
/>
|
||||
<TextInput
|
||||
type="tel"
|
||||
label={ __(
|
||||
'Phone',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
value={ billingFields.phone }
|
||||
autoComplete="tel"
|
||||
onChange={ ( newValue ) =>
|
||||
setBillingFields( {
|
||||
...billingFields,
|
||||
phone: newValue,
|
||||
} )
|
||||
}
|
||||
required={ true }
|
||||
/>
|
||||
</FormStep>
|
||||
) }
|
||||
|
@ -174,7 +215,6 @@ const Block = ( { shippingRates = [], isEditor = false } ) => {
|
|||
'Select your shipping method below.',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
stepNumber={ 3 }
|
||||
>
|
||||
{ shippingRates.length > 0 ? (
|
||||
<Packages
|
||||
|
@ -249,7 +289,6 @@ const Block = ( { shippingRates = [], isEditor = false } ) => {
|
|||
'Select a payment method below.',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
stepNumber={ 4 }
|
||||
>
|
||||
<PaymentMethods />
|
||||
{ /*@todo this should be something the payment method controls*/ }
|
||||
|
|
|
@ -5,6 +5,8 @@ import { __ } from '@wordpress/i18n';
|
|||
import { withFeedbackPrompt } from '@woocommerce/block-hocs';
|
||||
import { previewShippingRates } from '@woocommerce/resource-previews';
|
||||
import { SHIPPING_METHODS_EXIST } from '@woocommerce/block-settings';
|
||||
import { InspectorControls } from '@wordpress/block-editor';
|
||||
import { PanelBody, ToggleControl } from '@wordpress/components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -12,11 +14,38 @@ import { SHIPPING_METHODS_EXIST } from '@woocommerce/block-settings';
|
|||
import Block from './block.js';
|
||||
import './editor.scss';
|
||||
|
||||
const CheckoutEditor = ( { attributes } ) => {
|
||||
const { className } = attributes;
|
||||
const CheckoutEditor = ( { attributes, setAttributes } ) => {
|
||||
const { className, useShippingAsBilling } = attributes;
|
||||
// @todo: wrap Block with Disabled once you finish building the form
|
||||
return (
|
||||
<div className={ className }>
|
||||
<InspectorControls>
|
||||
<PanelBody
|
||||
title={ __(
|
||||
'Billing address',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
>
|
||||
<p className="wc-block-checkout__controls-text">
|
||||
{ __(
|
||||
'Reduce the number of fields required to checkout.',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
</p>
|
||||
<ToggleControl
|
||||
label={ __(
|
||||
'Use the shipping address as the billing address',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
checked={ useShippingAsBilling }
|
||||
onChange={ () =>
|
||||
setAttributes( {
|
||||
useShippingAsBilling: ! useShippingAsBilling,
|
||||
} )
|
||||
}
|
||||
/>
|
||||
</PanelBody>
|
||||
</InspectorControls>
|
||||
<Block
|
||||
attributes={ attributes }
|
||||
isEditor={ true }
|
||||
|
|
|
@ -3,3 +3,8 @@
|
|||
line-height: 24px;
|
||||
margin: 0 $gap-small 0 0;
|
||||
}
|
||||
|
||||
.wc-block-checkout__controls-text {
|
||||
color: #999;
|
||||
font-style: italic;
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@ import { withRestApiHydration } from '@woocommerce/block-hocs';
|
|||
import Block from './block.js';
|
||||
import renderFrontend from '../../../utils/render-frontend.js';
|
||||
|
||||
const getProps = () => {
|
||||
const getProps = ( el ) => {
|
||||
return {
|
||||
attributes: {
|
||||
isEditor: false,
|
||||
useShippingAsBilling: el.dataset.useShippingAsBilling !== 'false',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -38,15 +38,22 @@ const settings = {
|
|||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
useShippingAsBilling: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
edit,
|
||||
/**
|
||||
* Save the props to post content.
|
||||
*/
|
||||
save( { attributes } ) {
|
||||
const { className } = attributes;
|
||||
const { className, useShippingAsBilling } = attributes;
|
||||
const data = {
|
||||
'data-use-shipping-as-billing': useShippingAsBilling,
|
||||
};
|
||||
return (
|
||||
<div className={ className }>
|
||||
<div className={ className } { ...data }>
|
||||
Checkout block coming soon to store near you
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
}
|
||||
|
||||
@include breakpoint( ">480px" ) {
|
||||
.wc-block-checkout__billing-fields,
|
||||
.wc-block-checkout__shipping-fields {
|
||||
.wc-block-address-form {
|
||||
display: grid;
|
||||
|
|
|
@ -12,7 +12,7 @@ import BlockErrorBoundary from '@woocommerce/base-components/block-error-boundar
|
|||
* @param {Function} [getProps] Function to generate the props object for the
|
||||
* block.
|
||||
*/
|
||||
export default ( selector, Block, getProps = () => {} ) => {
|
||||
export default ( selector, Block, getProps = () => ( {} ) ) => {
|
||||
const containers = document.querySelectorAll( selector );
|
||||
|
||||
if ( containers.length ) {
|
||||
|
|
Loading…
Reference in New Issue