From d58712ee2b36c1889eb7593c1c985382fdcd65ac Mon Sep 17 00:00:00 2001 From: Seghir Nadir Date: Mon, 16 Dec 2019 23:13:41 +0100 Subject: [PATCH] Add Checkout Form components (https://github.com/woocommerce/woocommerce-blocks/pull/1351) * initial commit at fields * add radio control * change input to be uncotrolled * tweak styles * populate block with boilerplate * update aria in radio * remove comment * fix typo * add missing colors * put reminder to put Disabled back * wrap text in i18n __ * reorder styles * rename wc-components to wc-blocks * use value instead of index for keys * add no shipping placeholder * change isEditor default to false * fix problem with responsive --- .../assets/css/abstracts/_colors.scss | 4 + .../components/checkout/no-shipping/index.js | 40 +++ .../checkout/no-shipping/style.scss | 5 + .../js/base/components/input-row/index.js | 19 + .../js/base/components/input-row/style.scss | 21 ++ .../js/base/components/radio-control/index.js | 113 ++++++ .../base/components/radio-control/style.scss | 36 ++ .../js/base/components/text-input/index.js | 73 ++++ .../js/base/components/text-input/style.scss | 36 ++ .../js/blocks/cart-checkout/checkout/block.js | 330 ++++++++++++++++-- .../js/blocks/cart-checkout/checkout/edit.js | 7 +- .../blocks/cart-checkout/checkout/frontend.js | 4 +- .../blocks/cart-checkout/checkout/style.scss | 6 +- 13 files changed, 649 insertions(+), 45 deletions(-) create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/checkout/no-shipping/index.js create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/checkout/no-shipping/style.scss create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/input-row/index.js create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/input-row/style.scss create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/radio-control/index.js create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/radio-control/style.scss create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/text-input/index.js create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/text-input/style.scss diff --git a/plugins/woocommerce-blocks/assets/css/abstracts/_colors.scss b/plugins/woocommerce-blocks/assets/css/abstracts/_colors.scss index e8115fc6b0a..afcaf435024 100644 --- a/plugins/woocommerce-blocks/assets/css/abstracts/_colors.scss +++ b/plugins/woocommerce-blocks/assets/css/abstracts/_colors.scss @@ -47,5 +47,9 @@ $core-orange: #ca4a1f; // @todo: replace those colors with the correct values once we settle on a design system palette. $gray-10: #c3c4c7; $gray-20: #a7aaad; +$gray-50: #646970; $gray-60: #50575e; $gray-80: #2c3338; +// @todo: align those colors with what we have +$input-border-gray: #8d96a0; +$input-text-active: #2b2d2f; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/checkout/no-shipping/index.js b/plugins/woocommerce-blocks/assets/js/base/components/checkout/no-shipping/index.js new file mode 100644 index 00000000000..2c71c8c4f57 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/checkout/no-shipping/index.js @@ -0,0 +1,40 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { Placeholder, Button } from '@wordpress/components'; +import ShippingIcon from 'gridicons/dist/shipping'; +import { ADMIN_URL } from '@woocommerce/settings'; + +/** + * Internal dependencies + */ +import './style.scss'; + +const NoShipping = () => { + return ( + } + label={ __( 'Shipping options', 'woo-gutenberg-products-block' ) } + className="wc-blocks-checkout__no-shipping" + > + + { __( + 'Your store does not have any Shipping Options configured. Once you have added your Shipping Options they will appear here.', + 'woo-gutenberg-products-block' + ) } + + + + ); +}; + +export default NoShipping; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/checkout/no-shipping/style.scss b/plugins/woocommerce-blocks/assets/js/base/components/checkout/no-shipping/style.scss new file mode 100644 index 00000000000..92b11c945f9 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/checkout/no-shipping/style.scss @@ -0,0 +1,5 @@ +.wc-blocks-checkout__no-shipping-description { + display: block; + margin: 0.25em 0 1em 0; + font-size: 13px; +} diff --git a/plugins/woocommerce-blocks/assets/js/base/components/input-row/index.js b/plugins/woocommerce-blocks/assets/js/base/components/input-row/index.js new file mode 100644 index 00000000000..e6d853f9821 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/input-row/index.js @@ -0,0 +1,19 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * Internal dependencies + */ +import './style.scss'; + +const InputRow = ( { className, children } ) => { + return ( +
+ { children } +
+ ); +}; + +export default InputRow; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/input-row/style.scss b/plugins/woocommerce-blocks/assets/js/base/components/input-row/style.scss new file mode 100644 index 00000000000..694033a22bb --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/input-row/style.scss @@ -0,0 +1,21 @@ +.wc-blocks-input-row { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + + & > .wc-blocks-text-input { + margin-right: $gap-small; + flex-grow: 1; + margin-top: $gap; + &:last-child { + margin-right: 0; + } + } + + // Responsive media styles. + @include breakpoint( "<480px" ) { + .wc-blocks-text-input { + margin-right: 0; + } + } +} diff --git a/plugins/woocommerce-blocks/assets/js/base/components/radio-control/index.js b/plugins/woocommerce-blocks/assets/js/base/components/radio-control/index.js new file mode 100644 index 00000000000..336bd68e1b3 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/radio-control/index.js @@ -0,0 +1,113 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * Internal dependencies + */ +import Label from '../label'; +import './style.scss'; + +const RadioControl = ( { + className, + selected, + id, + onChange, + options = [], +} ) => { + const onChangeValue = ( event ) => onChange( event.target.value ); + return ( + options.length && ( +
+ { options.map( + ( { + value, + label, + description, + secondaryLabel, + secondaryDescription, + } ) => ( + + ) + ) } +
+ ) + ); +}; + +export default RadioControl; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/radio-control/style.scss b/plugins/woocommerce-blocks/assets/js/base/components/radio-control/style.scss new file mode 100644 index 00000000000..093ba6e53c9 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/radio-control/style.scss @@ -0,0 +1,36 @@ +.wc-blocks-radio-control__option { + display: flex; + position: relative; + justify-content: space-between; + flex-wrap: wrap; + padding: $gap-small $gap-small $gap-small ($gap-larger * 2); + border-bottom: 1px solid $core-grey-light-600; +} + +.wc-blocks-radio-control__input { + position: absolute; + left: $gap-large; + top: $gap-large; +} + +.wc-blocks-radio-control__label, +.wc-blocks-radio-control__secondary-label { + font-size: 16px; + line-height: 24px; + color: $core-grey-dark-600; + flex-basis: 50%; +} + +.wc-blocks-radio-control__description, +.wc-blocks-radio-control__secondary-description { + font-size: 14px; + line-height: 20px; + color: $core-grey-dark-400; + flex-basis: 50%; +} + +.wc-blocks-radio-control__secondary-label, +.wc-blocks-radio-control__secondary-description { + text-align: right; +} + diff --git a/plugins/woocommerce-blocks/assets/js/base/components/text-input/index.js b/plugins/woocommerce-blocks/assets/js/base/components/text-input/index.js new file mode 100644 index 00000000000..e5c4c5590d4 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/text-input/index.js @@ -0,0 +1,73 @@ +/** + * External dependencies + */ +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import Label from '../label'; +import './style.scss'; + +const TextInput = ( { + className, + id, + ariaLabel, + label, + screenReaderLabel, + disabled, + help, + value, + onChange, +} ) => { + const [ isActive, setIsActive ] = useState( false ); + const onChangeValue = ( event ) => onChange( event.target.value ); + return ( +
+
+ ); +}; + +TextInput.propTypes = { + id: PropTypes.string, + value: PropTypes.string, + onChangeValue: PropTypes.func, + ariaLabel: PropTypes.string, + label: PropTypes.string, + screenReaderLabel: PropTypes.string, + disabled: PropTypes.bool, + help: PropTypes.string, +}; + +export default TextInput; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/text-input/style.scss b/plugins/woocommerce-blocks/assets/js/base/components/text-input/style.scss new file mode 100644 index 00000000000..b1826b9e4b1 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/text-input/style.scss @@ -0,0 +1,36 @@ +.wc-blocks-text-input { + position: relative; + margin-top: $gap; +} + +.wc-blocks-text-input label { + position: absolute; + transform: translateX(#{$gap}) translateY(#{$gap-small}); + font-size: 16px; + line-height: 22px; + transition: all 200ms ease; + color: $gray-50; +} + +.wc-blocks-text-input.is-active label { + transform: translateX(#{$gap - $gap-small}) translateY(#{$gap-smallest}) scale(0.75); + transition: all 200ms ease; +} + +.wc-blocks-text-input input[type="text"] { + padding: $gap-small $gap; + border-radius: 4px; + border: 1px solid $input-border-gray; + width: 100%; + font-size: 16px; + line-height: 22px; + font-family: inherit; + margin: 0; + box-sizing: border-box; + height: 48px; + color: $input-text-active; +} + +.wc-blocks-text-input.is-active input[type="text"] { + padding: $gap-large $gap $gap-smallest; +} diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/block.js b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/block.js index 882cfc319aa..ebaf52c6add 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/block.js +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/block.js @@ -1,12 +1,15 @@ /** * External dependencies */ -import { Fragment } from '@wordpress/element'; -import { Placeholder } from '@wordpress/components'; +import { Fragment, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; 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'; +import TextInput from '@woocommerce/base-components/text-input'; +import RadioControl from '@woocommerce/base-components/radio-control'; +import InputRow from '@woocommerce/base-components/input-row'; +import { CheckboxControl, Placeholder } from '@wordpress/components'; /** * Internal dependencies */ @@ -15,7 +18,11 @@ import './style.scss'; /** * Component displaying an attribute filter. */ -const Block = () => { +const Block = ( { shippingMethods = [], isEditor = false } ) => { + const [ shippingMethod, setShippingMethod ] = useState( {} ); + const [ contactFields, setContactFields ] = useState( {} ); + const [ shouldSavePayment, setShouldSavePayment ] = useState( true ); + const [ shippingFields, setShippingFields ] = useState( {} ); return ( { ) } > - A checkout step, coming soon near you + + setContactFields( { + ...contactFields, + email: newValue, + } ) + } + /> + + setContactFields( { + ...contactFields, + keepUpdated: ! contactFields.keepUpdated, + } ) + } + /> + { shippingMethods.length === 0 && ( + + { isEditor && } + + ) } + { shippingMethods.length > 0 && ( + + + + + setShippingFields( { + ...shippingFields, + firstName: newValue, + } ) + } + /> + + setShippingFields( { + ...shippingFields, + lastName: newValue, + } ) + } + /> + + + setShippingFields( { + ...shippingFields, + streetAddress: newValue, + } ) + } + /> + + setShippingFields( { + ...shippingFields, + apartment: newValue, + } ) + } + /> + + + setShippingFields( { + ...shippingFields, + country: newValue, + } ) + } + /> + + setShippingFields( { + ...shippingFields, + country: newValue, + } ) + } + /> + + + + setShippingFields( { + ...shippingFields, + county: newValue, + } ) + } + /> + + setShippingFields( { + ...shippingFields, + postalCode: newValue, + } ) + } + /> + + + setShippingFields( { + ...shippingFields, + phone: newValue, + } ) + } + /> + + setShippingFields( { + ...shippingFields, + useSameForBilling: ! shippingFields.useSameForBilling, + } ) + } + /> + + + + setShippingMethod( { + ...shippingMethod, + method: option, + } ) + } + options={ [ + { + label: 'Click & Collect', + value: 'collect', + description: + 'Pickup between 12:00 - 16:00 (Mon-Fri)', + secondaryLabel: 'FREE', + }, + { + label: 'Regular shipping', + value: 'usps-normal', + description: 'Dispatched via USPS', + secondaryLabel: '€10.00', + secondaryDescription: '5 business days', + }, + { + label: 'Express shipping', + value: 'ups-express', + description: 'Dispatched via USPS', + secondaryLabel: '€50.00', + secondaryDescription: '2 business days', + }, + ] } + /> + + setShippingMethod( { + ...shippingMethod, + orderNote: ! shippingMethod.orderNote, + } ) + } + /> + + + ) } - A checkout step, coming soon near you - - - A checkout step, coming soon near you - - { ) } stepNumber={ 4 } > - A checkout step, coming soon near you + Payment methods, coming soon + + setShouldSavePayment( ! shouldSavePayment ) + } + /> ); diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/edit.js b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/edit.js index 740da959a4a..cd2d7704828 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/edit.js +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/edit.js @@ -2,7 +2,6 @@ * External dependencies */ import { __ } from '@wordpress/i18n'; -import { Disabled } from '@wordpress/components'; import { withFeedbackPrompt } from '@woocommerce/block-hocs'; /** @@ -13,12 +12,10 @@ import './editor.scss'; const CheckoutEditor = ( { attributes } ) => { const { className } = attributes; - + // @todo: wrap Block with Disabled once you finish building the form return (
- - - +
); }; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/frontend.js b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/frontend.js index bb508e5557c..101ba2403d2 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/frontend.js +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/frontend.js @@ -11,7 +11,9 @@ import renderFrontend from '../../../utils/render-frontend.js'; const getProps = () => { return { - attributes: {}, + attributes: { + isEditor: false, + }, }; }; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/style.scss index da3ad0454b1..91eb945f9bb 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/style.scss +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/style.scss @@ -1 +1,5 @@ -// To be written +.wc-blocks-checkout__add-note, +.wc-blocks-checkout__keep-updated, +.wc-blocks-checkout__use-address-for-billing { + margin-top: $gap; +}