0

I am making a pricing calculator on my site with 3 different options for calculation. I'd like the three categories at the top of the screenshot included to show the respective section (and make the others invisible) and turn that specific button black (it currently turns black on hover but not when clicked) and the others back to grey. Also screenshotted is an example of this working on Airtable's product page.

My script is below; I've been trying to make this work with useState and an onClick function as this is the recommended solution I've found in my research (linked one example of a few similar answers). However, if there is another more suitable approach I appreciate the advice.

import React, { useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import useWindowPosition from '../../hook/useWindowPosition';
import Typography from '@material-ui/core/Typography';
import TextField from '@material-ui/core/TextField';
import Switch from '@material-ui/core/Switch';

const useStyles = makeStyles((theme) => ({
root: {
  background: 'white',
  paddingTop: '30px',
  paddingBottom: '60px',
  marginBottom: '-80px',
},
    cardRoot: {
        width: '90vw',
        background: 'white',
        marginTop: '20px',
        marginBottom: '20px',

    }, 
    calculator: {
        display: 'flex',
        marginLeft: '10vw',
        marginTop: '5vh',
        [theme.breakpoints.down('md')]: {
          flexDirection: 'column',
        }, 
    },
    spacing: {
        marginTop: '10vh',
        marginLeft: '10vw',
    },
    header: {
      fontFamily: 'Nunito',
      fontWeight: 'bold',
      fontSize: '2rem',
      color: '#000',
      marginRight: '30px',
    },
    title: {
      fontFamily: 'Nunito',
      fontWeight: 'regular',
      fontSize: '1.5rem',
      color: '#000',
      marginRight: '30px',
    },
    price: {
      fontFamily: 'Nunito',
      fontWeight: 'regular',
      fontSize: '2rem',
      color: '#000',
      marginRight: '30px',
    },
    liststyle: {
      fontFamily: "Nunito",
      fontSize: "1rem",
      margin: '10px 10px',
    },
    list: {
      display: "flex",
      marginLeft: '8vw',

    },
    sections: {
      textDecoration: 'none',
      fontWeight: 'bold',
      color: '#B6B6B6',
      '&:hover': {
        backgroundColor: '#fff',
        color: '#000',
    },
    '&:clicked': {
      backgroundColor: '#fff',
      color: '#000',
  },
    },
}));


export default function () {
  const classes = useStyles();

const [state, setState] = useState({
    ImageNumber: '',
    checkedA: false,
    LabelImagesPrice: '',
    AnimalNumber: '',
    AnimalNumberPrice: '',
    DatasetImageNumber: '',
    DatasetAnimalNumber: '',
    DatasetModelPrice: '',
  });

  const [show, setShow] = useState({
    LabelImages: true,
    CustomModel: false,
    DatasetModel: false,
  })

  const onClick = () => setShow(true)

  const handleSwitchChange = (event) => {
    setState({ ...state, [event.target.name]: event.target.checked });
  };

  const handleChange = (event) => {
      console.log(event.target.name);
    setState({
      ...state,
      [event.target.name]: event.target.value,
    });
  };

  return (
    <section id="pricingcalc" data-scroll-id="pricingcalc" backgroundColor="white">
<div className={classes.root}>
<div className={classes.calculator}>
    <Typography
              gutterBottom
              variant="h5"
              component="h1"
              className={classes.header}
            >
              Pricing Calculator
              </Typography>
</div>
<div>
<ul className={classes.list} style={{ listStyleType: "none" }}>
              <li className={classes.liststyle}>
                <a className={classes.sections} href="#labelimages" onClick={onClick}>
                  Label Images
                </a>
              </li>
              <li className={classes.liststyle}>
                <a className={classes.sections} href="#custommodel" onClick={onClick}>
                  Custom Model
                </a>
              </li>
              <li className={classes.liststyle}>
                <a className={classes.sections} href="#datasetmodel" onClick={onClick}>
                  Specialized Model
                </a>
              </li>
            </ul>
</div>
<div className={classes.calculator} name="LabelImages">

    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.title}
            >
              Number of Images
              </Typography>
        <TextField label="" name="ImageNumber" type="text" value={state.ImageNumber} variant="outlined" onChange={(e) => handleChange(e)} />
    </div> 
    <div className={classes.calculator}>
    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.title}
            >
              Human verified?
              </Typography>
    <Switch checked={state.checkedA} color="primary" onChange={handleSwitchChange} name="checkedA" />
</div>
    <div className={classes.calculator}>
    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.price}
            >
              Price
              </Typography>
              <TextField label="$ (USD)" name="LabelImagesPrice" type="text" value={state.ImageNumber*10 + state.checkedA*99} disabled variant="outlined" onChange={(e) => handleChange(e)} />
    </div>
    <div className={classes.calculator} name="CustomModel">

    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.title}
            >
              Number of Animals in Model
              </Typography>
        <TextField label="" name="AnimalNumber" type="text" value={state.AnimalNumber} variant="outlined" onChange={(e) => handleChange(e)} />
    </div> 
    <div className={classes.calculator}>
    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.price}
            >
              Price
              </Typography>
              <TextField label="$ (USD)" name="AnimalNumberPrice" disabled type="text" value={state.AnimalNumber*15} disabled variant="outlined" onChange={(e) => handleChange(e)} />

    </div>
    <div className={classes.calculator} name="DatasetModel">

    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.title}
            >
              Number of Images in Training Dataset
              </Typography>
        <TextField label="" name="DatasetImageNumber" type="text" value={state.DatasetImageNumber} variant="outlined" onChange={(e) => handleChange(e)} />
    </div> 
    <div className={classes.calculator}>

<Typography
          gutterBottom
          variant="h6"
          component="h1"
          className={classes.title}
        >
          Number of Animals in Model
          </Typography>
    <TextField label="" name="DatasetAnimalNumber" type="text" value={state.DatasetAnimalNumber} variant="outlined" onChange={(e) => handleChange(e)} />
</div> 
    <div className={classes.calculator}>
    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.price}
            >
              Price
              </Typography>
      <TextField label="$ (USD)" name="DatasetModelPrice" type="text" disabled value={state.DatasetImageNumber*10 + state.DatasetAnimalNumber*2} variant="outlined" onChange={(e) => handleChange(e)} />
    </div>
    </div>
    </section>
  );
}

enter image description here

enter image description here

Updated script:

import React, { useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import useWindowPosition from '../../hook/useWindowPosition';
import Typography from '@material-ui/core/Typography';
import TextField from '@material-ui/core/TextField';
import Switch from '@material-ui/core/Switch';

const useStyles = makeStyles((theme) => ({
root: {
  background: 'white',
  paddingTop: '30px',
  paddingBottom: '60px',
  marginBottom: '-80px',
},
    cardRoot: {
        width: '90vw',
        background: 'white',
        marginTop: '20px',
        marginBottom: '20px',

    }, 
    calculator: {
        display: 'flex',
        marginLeft: '10vw',
        marginTop: '5vh',
        [theme.breakpoints.down('md')]: {
          flexDirection: 'column',
        }, 
    },
    spacing: {
        marginTop: '10vh',
        marginLeft: '10vw',
    },
    header: {
      fontFamily: 'Nunito',
      fontWeight: 'bold',
      fontSize: '2rem',
      color: '#000',
      marginRight: '30px',
    },
    title: {
      fontFamily: 'Nunito',
      fontWeight: 'regular',
      fontSize: '1.5rem',
      color: '#000',
      marginRight: '30px',
    },
    price: {
      fontFamily: 'Nunito',
      fontWeight: 'regular',
      fontSize: '2rem',
      color: '#000',
      marginRight: '30px',
    },
    liststyle: {
      fontFamily: "Nunito",
      fontSize: "1rem",
      margin: '10px 10px',
    },
    list: {
      display: "flex",
      marginLeft: '8vw',

    },
    sections: {
      textDecoration: 'none',
      fontWeight: 'bold',
      color: '#B6B6B6',
      '&:hover': {
        backgroundColor: '#fff',
        color: '#000',
    },
    '&:clicked': {
      backgroundColor: '#fff',
      color: '#000',
  },
    },
}));


export default function () {
  const classes = useStyles();
  const checked = useWindowPosition('header');

const [state, setState] = useState({
    ImageNumber: '',
    checkedA: false,
    LabelImagesPrice: '',
    AnimalNumber: '',
    AnimalNumberPrice: '',
    DatasetImageNumber: '',
    DatasetAnimalNumber: '',
    DatasetModelPrice: '',
  });

  const [show, setShow] = useState({
    LabelImages: true,
    CustomModel: false,
    DatasetModel: false,
  })

  const onClick = () => setShow(true)

  const handleSwitchChange = (event) => {
    setState({ ...state, [event.target.name]: event.target.checked });
  };

  const handleChange = (event) => {
      console.log(event.target.name);
    setState({
      ...state,
      [event.target.name]: event.target.value,
    });
  };

  return (
    <section id="pricingcalc" data-scroll-id="pricingcalc" backgroundColor="white">
<div className={classes.root}>
<div className={classes.calculator}>
    <Typography
              gutterBottom
              variant="h5"
              component="h1"
              className={classes.header}
            >
              Pricing Calculator
              </Typography>
</div>
<div>
<ul className={classes.list} style={{ listStyleType: "none" }}>
              <li className={classes.liststyle}>
              <a 
                style = {show.labelImages ? {color: 'black'} : {color: 'grey'}} 
                className={classes.sections} 
                href="#labelimages" 
                onClick={onClick}
              >
                Label Images
              </a>
              </li>
              <li className={classes.liststyle}>
                <a 
                style={show.customModel ? {color: 'black'} : {color: 'grey'}}
                className={classes.sections} 
                href="#customModel" 
                onClick={onClick}
                >
                  Custom Model
                </a>
              </li>
              <li className={classes.liststyle}>
                <a 
                style={show.datasetModel ? {color: 'black'} : {color: 'grey'}}
                className={classes.sections} 
                href="#datasetModel" 
                onClick={onClick}
                >
                  Specialized Model
                </a>
              </li>
            </ul>
</div>
{show.labelImages && <div className={classes.calculator} name="CustomModel">
    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.title}
            >
              Number of Images
              </Typography>
        <TextField label="" name="ImageNumber" type="text" value={state.ImageNumber} variant="outlined" onChange={(e) => handleChange(e)} />
    </div>} 
    {show.labelImages && <div className={classes.calculator} name="CustomModel">
    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.title}
            >
              Human verified?
              </Typography>
    <Switch checked={state.checkedA} color="primary" onChange={handleSwitchChange} name="checkedA" />
</div>}
{show.labelImages && <div className={classes.calculator} name="CustomModel">
    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.price}
            >
              Price
              </Typography>
              <TextField label="$ (USD)" name="LabelImagesPrice" type="text" value={state.ImageNumber*10 + state.checkedA*99} disabled variant="outlined" onChange={(e) => handleChange(e)} />
    </div>}

{show.customModel && <div className={classes.calculator} name="CustomModel">
    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.title}
            >
              Number of Animals in Model
              </Typography>
        <TextField label="" name="AnimalNumber" type="text" value={state.AnimalNumber} variant="outlined" onChange={(e) => handleChange(e)} />
    </div>}

{show.customModel && <div className={classes.calculator} name="CustomModel">
    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.price}
            >
              Price
              </Typography>
              <TextField label="$ (USD)" name="AnimalNumberPrice" disabled type="text" value={state.AnimalNumber*15} disabled variant="outlined" onChange={(e) => handleChange(e)} />
    </div>}

{show.datasetModel && <div className={classes.calculator} name="DatasetModel">

    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.title}
            >
              Number of Images in Training Dataset
              </Typography>
        <TextField label="" name="DatasetImageNumber" type="text" value={state.DatasetImageNumber} variant="outlined" onChange={(e) => handleChange(e)} />
    </div>}

{show.datasetModel && <div className={classes.calculator} name="DatasetModel">
<Typography
          gutterBottom
          variant="h6"
          component="h1"
          className={classes.title}
        >
          Number of Animals in Model
          </Typography>
    <TextField label="" name="DatasetAnimalNumber" type="text" value={state.DatasetAnimalNumber} variant="outlined" onChange={(e) => handleChange(e)} />
</div>}

{show.datasetModel && <div className={classes.calculator} name="DatasetModel">
    <Typography
              gutterBottom
              variant="h6"
              component="h1"
              className={classes.price}
            >
              Price
              </Typography>
      <TextField label="$ (USD)" name="DatasetModelPrice" type="text" disabled value={state.DatasetImageNumber*10 + state.DatasetAnimalNumber*2} variant="outlined" onChange={(e) => handleChange(e)} />
    </div>}
    </div>
    </section>
  );
}
Henrik
  • 191
  • 1
  • 17

1 Answers1

1

For each of the sections you can do something like:

{show.labelImages && <div className={classes.calculator} name="LabelImages"></div>}

and to get the buttons to turn black grey you can use a style tag like:

<a 
   style = {show.labelImages ? {color: 'black'} : {color: 'grey'} 
   className={classes.sections} 
   href="#labelimages" 
   onClick={onClick}
 >
   Label Images
 </a>
WebbH
  • 2,379
  • 1
  • 15
  • 26
  • I have an issue where wrapping my `
    ` in curly brackets `{ }` causes the whole enclosed scope to show the error `JSX expressions must have one parent element`. How do I go about this?
    – Henrik Sep 09 '21 at 14:24
  • Just wrap the whole return statement in a React Fragment: `<>>` – WebbH Sep 09 '21 at 14:28
  • ^That worked to clean up the error! Unfortunately, the second part of the answer isn't working right for me. Now each of the 3 sections are not visible and clicking the category buttons neither shows the respective section, nor turns the button black – Henrik Sep 09 '21 at 14:43
  • Could it be a boolean issue with `labelImages` vs. `LabelImages`? I've tried both options which doesn't change anything so far – Henrik Sep 09 '21 at 14:44
  • I've added my updated script to the original post to show the additions from your answer, perhaps I've implemented it wrong – Henrik Sep 09 '21 at 14:45
  • Managed to figure out a workaround by creating 3 separate `onClick` functions for showing/hiding each of the three categories. Might not be the most efficient but it works, thank you! – Henrik Sep 09 '21 at 17:30