Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Not Found
Desktop design screenshot for the Interactive rating component coding challenge

This is a solution for...

  • HTML
  • CSS
  • JS
1newbie
View challenge

Design comparison


SolutionDesign

Solution retrospective


I have a problem with the buttons, i cannot select just only one although i used useState and other methods. Once clicked every button is selected. Could you please help me ?

Community feedback

nicodes 240

@nicodes-dev

Posted

Hi Elisabeth! I'm non-native english speaker so please bear with me. I review your code and it seems like you are a beginner in React but I assume you know "props" and "state". First let's identify what is the problem.

"I cannot select just only one although i used useState and other methods. Once clicked every button is selected."

The buttons are working fine, the problem is that the class "selected" applies to all buttons because of the conditional statement in the className.

className={isActive ? "selected" : ""}

In your code, isActive is a boolean which you set to true if "any" button is clicked, so all the buttons have the class 'selected' applied to it.

To fix this, use the selectedNumber state instead.

className={selectedNumber === '1' ? 'selected' : ''} //the class will only apply to the button which holds the value 1

You are also passing the whole event object in setSelectedNumber and you only use extract the value in the <p> tag.

const handleClick = (numberSelected) => {
    setSelectedNumber(numberSelected) 
}

<p className="result">You selected {selectedNumber.target.value} out of 5</p>

To fix this, you should extract the value and pass it in the setSelectedNumber.

const handleClick = (event) => {
    const value = event.target.value
    setSelectedNumber(value ) 
}

<p className="result">You selected {selectedNumber} out of 5</p>

The snippets above should be able to fix the problem.

Now to help you clean your code, I have written the snippets below.

This might be too long so you can just paste it in your code and then review it.

In your Rating component, you initialize the selectedNumber as a number which value is 0.

const [selectedNumber, setSelectedNumber] = useState(0);

When you get the value from the event object, any value will be converted to a string. So you can just initialize it with an empty string.

const [selectedNumber, setSelectedNumber] = useState("");

Then you can remove the isActive state because we will be using the selectedNumber to add the "selected" class. You also have to change the handleSubmit function. Your code should look like this

const [selectedNumber, setSelectedNumber] = useState(")
const [success, setSuccess] = useState(false)

const handleClick = event => {
   setSelectedNumber(event.target.value)
}

const handleSubmit = () => {
    // you can just check the length we initialize selectedNumber as a string.
    if (selectedNumber.length === 0) {
      alert('Please select a rating!')
    } else {
      setSuccess(true)
    }
  }

You can also remove this line of codes since this is not the proper way to write inline styles in react.

  let rating_app = document.querySelector('.rating_app')
  let submit_btn = document.querySelector('.submit-btn')

rating_app.style.display = 'none'
submit_btn.style.display = 'none'

You can directly apply it to the element without having to use a querySelector.

let successComponent = null 

if (success) {
  successComponent = (
     <div>
        <img src={img}/>
        <p className="result">You selected {selectedNumber} out of 5</p>
        <h1>Thank you !</h1>
        <p>We appreciate you taking the time to give a rating. If you ever need
          more support, don't hesitate to get in touch!</p>
      </div>
    )
}

Then in the return statement, we will use a ternary operator to render either successComponent or the rating div. Note: I remove the key and id attribute in your button because it is not needed in this solution.

return (
    <div className="container">
      <div className="card">
        {success ? (
          <div className="successComponent">{successComponent}</div>
        ) : (
          <>
            <div className="rating_app">
              <img src={icon} className="icon" alt="icon" />
              <h1>How did we do ? </h1>
              <p>Please let us know how we did with your support request. 
                  All feedback is appreciated to help us improve our offering!</p>
              <div className="ratings">
                <div className="circle">
                  <button   
                    className={setSelectedNumber === '1' ? 'selected' : ''}
                    onClick={handleClick}
                    value="1"
                  >
                    1
                  </button>
                </div>
                <div className="circle">
                  <button
                    className={setSelectedNumber === '2' ? 'selected' : ''}
                    onClick={handleClick}
                    value="2"
                  >
                    2
                  </button>
                </div>
                <div className="circle">
                  <button
                    className={setSelectedNumber === '3' ? 'selected' : ''}
                    onClick={handleClick}
                    value="3"
                  >
                    3
                  </button>
                </div>
                <div className="circle">
                  <button
                    className={setSelectedNumber === '4' ? 'selected' : ''}
                    onClick={handleClick}
                    value="4"
                  >
                    4
                  </button>
                </div>
                <div className="circle">
                  <button
                    className={setSelectedNumber === '5' ? 'selected' : ''}
                    onClick={handleClick}
                    value="5"
                  >
                    5
                  </button>
                </div>
              </div>
            </div>
            <button className="submit-btn" onClick={handleSubmit}>
              Submit
            </button>
          </>
        )}
      </div>

You can also store the values that you are going to use in the buttons in an array and then map it's value.

const btnArrays = ['1', '2', '3', '4', '5'].map((value, index) => {
    return (
      <div className="circle" key={index}>
        <button
          className={selectedNumber === value ? 'selected' : ''}
          onClick={handleClick}
          value={value}
        >
          {value}
        </button>
      </div>
    )
  })

Then use it to render the buttons.

return (
    <div className="container">
      <div className="card">
        {success ? (
          <div className="successComponent">{successComponent}</div>
        ) : (
          <>
            <div className="rating_app">
              <img src={icon} className="icon" alt="icon" />

              <h1>How did we do ? </h1>
              <p>
                Please let us know how we did with your support request. All
                feedback is appreciated to help us improve our offering!
              </p>

              <p className="results"></p>
              <div className="ratings">{btnArrays}</div>
            </div>
            <button className="submit-btn" onClick={handleSubmit}>
              Submit{' '}
            </button>
          </>
        )}
      </div>
  )

You can also separate the successComponent and btnsArray into another component. Then pass down the values you wish to pass to the component as props, remember that the Rating component holds the states.

ButtonComponents.jsx

const btnArrays = ['1', '2', '3', '4', '5']

const ButtonComponent = ({ selectedNumber, handleClick }) => {
  return btnArrays.map((value, index) => {
    return (
      <div className="circle" key={index}>
        <button
          className={selectedNumber === value ? 'selected' : ''}
          onClick={handleClick}
          value={value}
        >
          {value}
        </button>
      </div>
    )
  })
}

export default ButtonComponent

SuccessComponent.jsx

const SuccessComponent = ({ img, selectedNumber }) => {
  return (
    <div className="successComponent">
      <div>
        <img src={img}></img>
        <p className="result">You selected {selectedNumber} out of 5</p>
        <h1>Thank you !</h1>
        <p>
          We appreciate you taking the time to give a rating. If you ever need
          more support, don't hesitate to get in touch!
        </p>
      </div>
    </div>
  )
}

export default SuccessComponent

Then your Rating component should look like this.

Rating.jsx

import { useState } from 'react'
import icon from '../assets/images/icon-star.svg'
import img from '.././assets/images/illustration-thank-you.svg'
import '../App.css'
import ButtonComponent from './ButtonComponent'
import SuccessComponent from './SucessComponent'

const Rating = () => {
  const [selectedNumber, setSelectedNumber] = useState('')
  const [success, setSuccess] = useState(false)

  const handleClick = event => {
    setSelectedNumber(event.target.value)
  }

  const handleSubmit = () => {
    if (selectedNumber.length === 0) {
      alert('Please select a rating!')
    } else {
      setSuccess(true)
    }
  }

  return (
    <div className="container">
      <div className="card">
        {success ? (
          <SuccessComponent img={img} selectedNumber={selectedNumber} />
        ) : (
          <>
            <div className="rating_app">
              <img src={icon} className="icon" alt="icon" />

              <h1>How did we do ? </h1>
              <p>
                Please let us know how we did with your support request. All
                feedback is appreciated to help us improve our offering!
              </p>

              <p className="results"></p>
              <div className="ratings">
                {
                  <ButtonComponent
                    handleClick={handleClick}
                    selectedNumber={selectedNumber}
                  />
                }
              </div>
            </div>
            <button className="submit-btn" onClick={handleSubmit}>
              Submit{' '}
            </button>
          </>
        )}
      </div>
  )
}

export default Rating

and finally, your App.jsx should not have any state, since your declare those in the Rating component.

import { React, useState } from 'react'
import Rating from './components/Rating.jsx'

import './App.css'

function App() {
  //const [success, setSuccess] = useState(true);
  //const [selectedNumber, setSelectedNumber] = useState(0);

  return (
    <>
      <Rating />
    </>
  )
}

export default App

You can copy and paste all those snippets since I tested it first.

Marked as helpful

3

@elic4vet

Posted

@nicodes-dev Thank you for your help and your time :) Your answer helped me a lot !! :)

1
nicodes 240

@nicodes-dev

Posted

@elic4vet Thank you 😀

0
P
Curtis 890

@webguy83

Posted

Using React for this kind of simple widget is definitely way beyond overkill. A much more simple approach to this can be to make a simple HTML form with 5 radio buttons along with a submit button and using css to style them. The only JavaScript you'd need is an submit button handler to detect the value selected. This functionality is already done for you using radio buttons.:). No need to bring React in to complicate it.

0

@FedeNicoletti

Posted

Hi! It looks like the issue is with the isActive state. Currently, you are using a single isActive state for all buttons, which means that when you click on any button, all buttons will be toggled to the same state. To fix this, you need to have a separate state for each button to keep track of its selected status. Maybe you can try something like this:

import React, { useState } from "react";
import icon from "../assets/images/icon-star.svg";
import img from ".././assets/images/illustration-thank-you.svg";
import "../App.css";

const Rating = () => {
  const [selectedNumber, setSelectedNumber] = useState(0);
  const [success, setSuccess] = useState(false);

  const handleClick = (numberSelected) => {
    setSelectedNumber(numberSelected);
  };

  const handleSubmit = () => {
    if (selectedNumber === 0) {
      alert("Please select a rating!");
    } else {
      setSuccess(true);
    }
  };

  const ratingButtons = Array.from({ length: 5 }, (_, index) => index + 1);

  let successComponent = null;
  if (success) {
    successComponent = (
      <div>
        <img src={img} alt="Success" />
        <p className="result">You selected {selectedNumber} out of 5</p>
        <h1>Thank you!</h1>
        <p>
          We appreciate you taking the time to give a rating. If you ever need
          more support, don't hesitate to get in touch!
        </p>
      </div>
    );
  }

  return (
    <div className="container">
      <div className="card">
        <div className="successComponent">{successComponent}</div>
        <div className="rating_app">
          <img src={icon} className="icon" alt="icon" />

          <h1>How did we do?</h1>
          <p>
            Please let us know how we did with your support request. All
            feedback is appreciated to help us improve our offering!
          </p>

          <p className="results"></p>
          <div className="ratings">
            {ratingButtons.map((number) => (
              <div className="circle" key={number}>
                <button
                  className={selectedNumber === number ? "selected" : ""}
                  onClick={() => handleClick(number)}
                  value={number}
                >
                  {number}
                </button>
              </div>
            ))}
          </div>
        </div>
        <button className="submit-btn" onClick={handleSubmit}>
          Submit
        </button>
      </div>

      <div className="attribution">
        Challenge by{" "}
        <a
          href="https://www.frontendmentor.io?ref=challenge"
          target="_blank"
          rel="noreferrer"
        >
          Frontend Mentor
        </a>{" "}
        Coded by{" "}
        <a href="https://www.linkedin.com/in/eerkekoglou/">Elisabeth Erkekoglou</a>
      </div>
    </div>
  );
};

export default Rating;

0

Please log in to post a comment

Log in with GitHub
Discord logo

Join our Discord community

Join thousands of Frontend Mentor community members taking the challenges, sharing resources, helping each other, and chatting about all things front-end!

Join our Discord