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

Commit

Permalink
WIP - Checkout i2 Feature Branch Tracking (#4268)
Browse files Browse the repository at this point in the history
* Duplicate checkout block

* Contact information block

* form step block

* shipping address block

* Setup atomic blocks

* Container structure

* More formal steps rather than generic form step

* Add billing and shipping forms

* add checkout actions block

* add order note block

* Add order summary

* add payment block

* Add inspector controls for address fields

* frontend WIP

* move attributes

* wrap shipping with form step

* PhoneNumber to typescript

* Remove column block

* form steps

* move payment logic to frontend

* Express block

* inline payment block

* Add shipping method block

* Render inner blocks (not standalone blocks) and add classes to Atomic Block list on php side

* lazy again

* Add more wrappers from old frontend file

* add layout

* Checkout wrappers were missing

* Enqueue payment methods for new block

* Add missing classnames

* Move shipping as billing state to context provider

* express payments rendering

* try/block-registry

* Remove atomic components (unused)

* Fix attribute persistance due to template locking

* Fix shipping display when not needed

* Set correct parent blocks for inner blocks

* pass data to blocks

* demo/newsletter

* Skeleton styling

* only apply styles to loading state for now

* shipping method block frontend

* rename express block

* lock template

* fix ts warning for __webpack_public_path__

* Refactor to avoid duplicating atomic block logic

* remove changes in save method

* Add zones and shipping methods to the sidebar for the shipping inner block

Closes #4320

* Fix script handles

* Fix method display when there are none

* Add shipping phone

* Add phone to api and sync with billing correctly

* Clear hidden fields on load

* fix requirePhoneField property

* Enable shipping and billing phone fields

* readonly field support

* Handle context attributes

* Fix createInterpolateElement usage

* add totalswrapper

* Implement Terms and Conditions block for Checkout i2  (#4436)

* Setup atomic blocks

* frontend WIP

* Express block

* try/block-registry

* Set correct parent blocks for inner blocks

* Skeleton styling

* Refactor to avoid duplicating atomic block logic

* add block locking

* add terms and conditions block

* hardcore settings image

* lock blocks from being deleted

* hide original checkout block

* mark blocks as side effectful

* move variations to block register function

* prevent core checkout blocks from needlessly showing in the inserter

* enable checkout i1

* fix broken rebase

* move save back

* Localise default text

Co-authored-by: Mike Jolley <[email protected]>

* Add add-hoc Block locking from WooCommerce Blocks side. (#4454)

* add locking

* use subscribe instead

* fix condition

* add locking to blocks

* check if the item is not a text field

* Tidy up hacks CSS class handling

* Fix error if node is undefined

* Hide menu when move is disabled

* update package lock

* Add todo and fix issue where selector returns null

* split todos

* move todo

* edit comment

Co-authored-by: Mike Jolley <[email protected]>

* Un-disable the billing checkbox in the editor (#4457)

* Add missing Slot fill provider on frontend

Fixes #4441 by adding the slot fill provider to the checkout-i2 block.

* Use column style appender

* Add padding/styles to actions

* Add/update icon library

* Multiline checkbox alignment

* Icons and copy changes for i2 blocks

* Add terms by default

* Add notice if text is missing links (#4466)

* Swap variations for toggle

* Add payment settings to inspector

* Update package lock

* Add inline docs to block registry

* Add inner block areas below each form step.

This does not include the form step contents, just adds inner blocks after existing content. Moving content within the inner block area is a separate discussion.

This closes #4306

* Sample block registration + docs

* Add tests for registerCheckoutBlock

* Fix lazy component detection in tests

* Add basic transform between i1 and i2

* remove template lock todo

* Update scroll to top hoc

* Move shared settings to new context providers

Closes #4472

* Remove readonly field support (unused)

* Remove context code

* Experimental

* remove invalid typedef

* FIx scrolling on validation due to misplaced context provider

* Update assets/js/base/context/providers/cart-checkout/checkout-state/index.tsx

Co-authored-by: Darren Ethier <[email protected]>

* Update comment to remove reference to phone

* Update packages/checkout/blocks-registry/README.md

Co-authored-by: Darren Ethier <[email protected]>

* Rename ScrollToTopComponent

* Add explicit list of expectedType in TypeScript definition

* Add todo to remove custom shipping phone handling

* Remove dangerouslySetInnerHTML in External Link Card Component

* Add ExternalLinkCard to storybook

* update todo wording

* Refactor withScrollToTop to remove useCallback and use typescript

* Support children on CheckboxControl, with added Typescript

* Spread getRegisteredBlocks return value

Co-authored-by: Nadir Seghir <[email protected]>
Co-authored-by: Darren Ethier <[email protected]>
  • Loading branch information
3 people authored Jul 22, 2021
1 parent bb5a6da commit 89b5d30
Show file tree
Hide file tree
Showing 140 changed files with 5,673 additions and 209 deletions.
2 changes: 1 addition & 1 deletion assets/js/atomic/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * from './get-block-map';
export * from './create-blocks-from-template';
export * from './render-parent-block';
export * from './block-styling.js';
export * from './block-styling';
export * from './render-standalone-blocks';
2 changes: 1 addition & 1 deletion assets/js/base/components/block-error-boundary/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
max-width: 60ch;
}
.wc-block-components-error__message {
margin: 1em 0 0;
margin: 1em auto 0;
font-style: italic;
color: $studio-gray-30;
max-width: 60ch;
Expand Down
6 changes: 5 additions & 1 deletion assets/js/base/components/cart-checkout/form-step/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@
position: relative;
}

.wc-block-components-checkout-step__content {
.wc-block-components-checkout-step__content > * {
margin-bottom: em($gap);
}
.wc-block-components-checkout-step--with-step-number .wc-block-components-checkout-step__content > :last-child {
margin-bottom: 0;
padding-bottom: em($gap-large);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
getShippingRatesPackageCount,
getShippingRatesRateCount,
} from '@woocommerce/base-utils';
import { useStoreCart } from '@woocommerce/base-context/hooks';
import { useStoreCart, useEditorContext } from '@woocommerce/base-context';
import { CartResponseShippingRate } from '@woocommerce/type-defs/cart-response';
import { ReactElement } from 'react';

Expand Down Expand Up @@ -162,6 +162,7 @@ const ShippingRatesControl = ( {
ShippingRatesControlPackage,
},
};
const { isEditor } = useEditorContext();

return (
<LoadingMask
Expand All @@ -172,14 +173,26 @@ const ShippingRatesControl = ( {
) }
showSpinner={ true }
>
<ExperimentalOrderShippingPackages.Slot { ...slotFillProps } />
<ExperimentalOrderShippingPackages>
{ isEditor ? (
<Packages
packages={ shippingRates }
noResultsMessage={ noResultsMessage }
renderOption={ renderOption }
/>
</ExperimentalOrderShippingPackages>
) : (
<>
<ExperimentalOrderShippingPackages.Slot
{ ...slotFillProps }
/>
<ExperimentalOrderShippingPackages>
<Packages
packages={ shippingRates }
noResultsMessage={ noResultsMessage }
renderOption={ renderOption }
/>
</ExperimentalOrderShippingPackages>
</>
) }
</LoadingMask>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,34 @@
* External dependencies
*/
import { withInstanceId } from '@woocommerce/base-hocs/with-instance-id';
import PropTypes from 'prop-types';
import classNames from 'classnames';

/**
* Internal dependencies
*/
import './style.scss';

type CheckboxControlProps = {
className?: string;
label?: string;
id?: string;
instanceId: string;
onChange: ( value: boolean ) => void;
children: React.ReactChildren;
};

/**
* Component used to show a checkbox control with styles.
*
* @param {Object} props Incoming props for the component.
* @param {string} props.className CSS class used.
* @param {string} props.label Label for component.
* @param {string} props.id Id for component.
* @param {string} props.instanceId Unique id for instance of component.
* @param {function():any} props.onChange Function called when input changes.
* @param {Object} props.rest Rest of properties spread.
*/
const CheckboxControl = ( {
className,
label,
id,
instanceId,
onChange,
children,
...rest
} ) => {
}: CheckboxControlProps ): JSX.Element => {
const checkboxId = id || `checkbox-control-${ instanceId }`;

return (
Expand All @@ -54,19 +55,14 @@ const CheckboxControl = ( {
>
<path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" />
</svg>

<span className="wc-block-components-checkbox__label">
{ label }
</span>
{ label && (
<span className="wc-block-components-checkbox__label">
{ label }
</span>
) }
{ children }
</label>
);
};

CheckboxControl.propTypes = {
className: PropTypes.string,
label: PropTypes.string,
id: PropTypes.string,
onChange: PropTypes.func,
};

export default withInstanceId( CheckboxControl );
10 changes: 6 additions & 4 deletions assets/js/base/components/checkbox-control/style.scss
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
.wc-block-components-checkbox {
@include reset-typography();
align-items: center;
align-items: flex-start;
display: flex;
height: 1em;
position: relative;

.wc-block-components-checkbox__input[type="checkbox"] {
font-size: 1em;
appearance: none;
border: 2px solid $input-border-gray;
border-radius: 2px;
box-sizing: border-box;
height: em(24px);
width: em(24px);
margin: 0;
Expand Down Expand Up @@ -48,8 +48,8 @@
.wc-block-components-checkbox__mark {
fill: #000;
position: absolute;
left: em(3px);
top: em(-2px);
margin-left: em(3px);
margin-top: em(1px);
width: em(18px);
height: em(18px);

Expand All @@ -58,9 +58,11 @@
}
}

> span,
.wc-block-components-checkbox__label {
padding-left: $gap;
vertical-align: middle;
line-height: em(24px);
}
}

Expand Down
1 change: 1 addition & 0 deletions assets/js/base/context/hooks/cart/test/use-store-cart.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ describe( 'useStoreCart', () => {
state: '',
postcode: '',
country: '',
phone: '',
},
shippingRates: previewCart.shipping_rates,
extensions: {},
Expand Down
2 changes: 1 addition & 1 deletion assets/js/base/context/hooks/cart/use-store-cart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ const defaultShippingAddress: CartResponseShippingAddress = {
state: '',
postcode: '',
country: '',
phone: '',
};

const defaultBillingAddress: CartResponseBillingAddress = {
...defaultShippingAddress,
email: '',
phone: '',
};

const defaultCartTotals: CartResponseTotals = {
Expand Down
69 changes: 32 additions & 37 deletions assets/js/base/context/hooks/use-checkout-address.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,30 @@
* External dependencies
*/
import { defaultAddressFields } from '@woocommerce/settings';
import { useState, useEffect, useCallback, useRef } from '@wordpress/element';
import { useEffect, useCallback, useRef } from '@wordpress/element';

/**
* Internal dependencies
*/
import {
useShippingDataContext,
useCustomerDataContext,
useCheckoutContext,
} from '../providers/cart-checkout';

/**
* Compare two addresses and see if they are the same.
*
* @param {Object} address1 First address.
* @param {Object} address2 Second address.
*/
const isSameAddress = ( address1, address2 ) => {
return Object.keys( defaultAddressFields ).every(
( field ) => address1[ field ] === address2[ field ]
);
};

/**
* Custom hook for exposing address related functionality for the checkout address form.
*/
export const useCheckoutAddress = () => {
const { customerId } = useCheckoutContext();
const { needsShipping } = useShippingDataContext();
const {
billingData,
setBillingData,
shippingAddress,
setShippingAddress,
shippingAsBilling,
setShippingAsBilling,
} = useCustomerDataContext();

// This tracks the state of the "shipping as billing" address checkbox. It's
// initial value is true (if shipping is needed), however, if the user is
// logged in and they have a different billing address, we can toggle this off.
const [ shippingAsBilling, setShippingAsBilling ] = useState(
() =>
needsShipping &&
( ! customerId || isSameAddress( shippingAddress, billingData ) )
);

const currentShippingAsBilling = useRef( shippingAsBilling );
const previousBillingData = useRef( billingData );

Expand Down Expand Up @@ -78,23 +57,22 @@ export const useCheckoutAddress = () => {
[ needsShipping, setShippingAddress, setBillingData ]
);

// When the "Use same address" checkbox is toggled we need to update the current billing address to reflect this;
// that is either setting the billing address to the shipping address, or restoring the billing address to it's
// previous state.
// When the "Use same address" checkbox is toggled we need to update the current billing address to reflect this.
// This either sets the billing address to the shipping address, or restores the billing address to it's previous state.
useEffect( () => {
if ( currentShippingAsBilling.current !== shippingAsBilling ) {
if ( shippingAsBilling ) {
previousBillingData.current = billingData;
setBillingData( shippingAddress );
} else {
const {
// We need to pluck out email and phone from previous billing data because they can be empty, causing the current email and phone to get emptied. See issue #4155
// We need to pluck out email from previous billing data because they can be empty, causing the current email to get emptied. See issue #4155
/* eslint-disable no-unused-vars */
email,
phone,
/* eslint-enable no-unused-vars */
...billingAddress
} = previousBillingData.current;

setBillingData( {
...billingAddress,
} );
Expand All @@ -103,14 +81,29 @@ export const useCheckoutAddress = () => {
}
}, [ shippingAsBilling, setBillingData, shippingAddress, billingData ] );

const setEmail = ( value ) =>
void setBillingData( {
email: value,
} );
const setPhone = ( value ) =>
void setBillingData( {
phone: value,
} );
const setEmail = useCallback(
( value ) =>
void setBillingData( {
email: value,
} ),
[ setBillingData ]
);

const setPhone = useCallback(
( value ) =>
void setBillingData( {
phone: value,
} ),
[ setBillingData ]
);

const setShippingPhone = useCallback(
( value ) =>
void setShippingFields( {
phone: value,
} ),
[ setShippingFields ]
);

// Note that currentShippingAsBilling is returned rather than the current state of shippingAsBilling--this is so that
// the billing fields are not rendered before sync (billing field values are debounced and would be outdated)
Expand All @@ -122,8 +115,10 @@ export const useCheckoutAddress = () => {
setBillingFields,
setEmail,
setPhone,
setShippingPhone,
shippingAsBilling,
setShippingAsBilling,
showShippingFields: needsShipping,
showBillingFields:
! needsShipping || ! currentShippingAsBilling.current,
};
Expand Down
15 changes: 10 additions & 5 deletions assets/js/base/context/hooks/use-customer-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export const useCustomerData = (): {
/**
* Set billing data.
*
* Contains special handling for email and phone so those fields are not overwritten if simply updating address.
* Contains special handling for email so those fields are not overwritten if simply updating address.
*/
const setBillingData = useCallback( ( newData ) => {
setCustomerData( ( prevState ) => {
Expand All @@ -130,10 +130,15 @@ export const useCustomerData = (): {
* Set shipping data.
*/
const setShippingAddress = useCallback( ( newData ) => {
setCustomerData( ( prevState ) => ( {
...prevState,
shippingAddress: newData,
} ) );
setCustomerData( ( prevState ) => {
return {
...prevState,
shippingAddress: {
...prevState.shippingAddress,
...newData,
},
};
} );
}, [] );

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ export const useCheckoutContext = (): CheckoutStateContextType => {

/**
* Checkout state provider
* This provides provides an api interface exposing checkout state for use with
* cart or checkout blocks.
* This provides an API interface exposing checkout state for use with cart or checkout blocks.
*
* @param {Object} props Incoming props for the provider.
* @param {Object} props.children The children being wrapped.
Expand Down
Loading

0 comments on commit 89b5d30

Please sign in to comment.