I'm about 3/4 of the way through the video and really enjoying it so far. I'm struggling with the ShippingData part. For some reason it doesn't look like the FormInput fields are being set in shippingData request payload to api.chec - As you can see its an empty object below
{,…} customer: {} fulfillment: {shipping_method: "ship_p6dP5gbmYon7kA"} line_items: [{id: "item_7RyWOwmK5nEa2V", product_id: "prod_Kvg9l61n0d51bB", name: "Robin Hood",…},…] payment: {gateway: "stripe", stripe: {payment_method_id: "pm_1KhaFELTXNlEjoivg8TNLkUu"}} shipping: {name: "Primary", county_state: "IA", country: "US"}
{"status_code":422,"error":{"message":"The given data was invalid.","type":"unprocessable_entity","errors":{"customer.email":["The Email field is required when customer.id is not present."],"shipping.street":["The Shipping street address field is required when customer.id is not present."],"shipping.town_city":["The Shipping town\/city field is required when customer.id is not present."]}},
Only the fields that have a set like SetShippingCountries are being passed to the ShippingData.. The other values that come from the onSubmit are not being populated - The fields shown below do not pass into customer or shipping.
<FormInput name='firstName' label='First name' /> <FormInput name='lastName' label='Last name' /> <FormInput name='address1' label='Address line 1' /> <FormInput name='email' label='Email' /> <FormInput name='city' label='City' /> <FormInput name='zip' label='ZIP / Postal Code' />
Here's my AddressForm.jsx
`import React, { useState, useEffect } from 'react';
import {
InputLabel,
Select,
MenuItem,
Button,
Grid,
Typography,
} from '@material-ui/core';
import { useForm, FormProvider } from 'react-hook-form';
import { Link } from 'react-router-dom';
import { commerce } from '../../lib/commerce';
import FormInput from './CustomTextField';
const AddressForm = ({ checkoutToken, test }) => {
const [shippingCountries, setShippingCountries] = useState([]);
const [shippingCountry, setShippingCountry] = useState('');
const [shippingSubdivisions, setShippingSubdivisions] = useState([]);
const [shippingSubdivision, setShippingSubdivision] = useState('');
const [shippingOptions, setShippingOptions] = useState([]);
const [shippingOption, setShippingOption] = useState('');
const methods = useForm();
const countries = Object.entries(shippingCountries).map(([code, name]) => ({
id: code,
label: name,
}));
const subdivisions = Object.entries(shippingSubdivisions).map(
([code, name]) => ({
id: code,
label: name,
})
);
const options = shippingOptions.map((so) => ({
id: so.id,
label: ${so.description} - (${so.price.formatted_with_symbol})
,
}));
const fetchShippingCountries = async (checkoutTokenId) => {
const { countries } = await commerce.services.localeListShippingCountries(
checkoutTokenId
);
// console.log(countries);
setShippingCountries(countries);
setShippingCountry(Object.keys(countries)[0]);
};
const fetchSubdivisions = async (countryCode) => {
const { subdivisions } = await commerce.services.localeListSubdivisions(
countryCode
);
setShippingSubdivisions(subdivisions);
setShippingSubdivision(Object.keys(subdivisions)[0]);
};
const fetchShippingOptions = async (
checkoutTokenId,
country,
// region = null
stateProvince
) => {
const options = await commerce.checkout.getShippingOptions(
checkoutTokenId,
{ country, stateProvince }
);
setShippingOptions(options);
setShippingOption(options[0].id);
};
useEffect(() => {
fetchShippingCountries(checkoutToken.id);
}, []);
useEffect(() => {
if (shippingCountry) fetchSubdivisions(shippingCountry);
}, [shippingCountry]);
useEffect(() => {
if (shippingSubdivision)
fetchShippingOptions(
checkoutToken.id,
shippingCountry,
shippingSubdivision
);
}, [shippingSubdivision]);
return (
<>
Shipping Address
<FormProvider {...methods}>
<form
onSubmit={methods.handleSubmit((data) =>
test({
...data,
shippingCountry,
shippingSubdivision,
shippingOption,
})
)}
>
Shipping Country
<Select
value={shippingCountry}
fullwidth='true'
onChange={(e) => setShippingCountry(e.target.value)}
>
{countries.map((country) => (
{country.label}
))}
Shipping Subdivision
<Select
value={shippingSubdivision}
fullwidth='true'
onChange={(e) => setShippingSubdivision(e.target.value)}
>
{subdivisions.map((subdivision) => (
{subdivision.label}
))}
Shipping Options
<Select
value={shippingOption}
fullwidth='true'
onChange={(e) => setShippingOption(e.target.value)}
>
{options.map((option) => (
{option.label}
))}
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
Back to Cart
Next
</>
);
};
export default AddressForm;
`
Here's my PaymentForm.jsx
`import React from 'react';
import { Typography, Button, Divider } from '@material-ui/core';
import {
Elements,
CardElement,
ElementsConsumer,
} from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import Review from './Review';
const stripePromise = loadStripe(process.env.REACT_APP_STRIPE_PUBLIC_KEY);
const PaymentForm = ({
checkoutToken,
backStep,
nextStep,
shippingData,
onCaptureCheckout,
}) => {
const handleSubmit = async (event, elements, stripe) => {
event.preventDefault();
if (!stripe || !elements) return;
const cardElement = elements.getElement(CardElement);
const { error, paymentMethod } = await stripe.createPaymentMethod({
type: 'card',
card: cardElement,
});
if (error) {
console.log('[error]', error);
} else {
const orderData = {
line_items: checkoutToken.live.line_items,
customer: {
firstname: shippingData.firstName,
lastname: shippingData.lastName,
email: shippingData.email,
// firstname: 'John',
// lastname: 'Smith',
// email: '[email protected]',
},
shipping: {
name: 'Primary',
street: shippingData.address1,
town_city: shippingData.city,
county_state: shippingData.shippingSubdivision,
postal_zip_code: shippingData.zip,
country: shippingData.shippingCountry,
},
fulfillment: { shipping_method: shippingData.shippingOption },
payment: {
gateway: 'stripe',
stripe: {
payment_method_id: paymentMethod.id,
},
},
};
onCaptureCheckout(checkoutToken.id, orderData);
nextStep();
}
};
return (
<>
<Typography variant='h6' gutterBottom style={{ margin: '20px 0' }}>
Payment method
{({ elements, stripe }) => (
<form onSubmit={(e) => handleSubmit(e, elements, stripe)}>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
Back
Pay {checkoutToken.live.subtotal.formatted_with_symbol}
)}
</>
);
};
export default PaymentForm;
`
Here's my app.js
`import React, { useState, useEffect } from 'react';
import { commerce } from './lib/commerce';
import { Products, Navbar, Cart, Checkout, PageNotFound } from './components';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
const App = () => {
const [products, setProducts] = useState([]);
const [cart, setCart] = useState({});
const [order, setOrder] = useState({});
const [errorMessage, setErrorMessage] = useState('');
const fetchProducts = async () => {
const { data } = await commerce.products.list();
setProducts(data);
};
const fetchCart = async () => {
setCart(await commerce.cart.retrieve());
};
const handleAddToCart = async (productId, quantity) => {
const item = await commerce.cart.add(productId, quantity);
};
const handleUpdateCartQty = async (productId, quantity) => {
const { cart } = await commerce.cart.update(productId, { quantity });
};
const handleRemoveFromCart = async (productId) => {
const { cart } = await commerce.cart.remove(productId);
};
const handleEmptyCart = async () => {
const { cart } = await commerce.cart.empty();
};
const refreshCart = async () => {
const newCart = await commerce.cart.refresh();
};
const handleCaptureCheckout = async (checkoutTokenId, newOrder) => {
try {
console.log(HandleCaptureCheckout Function entered
);
const incomingOrder = await commerce.checkout.capture(
checkoutTokenId,
newOrder
);
setOrder(incomingOrder);
console.log(This is neworder ${newOrder}
);
console.log(This is incomingOrder ${incomingOrder}
);
refreshCart();
} catch (error) {
setErrorMessage(error.data.error.message);
}
};
useEffect(() => {
fetchProducts();
fetchCart();
}, []);
//console.log(products);
// console.log(cart);
return (
);
};
export default App;
`
Here's my App.js
import React, { useState, useEffect } from 'react';
import {
InputLabel,
Select,
MenuItem,
Button,
Grid,
Typography,
} from '@material-ui/core';
import { useForm, FormProvider } from 'react-hook-form';
import { Link } from 'react-router-dom';
import { commerce } from '../../lib/commerce';
import FormInput from './CustomTextField';
const AddressForm = ({ checkoutToken, test }) => {
const [shippingCountries, setShippingCountries] = useState([]);
const [shippingCountry, setShippingCountry] = useState('');
const [shippingSubdivisions, setShippingSubdivisions] = useState([]);
const [shippingSubdivision, setShippingSubdivision] = useState('');
const [shippingOptions, setShippingOptions] = useState([]);
const [shippingOption, setShippingOption] = useState('');
const methods = useForm();
const countries = Object.entries(shippingCountries).map(([code, name]) => ({
id: code,
label: name,
}));
const subdivisions = Object.entries(shippingSubdivisions).map(
([code, name]) => ({
id: code,
label: name,
})
);
const options = shippingOptions.map((so) => ({
id: so.id,
label: ${so.description} - (${so.price.formatted_with_symbol})
,
}));
const fetchShippingCountries = async (checkoutTokenId) => {
const { countries } = await commerce.services.localeListShippingCountries(
checkoutTokenId
);
// console.log(countries);
setShippingCountries(countries);
setShippingCountry(Object.keys(countries)[0]);
};
const fetchSubdivisions = async (countryCode) => {
const { subdivisions } = await commerce.services.localeListSubdivisions(
countryCode
);
setShippingSubdivisions(subdivisions);
setShippingSubdivision(Object.keys(subdivisions)[0]);
};
const fetchShippingOptions = async (
checkoutTokenId,
country,
// region = null
stateProvince
) => {
const options = await commerce.checkout.getShippingOptions(
checkoutTokenId,
{ country, stateProvince }
);
setShippingOptions(options);
setShippingOption(options[0].id);
};
useEffect(() => {
fetchShippingCountries(checkoutToken.id);
}, []);
useEffect(() => {
if (shippingCountry) fetchSubdivisions(shippingCountry);
}, [shippingCountry]);
useEffect(() => {
if (shippingSubdivision)
fetchShippingOptions(
checkoutToken.id,
shippingCountry,
shippingSubdivision
);
}, [shippingSubdivision]);
return (
<>
Shipping Address
<FormProvider {...methods}>
<form
onSubmit={methods.handleSubmit((data) =>
test({
...data,
shippingCountry,
shippingSubdivision,
shippingOption,
})
)}
>
Shipping Country
<Select
value={shippingCountry}
fullwidth='true'
onChange={(e) => setShippingCountry(e.target.value)}
>
{countries.map((country) => (
{country.label}
))}
Shipping Subdivision
<Select
value={shippingSubdivision}
fullwidth='true'
onChange={(e) => setShippingSubdivision(e.target.value)}
>
{subdivisions.map((subdivision) => (
{subdivision.label}
))}
Shipping Options
<Select
value={shippingOption}
fullwidth='true'
onChange={(e) => setShippingOption(e.target.value)}
>
{options.map((option) => (
{option.label}
))}
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
Back to Cart
Next
</>
);
};
export default AddressForm;