Checkout form options to control field visibility (https://github.com/woocommerce/woocommerce-blocks/pull/1868)

* Fix background overlap of feedback box

* TS notices

* Add company name toggle

* Implement new attributes and toggles in editor

* Handle field config in address component

* Remove other hoc rule from tsconfig

* map -> forEach

* Remove return from forEach

* Export and extend field config

* Fix optional text for all field types

* unit text

* Update snapshot
This commit is contained in:
Mike Jolley 2020-03-05 13:06:47 +00:00 committed by GitHub
parent 401f50a607
commit dd54ce1136
11 changed files with 242 additions and 87 deletions

View File

@ -17,19 +17,7 @@ import {
DEFAULT_ADDRESS_FIELDS,
} from '@woocommerce/block-settings';
const defaultFieldNames = [
'first_name',
'last_name',
'company',
'address_1',
'address_2',
'country',
'city',
'postcode',
'state',
];
const defaultFieldValues = {
export const defaultFieldConfig = {
first_name: {
autocomplete: 'given-name',
},
@ -48,6 +36,7 @@ const defaultFieldValues = {
country: {
autocomplete: 'country',
priority: 65,
required: true,
},
city: {
autocomplete: 'address-level2',
@ -61,7 +50,8 @@ const defaultFieldValues = {
};
const AddressForm = ( {
fields = defaultFieldNames,
fields = Object.keys( defaultFieldConfig ),
fieldConfig = defaultFieldConfig,
onChange,
type = 'shipping',
values,
@ -71,18 +61,31 @@ const AddressForm = ( {
key: field,
...DEFAULT_ADDRESS_FIELDS[ field ],
...countryLocale[ field ],
...defaultFieldValues[ field ],
...fieldConfig[ field ],
} ) );
const sortedAddressFields = addressFields.sort(
( a, b ) => a.priority - b.priority
);
const optionalText = __( '(optional)', 'woo-gutenberg-products-block' );
return (
<div className="wc-block-address-form">
{ sortedAddressFields.map( ( addressField ) => {
if ( addressField.hidden ) {
return null;
}
const requiredField = addressField.required;
let fieldLabel = addressField.label || addressField.placeholder;
if (
! addressField.required &&
! fieldLabel.includes( optionalText )
) {
fieldLabel = fieldLabel + ' ' + optionalText;
}
if ( addressField.key === 'country' ) {
const Tag =
type === 'shipping'
@ -91,10 +94,7 @@ const AddressForm = ( {
return (
<Tag
key={ addressField.key }
label={ __(
'Country / Region',
'woo-gutenberg-products-block'
) }
label={ fieldLabel }
value={ values.country }
autoComplete={ addressField.autocomplete }
onChange={ ( newValue ) =>
@ -104,10 +104,11 @@ const AddressForm = ( {
state: '',
} )
}
required={ true }
required={ requiredField }
/>
);
}
if ( addressField.key === 'state' ) {
const Tag =
type === 'shipping'
@ -117,7 +118,7 @@ const AddressForm = ( {
<Tag
key={ addressField.key }
country={ values.country }
label={ addressField.label }
label={ fieldLabel }
value={ values.state }
autoComplete={ addressField.autocomplete }
onChange={ ( newValue ) =>
@ -126,17 +127,16 @@ const AddressForm = ( {
state: newValue,
} )
}
required={
! values.country || addressField.required
}
required={ requiredField }
/>
);
}
return (
<TextInput
key={ addressField.key }
className={ `wc-block-address-form__${ addressField.key }` }
label={ addressField.label || addressField.placeholder }
label={ fieldLabel }
value={ values[ addressField.key ] }
autoComplete={ addressField.autocomplete }
onChange={ ( newValue ) =>
@ -145,7 +145,7 @@ const AddressForm = ( {
[ addressField.key ]: newValue,
} )
}
required={ addressField.required }
required={ requiredField }
/>
);
} ) }
@ -156,7 +156,10 @@ const AddressForm = ( {
AddressForm.propTypes = {
onChange: PropTypes.func.isRequired,
values: PropTypes.object.isRequired,
fields: PropTypes.arrayOf( PropTypes.oneOf( defaultFieldNames ) ),
fields: PropTypes.arrayOf(
PropTypes.oneOf( Object.keys( defaultFieldConfig ) )
),
fieldConfig: PropTypes.object,
type: PropTypes.oneOf( [ 'billing', 'shipping' ] ),
};

View File

@ -27,7 +27,7 @@ const FormStep = ( {
legend,
description,
children,
stepHeadingContent = () => null,
stepHeadingContent = () => {},
} ) => {
return (
<fieldset

View File

@ -0,0 +1,33 @@
const blockAttributes = {
isPreview: {
type: 'boolean',
default: false,
save: false,
},
useShippingAsBilling: {
type: 'boolean',
default: true,
},
showCompanyField: {
type: 'boolean',
default: false,
},
requireCompanyField: {
type: 'boolean',
default: false,
},
showAddress2Field: {
type: 'boolean',
default: true,
},
showPhoneField: {
type: 'boolean',
default: true,
},
requirePhoneField: {
type: 'boolean',
default: false,
},
};
export default blockAttributes;

View File

@ -3,7 +3,9 @@
*/
import { Fragment, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import AddressForm from '@woocommerce/base-components/address-form';
import AddressForm, {
defaultFieldConfig,
} from '@woocommerce/base-components/address-form';
import FormStep from '@woocommerce/base-components/checkout/form-step';
import CheckoutForm from '@woocommerce/base-components/checkout/form';
import NoShipping from '@woocommerce/base-components/checkout/no-shipping';
@ -57,6 +59,19 @@ const Block = ( { attributes, isEditor = false, shippingRates = [] } ) => {
const showBillingFields =
! SHIPPING_ENABLED || ! useShippingAddressAsBilling;
const addressFields = {
...defaultFieldConfig,
company: {
...defaultFieldConfig.company,
hidden: ! attributes.showCompanyField,
required: attributes.requireCompanyField,
},
address_2: {
...defaultFieldConfig.address_2,
hidden: ! attributes.showAddress2Field,
},
};
return (
<CheckoutProvider>
<ExpressCheckoutFormControl />
@ -134,23 +149,34 @@ const Block = ( { attributes, isEditor = false, shippingRates = [] } ) => {
<AddressForm
onChange={ setShippingFields }
values={ shippingFields }
fields={ Object.keys( addressFields ) }
fieldConfig={ addressFields }
/>
<TextInput
type="tel"
label={ __(
'Phone',
'woo-gutenberg-products-block'
) }
value={ shippingFields.phone }
autoComplete="tel"
onChange={ ( newValue ) =>
setShippingFields( {
...shippingFields,
phone: newValue,
} )
}
required={ true }
/>
{ attributes.showPhoneField && (
<TextInput
type="tel"
label={
attributes.requirePhoneField
? __(
'Phone',
'woo-gutenberg-products-block'
)
: __(
'Phone (optional)',
'woo-gutenberg-products-block'
)
}
value={ shippingFields.phone }
autoComplete="tel"
onChange={ ( newValue ) =>
setShippingFields( {
...shippingFields,
phone: newValue,
} )
}
required={ attributes.requirePhoneField }
/>
) }
<CheckboxControl
className="wc-block-checkout__use-address-for-billing"
label={ __(
@ -181,22 +207,8 @@ const Block = ( { attributes, isEditor = false, shippingRates = [] } ) => {
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 }
fields={ Object.keys( addressFields ) }
fieldConfig={ addressFields }
/>
</FormStep>
) }

View File

@ -6,7 +6,11 @@ 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';
import {
PanelBody,
ToggleControl,
CheckboxControl,
} from '@wordpress/components';
/**
* Internal dependencies
@ -15,11 +19,98 @@ import Block from './block.js';
import './editor.scss';
const CheckoutEditor = ( { attributes, setAttributes } ) => {
const { className, useShippingAsBilling } = attributes;
const {
className,
useShippingAsBilling,
showCompanyField,
showAddress2Field,
showPhoneField,
requireCompanyField,
requirePhoneField,
} = attributes;
// @todo: wrap Block with Disabled once you finish building the form
return (
<div className={ className }>
<InspectorControls>
<PanelBody
title={ __(
'Form options',
'woo-gutenberg-products-block'
) }
>
<p className="wc-block-checkout__controls-text">
{ __(
'Choose whether your checkout form requires extra information from customers.',
'woo-gutenberg-products-block'
) }
</p>
<ToggleControl
label={ __(
'Company name',
'woo-gutenberg-products-block'
) }
checked={ showCompanyField }
onChange={ () =>
setAttributes( {
showCompanyField: ! showCompanyField,
} )
}
/>
{ showCompanyField && (
<CheckboxControl
label={ __(
'Require company name?',
'woo-gutenberg-products-block'
) }
checked={ requireCompanyField }
onChange={ () =>
setAttributes( {
requireCompanyField: ! requireCompanyField,
} )
}
className="components-base-control--nested"
/>
) }
<ToggleControl
label={ __(
'Apartment, suite, unit etc',
'woo-gutenberg-products-block'
) }
checked={ showAddress2Field }
onChange={ () =>
setAttributes( {
showAddress2Field: ! showAddress2Field,
} )
}
/>
<ToggleControl
label={ __(
'Phone number',
'woo-gutenberg-products-block'
) }
checked={ showPhoneField }
onChange={ () =>
setAttributes( {
showPhoneField: ! showPhoneField,
} )
}
/>
{ showPhoneField && (
<CheckboxControl
label={ __(
'Require phone number?',
'woo-gutenberg-products-block'
) }
checked={ requirePhoneField }
onChange={ () =>
setAttributes( {
requirePhoneField: ! requirePhoneField,
} )
}
className="components-base-control--nested"
/>
) }
</PanelBody>
<PanelBody
title={ __(
'Billing address',

View File

@ -8,3 +8,8 @@
color: #999;
font-style: italic;
}
.components-base-control--nested {
padding-left: 52px;
margin-top: -12px;
}

View File

@ -7,13 +7,27 @@ import { withRestApiHydration } from '@woocommerce/block-hocs';
* Internal dependencies
*/
import Block from './block.js';
import blockAttributes from './attributes';
import renderFrontend from '../../../utils/render-frontend.js';
const getProps = ( el ) => {
const attributes = {};
Object.keys( blockAttributes ).forEach( ( key ) => {
if ( typeof el.dataset[ key ] !== 'undefined' ) {
if (
el.dataset[ key ] === 'true' ||
el.dataset[ key ] === 'false'
) {
attributes[ key ] = el.dataset[ key ] !== 'false';
} else {
attributes[ key ] = el.dataset[ key ];
}
}
} );
return {
attributes: {
useShippingAsBilling: el.dataset.useShippingAsBilling !== 'false',
},
attributes,
};
};

View File

@ -4,11 +4,13 @@
import { __ } from '@wordpress/i18n';
import { registerBlockType } from '@wordpress/blocks';
import { Icon, card } from '@woocommerce/icons';
import { kebabCase } from 'lodash';
/**
* Internal dependencies
*/
import edit from './edit';
import blockAttributes from './attributes';
import { example } from './example';
import './editor.scss';
@ -30,30 +32,25 @@ const settings = {
multiple: false,
},
example,
attributes: {
/**
* Are we previewing?
*/
isPreview: {
type: 'boolean',
default: false,
},
useShippingAsBilling: {
type: 'boolean',
default: true,
},
},
attributes: blockAttributes,
edit,
/**
* Save the props to post content.
*/
save( { attributes } ) {
const { className, useShippingAsBilling } = attributes;
const data = {
'data-use-shipping-as-billing': useShippingAsBilling,
};
const data = {};
Object.keys( blockAttributes ).forEach( ( key ) => {
if (
blockAttributes[ key ].save !== false &&
typeof attributes[ key ] !== 'undefined'
) {
data[ 'data-' + kebabCase( key ) ] = attributes[ key ];
}
} );
return (
<div className={ className } { ...data }>
<div className={ attributes.className } { ...data }>
Checkout block coming soon to store near you
</div>
);

View File

@ -1,7 +1,7 @@
.wc-block-feedback-prompt {
background-color: #f7f7f7;
border-top: 1px solid #e2e4e7;
margin: $gap -16px -16px;
margin: 0 -16px 0;
padding: $gap-large;
text-align: center;

View File

@ -2,6 +2,6 @@
exports[`Checkout Block can be created 1`] = `
"<!-- wp:woocommerce/checkout -->
<div class=\\"wp-block-woocommerce-checkout\\" data-use-shipping-as-billing=\\"true\\">Checkout block coming soon to store near you</div>
<div class=\\"wp-block-woocommerce-checkout\\" data-use-shipping-as-billing=\\"true\\" data-show-company-field=\\"false\\" data-require-company-field=\\"false\\" data-show-address-2-field=\\"true\\" data-show-phone-field=\\"true\\" data-require-phone-field=\\"false\\">Checkout block coming soon to store near you</div>
<!-- /wp:woocommerce/checkout -->"
`;

View File

@ -26,7 +26,7 @@
"@woocommerce/base-utils": [ "assets/js/base/utils" ],
"@woocommerce/block-components/*": [ "assets/js/components/*" ],
"@woocommerce/block-data": [ "assets/js/data" ],
"@woocommerce/block-hocs/*": [ "assets/js/hocs/*" ],
"@woocommerce/block-hocs": [ "assets/js/hocs" ],
"@woocommerce/blocks-registry/*": [ "assets/js/blocks-registry/*" ],
"@woocommerce/block-settings": [ "assets/js/settings/blocks" ],
"@woocommerce/e2e-tests": [