'React js ecommerce price change when size and material variants option selected

I am trying to get the final price in the productInfo page when the material and size variants options are selected. In the data.js:

export const productItems = [
    {
        id: 1,
        image: ["../Images/Prod1/Swiming_fish_W.png","../Images/Prod1/Ocean Fish2.png"],
        title: "Swim Fish",
        price:49.99,
        desc: "Simplicty, Naturality, and Humanity of Art",
        variants: [{material: "Stretched Canvas", size: "12x16 inches", price: 49},
                   {material: "Stretched Canvas", size: "15x20 inches",  price: 69},
                   {material: "Fine Art Print", size: "12x16 inches",  price:39},
                   {material: "Fine Art Print", size: "15x20 inches",  price: 59},
                  ],
        
    },

    {
        id: 2,
        image: ["../Images/Prod2/Duckling_W.png","../Images/Prod2/Duckling 2.png"],
        title: "Bath Duckling",
        price:49.99,
        desc: "Simplicty, Naturality, and Humanity of Art",
        variants: [{material: "Stretched Canvas",size: "20x24 inches",  price: 69},
                   {material: "Stretched Canvas",size: "24x30 inches",  price: 79},
                   {material: "Fine Art Print", size: "20x24 inches",  price:59},
                   {material: "Fine Art Print", size: "24x30 inches",  price: 69},
                   ],
    }]

In the detailProductPage.js

import React, { useEffect, useState } from 'react';
// import { Col, Row } from 'antd';
import ProductImages from './ProductImages';
import ProductInfo from './ProductInfo';
import {productItems} from '../Data';
import { useParams } from 'react-router-dom';
import './DetailProductPage.css';


function DetailProductPage() {

    const { id }=useParams();
    const [details, setDetails]=useState([])
    
    useEffect(() => {
        setDetails(productItems.find(item => String(item.id) ===id ))
    
     }, [id]);
        
    return (
        <div className="postPage" style={{width:'100%', padding: '5rem 3rem'}}>

        <div className="detailInfo">
          <div className="detailLeft">
               <ProductImages detail={details} />
           </div>

           <div className="detailRight">
               <ProductInfo  detail={details} />
           </div>
        </div>
      </div>
  )
}

export default DetailProductPage

Finally in the ProductInfo.js

import React, {useEffect, useState} from 'react';
import { useStateValue } from '../StateProvider';
import './ProductInfo.css';
import Select from 'react-select';


function ProductInfo(props) {
  const [Product, setProduct] = useState({})
  const [{basket},dispatch]=useStateValue()

  const [size, setSize] = React.useState();
  const [material, setMaterial] = React.useState();
  const [price, setPrice] = React.useState();
  console.log(props.detail.variants)

  const materialOptions = props.detail.variants
    .map((p) => p.material)
    .filter((v, i, a) => a.indexOf(v) === i)
    .map((material) => ({ label: material, value: material }))
  console.log(materialOptions)

  const sizeOptions = props.detail.variants
    .map((p) => p.size)
    .filter((v, i, a) => a.indexOf(v) === i)
    .map((size) => ({ label: size, value: size }));
  console.log(sizeOptions)
  
  const priceOptions = props.detail.variants
    .filter((p) => size && p.size === size.value && material && p.material=== material.value)
    .map((p) => p.price)
    .filter((v, i, a) => a.indexOf(v) === i)
    .map((price) => ({ label: price, value: price }));
  console.log(priceOptions.length)

    useEffect(()=>{
        setProduct(props.detail)
      }, [props.detail])
    
return (
   <div className='prod__info'>
        
    <h1>{Product.title}</h1>
    <h5 className='prod__desc'>Description</h5>
    <p className='prod__text'>{Product.desc}</p>

    <p className='prod__price'>
            <small>$</small>
            if (priceOptions.length===1){
              priceOptions.value
            } else {Product.price} 
    </p>
    <br />
      <p className='prod__desc'>Material</p>
      <div style={{boxShadow: '0 5px 5px #939596',cursor:'pointer',borderRadius: '10px!'}}>
      <Select value={material} onChange={setMaterial} options={materialOptions} />
      </div>

      <p className='prod__desc'>Size</p>
      <div style={{boxShadow: '0 5px 5px #939596',cursor:'pointer',borderRadius: '10px!'}}>
      <Select value={size} onChange={setSize} options={sizeOptions} />
      
    </div>
    <br />
    <br />
    <div className='button__cart'>    
      <button className='prod__button'
          onClick={addToBasket}
        >
            Add to basket
    </button>
    </div>

</div>

)
}

export default ProductInfo

I have problems in getting the final price change after material and size variant options selected in ProductInfo.js

<p className='prod__price'>
            <small>$</small>
            if (priceOptions.length===1){
              priceOptions.value
            } else {Product.price} 
    </p>

For reference, my website is weiwhite.com, clicking on one of the painting for the product detail page.



Solution 1:[1]

In productInfo.js add a ? in front of .map:

//...
let finalPrice={}

if (priceOptions?.length === 1) {
  finalPrice = priceOptions.value
} else {
  finalPrice = Product.price
} 
//...
return
//...
<strong> finalPrice </strong>
//...

The question mark creates an Optional Chain.

The optional chaining operator (?.) enables you to read the value of a property located deep within a chain of connected objects without having to check that each reference in the chain is valid. - MDN

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Zach Jensz