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:
parent
401f50a607
commit
dd54ce1136
|
@ -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' ] ),
|
||||
};
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ const FormStep = ( {
|
|||
legend,
|
||||
description,
|
||||
children,
|
||||
stepHeadingContent = () => null,
|
||||
stepHeadingContent = () => {},
|
||||
} ) => {
|
||||
return (
|
||||
<fieldset
|
||||
|
|
|
@ -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;
|
|
@ -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>
|
||||
) }
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -8,3 +8,8 @@
|
|||
color: #999;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.components-base-control--nested {
|
||||
padding-left: 52px;
|
||||
margin-top: -12px;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 -->"
|
||||
`;
|
||||
|
|
|
@ -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": [
|
||||
|
|
Loading…
Reference in New Issue