Skip to content

Commit

Permalink
Refactor checkout workflow to set shipping address and receive shippi…
Browse files Browse the repository at this point in the history
…ng methods in single action.
  • Loading branch information
sirugh committed Dec 12, 2019
1 parent 60a0d47 commit 4030d43
Show file tree
Hide file tree
Showing 17 changed files with 263 additions and 113 deletions.
88 changes: 74 additions & 14 deletions packages/peregrine/lib/store/actions/checkout/asyncActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,30 @@ import actions from './actions';
const { request } = Magento2;
const storage = new BrowserPersistence();

export const beginCheckout = payload =>
export const beginCheckout = () =>
async function thunk(dispatch) {
const { fetchCartId } = payload;
// Before we begin, reset the state of checkout to clear out stale data.
dispatch(actions.reset());

const storedAvailableShippingMethods = await retreiveAvailableShippingMethods();
const storedBillingAddress = storage.getItem('billing_address');
const storedPaymentMethod = storage.getItem('paymentMethod');
const storedShippingAddress = storage.getItem('shipping_address');
const storedShippingMethod = storage.getItem('shippingMethod');

dispatch(
actions.begin({
availableShippingMethods: storedAvailableShippingMethods || [],
billingAddress: storedBillingAddress,
paymentCode: storedPaymentMethod && storedPaymentMethod.code,
paymentData: storedPaymentMethod && storedPaymentMethod.data,
shippingAddress: storedShippingAddress,
shippingAddress: storedShippingAddress || {},
shippingMethod:
storedShippingMethod && storedShippingMethod.carrier_code,
shippingTitle:
storedShippingMethod && storedShippingMethod.carrier_title
})
);
dispatch(
getShippingMethods({
fetchCartId
})
);
};

export const cancelCheckout = () =>
Expand Down Expand Up @@ -170,23 +166,74 @@ export const submitPaymentMethod = payload =>
}
};

export const submitShippingAddress = payload =>
export const submitShippingAddress = (payload = {}) =>
async function thunk(dispatch, getState) {
dispatch(actions.shippingAddress.submit());

const { cart } = getState();
const {
formValues,
countries,
setGuestEmail,
setShippingAddressOnCart
} = payload;

const { cart, user } = getState();

const { cartId } = cart;
if (!cartId) {
throw new Error('Missing required information: cartId');
}

try {
const address = formatAddress(
payload.formValues,
payload.countries
);
const address = formatAddress(formValues, countries);

if (!user.isSignedIn) {
if (!formValues.email) {
throw new Error('Missing required information: email');
}
await setGuestEmail({
variables: {
cartId,
email: formValues.email
}
});
}

const {
firstname,
lastname,
street,
city,
region_code,
postcode,
telephone,
country_id
} = address;

const { data } = await setShippingAddressOnCart({
variables: {
cartId,
firstname,
lastname,
street,
city,
region_code,
postcode,
telephone,
country_id
}
});
// We can get the shipping methods immediately after setting the
// address. Grab it from the response and put it in the store.
const shippingMethods =
data.setShippingAddressesOnCart.cart.shipping_addresses[0]
.available_shipping_methods;

// On success, save to local storage.
await saveAvailableShippingMethods(shippingMethods);
await saveShippingAddress(address);

dispatch(actions.getShippingMethods.receive(shippingMethods));
dispatch(actions.shippingAddress.accept(address));
} catch (error) {
dispatch(actions.shippingAddress.reject(error));
Expand Down Expand Up @@ -351,6 +398,18 @@ export const formatAddress = (address = {}, countries = []) => {
};
};

async function clearAvailableShippingMethods() {
return storage.removeItem('availableShippingMethods');
}

async function retreiveAvailableShippingMethods() {
return storage.getItem('availableShippingMethods');
}

async function saveAvailableShippingMethods(methods) {
return storage.setItem('availableShippingMethods', methods);
}

async function clearBillingAddress() {
return storage.removeItem('billing_address');
}
Expand Down Expand Up @@ -404,4 +463,5 @@ export const clearCheckoutDataFromStorage = async () => {
await clearPaymentMethod();
await clearShippingAddress();
await clearShippingMethod();
await clearAvailableShippingMethods();
};
2 changes: 1 addition & 1 deletion packages/peregrine/lib/store/reducers/checkout.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const initialState = {
receipt: {
order: {}
},
shippingAddress: null,
shippingAddress: {},
shippingAddressError: null,
shippingMethod: '',
shippingMethodError: null,
Expand Down
49 changes: 42 additions & 7 deletions packages/peregrine/lib/talons/Checkout/useAddressForm.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { useCallback, useMemo } from 'react';
import { useCheckoutContext } from '@magento/peregrine/lib/context/checkout';
import { useMutation } from '@apollo/react-hooks';
import { useUserContext } from '@magento/peregrine/lib/context/user';

/**
* Returns values used to render an AddressForm component.
*
* @param {Object} props
* @param {Object[]} props.fields an array of fields to reduce over for initial values
* @param {Object} props.initialValues Object containing some initial values from state
* @param {function} props.onCancel cancel callback
* @param {function} props.onSubmit submit callback
* @returns {{
Expand All @@ -14,31 +17,63 @@ import { useCallback, useMemo } from 'react';
* }}
*/
export const useAddressForm = props => {
const { fields, initialValues, onCancel, onSubmit } = props;
const {
countries,
fields,
onCancel,
onSubmit,
setGuestEmailMutation,
setShippingAddressOnCartMutation
} = props;

const [
{ shippingAddress, shippingAddressError },
{ submitShippingAddress }
] = useCheckoutContext();

const [{ isSignedIn }] = useUserContext();

const [setGuestEmail] = useMutation(setGuestEmailMutation);
const [setShippingAddressOnCart] = useMutation(
setShippingAddressOnCartMutation
);
const values = useMemo(
() =>
fields.reduce((acc, key) => {
acc[key] = initialValues[key];
acc[key] = shippingAddress[key];
return acc;
}, {}),
[fields, initialValues]
[fields, shippingAddress]
);

const handleCancel = useCallback(() => {
onCancel();
}, [onCancel]);

const handleSubmit = useCallback(
addressFormValues => {
onSubmit(addressFormValues);
async addressFormValues => {
await submitShippingAddress({
formValues: addressFormValues,
countries,
setGuestEmail,
setShippingAddressOnCart
});
onSubmit();
},
[onSubmit]
[
countries,
onSubmit,
setGuestEmail,
setShippingAddressOnCart,
submitShippingAddress
]
);

return {
error: shippingAddressError,
handleCancel,
handleSubmit,
isSignedIn,
initialValues: values
};
};
14 changes: 3 additions & 11 deletions packages/peregrine/lib/talons/Checkout/useEditableForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,16 @@ export const useEditableForm = props => {
countries,
setEditing,
submitPaymentMethodAndBillingAddress,
submitShippingAddress,
submitShippingMethod
} = props;

const handleCancel = useCallback(() => {
setEditing(null);
}, [setEditing]);

const handleSubmitAddressForm = useCallback(
async formValues => {
await submitShippingAddress({
countries,
formValues
});
setEditing(null);
},
[countries, setEditing, submitShippingAddress]
);
const handleSubmitAddressForm = useCallback(() => {
setEditing(null);
}, [setEditing]);

const handleSubmitPaymentsForm = useCallback(
async formValues => {
Expand Down
12 changes: 3 additions & 9 deletions packages/peregrine/lib/talons/Checkout/useFlow.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useCallback } from 'react';
import { useMutation } from '@apollo/react-hooks';

import { useCartContext } from '@magento/peregrine/lib/context/cart';
import { useCheckoutContext } from '@magento/peregrine/lib/context/checkout';
Expand Down Expand Up @@ -27,8 +26,7 @@ const isCheckoutReady = checkout => {
};

export const useFlow = props => {
const { createCartMutation, onSubmitError, setStep } = props;
const [fetchCartId] = useMutation(createCartMutation);
const { onSubmitError, setStep } = props;
const [cartState] = useCartContext();
const [
checkoutState,
Expand All @@ -37,17 +35,14 @@ export const useFlow = props => {
cancelCheckout,
submitOrder,
submitPaymentMethodAndBillingAddress,
submitShippingAddress,
submitShippingMethod
}
] = useCheckoutContext();

const handleBeginCheckout = useCallback(async () => {
await beginCheckout({
fetchCartId
});
await beginCheckout();
setStep('form');
}, [beginCheckout, fetchCartId, setStep]);
}, [beginCheckout, setStep]);

const handleCancelCheckout = useCallback(async () => {
await cancelCheckout();
Expand Down Expand Up @@ -75,7 +70,6 @@ export const useFlow = props => {
checkoutState,
isReady: isCheckoutReady(checkoutState),
submitPaymentMethodAndBillingAddress,
submitShippingAddress,
submitShippingMethod,
handleBeginCheckout,
handleCancelCheckout,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useCallback, useState } from 'react';
import { useFormState } from 'informed';
import { useUserContext } from '@magento/peregrine/lib/context/user';

/**
*
Expand All @@ -9,7 +10,7 @@ import { useFormState } from 'informed';
*/
export const usePaymentsFormItems = props => {
const [isReady, setIsReady] = useState(false);

const [{ isSignedIn }] = useUserContext();
const { isSubmitting, setIsSubmitting, onCancel, onSubmit } = props;

// Currently form state toggles dirty from false to true because of how
Expand Down Expand Up @@ -71,6 +72,7 @@ export const usePaymentsFormItems = props => {
handleError,
handleSuccess,
isDisabled: !isReady || isSubmitting,
isSignedIn,
setIsReady
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ Array [
</button>
<button
className="root"
disabled={true}
onClick={[Function]}
>
<span
Expand Down Expand Up @@ -226,6 +227,7 @@ Array [
</button>
<button
className="root"
disabled={true}
onClick={[Function]}
>
<span
Expand Down Expand Up @@ -383,6 +385,7 @@ Array [
</button>
<button
className="root"
disabled={true}
onClick={[Function]}
>
<span
Expand Down Expand Up @@ -540,6 +543,7 @@ Array [
</button>
<button
className="root"
disabled={true}
onClick={[Function]}
>
<span
Expand Down
Loading

0 comments on commit 4030d43

Please # to comment.