Reputation: 45
Basically I'm creating an e-commerce test site by linking it with stripe and Commercejs. Everything works up until the checkout form loads. I am able to input information, however, upon the page being loaded I get the error:
"Unhandled Rejection (TypeError): Cannot read property 'id' of undefined" for only one line of code. Which is:
setShippingOption(options[0].id);
That code was nested in:
const fetchShippingOptions = async (checkoutTokenId, country, stateProvince = null) => {
const options = await commerce.checkout.getShippingOptions(checkoutTokenId, { country, region: stateProvince });
setShippingOptions(options);
setShippingOption(options[0].id);
};
This code is essentially for the address form, which follows:
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 './FormInput';
const AddressForm = ({ checkoutToken, next }) => {
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 fetchShippingCountries = async (checkoutTokenId) => {
const { countries } = await commerce.services.localeListShippingCountries(checkoutTokenId);
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, stateProvince = null) => {
const options = await commerce.checkout.getShippingOptions(checkoutTokenId, { country, region: 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 (
<>
<Typography variant="h6" gutterBottom>Shipping address</Typography>
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit((data) => next({ ...data, shippingCountry, shippingSubdivision, shippingOption }))}>
<Grid container spacing={3}>
<FormInput required name="firstName" label="First name" />
<FormInput required name="lastName" label="Last name" />
<FormInput required name="address1" label="Address line 1" />
<FormInput required name="email" label="Email" />
<FormInput required name="city" label="City" />
<FormInput required name="zip" label="Zip / Postal code" />
<Grid item xs={12} sm={6}>
<InputLabel>Shipping Country</InputLabel>
<Select value={shippingCountry} fullWidth onChange={(e) => setShippingCountry(e.target.value)}>
{Object.entries(shippingCountries).map(([code, name]) => ({ id: code, label: name })).map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.label}
</MenuItem>
))}
</Select>
</Grid>
<Grid item xs={12} sm={6}>
<InputLabel>Shipping Subdivision</InputLabel>
<Select value={shippingSubdivision} fullWidth onChange={(e) => setShippingSubdivision(e.target.value)}>
{Object.entries(shippingSubdivisions).map(([code, name]) => ({ id: code, label: name })).map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.label}
</MenuItem>
))}
</Select>
</Grid>
<Grid item xs={12} sm={6}>
<InputLabel>Shipping Options</InputLabel>
<Select value={shippingOption} fullWidth onChange={(e) => setShippingOption(e.target.value)}>
{shippingOptions.map((sO) => ({ id: sO.id, label: `${sO.description} - (${sO.price.formatted_with_symbol})` })).map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.label}
</MenuItem>
))}
</Select>
</Grid>
</Grid>
<br />
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<Button component={Link} variant="outlined" to="/cart">Back to Cart</Button>
<Button type="submit" variant="contained" color="primary">Next</Button>
</div>
</form>
</FormProvider>
</>
);
};
export default AddressForm;
Aside from this, that was the only error I was receiving.
Just a side note, I'm still fairly new to JavaScript, I'm in my first year of university.
Upvotes: 1
Views: 889
Reputation: 138
Just ran into your problem and fixed it. I also used the same resource as you.
If you console.log(options) in your fetchShippingOptions const, you'll probably see a description value with Domestic or International. These are your shipping categories.
Depending on your CommerceJS setup, one of these is selected by default. When the default it selected, it tries to load your subdivisions immediately.
Here's the problem: if you try to render subdivisions that don't mesh with your backend, it will consider the value undefined. So, you have to go to the Shipping Options in your Commerce JS profile and ensure that all subdivisions for every shipping option are available on your account (so that your API key can properly read the back-end values).
Do you have a Shipping entry that you forgot to enable all the regions on? That's what I had. Remember, in your form you're mapping all of the subdivisions. That doesn't necessarily mean that, when you try to push data with your API, all of the back-end endpoints are properly connected.
So, go to your Commerce JS account and check your Shipping Options for this project. If any entry shows less Regions than they should, the entry is not properly housing your endpoints and will end up unable to read the values.
Upvotes: 2
Reputation: 11
Edit de United States zone and in add/edit countries make sure to add all of the 57 regions.
Upvotes: 0
Reputation: 21
Make sure that the countries in your Commercejs shipping settings have all of the correct regions. I was using the United States but noticed that I only had 2 regions enabled.
Upvotes: 2
Reputation: 11
Check the shipping setups at dashboard you might be missing the subdivisions
Upvotes: 0