0

I'm working on a billing app. I have managed to fetch Products from an API.. now i want to calculate the total price and display it every time the user click's on either the add or minus button.

I tried to use addEventListener() and onClick() but neither of these two worked with me, am probably doing something wrong but i am not sure what is it!

I would really appreciate some help or feedback, thanks.

enter image description here

Here's my code: Sorry if my code is messy, i'm still learning Javascript and React.js.

    import React, { useState } from "react";
import "./Bill.css";
import { Link, useParams, Switch, Route } from "react-router-dom";
import { connect } from "react-redux";
import { getItems } from "../store/actions/itemsActions";


function BillList({  items }) {
  

  const [counter, setCounter] = useState(1);

 
  // will display the current number

  function Display(props) {
    return <label style={{ marginLeft: ".5rem" }}>{props.message}</label>;
  }


    const params = useParams();
    return (
      <div className="bills">
        <div
          className="main-title"
          style={{
            textAlign: "center",
            justifyContent: "center",
            alignItems: "center",
            fontSize: 14,
          }}
        >
          
          <h1>Bakery</h1>
          <h1>Company Gbr</h1>
          <h1>Oranienburger Straße 120</h1>
          <h1>10119 Berlin</h1>
        </div>
        
  
        <div className="bills-container">
          <div></div>
  
          {/* pass in the details  */}
          <div className="item-list">
            {items &&
              items.items &&
              items.items.map((item) => (
                <React.Fragment key={item.id}>
                 
                  <div className="bill-time">
                    <div className="bill">
                      <h4>
                        {" "}
                        <strong>Bill: </strong>
                        {item.billNumber}
                      </h4>
                    </div>
                    
  
                   
                    {/* <div style={{flex: 1,textAlign: 'right'}} className="time-date"> */}
                    <div className="time">
                      <h4>
                        {" "}
                        <strong>Time: </strong>
                        {item.created_datetime}
                      </h4>
                    </div>
                  </div>
                  ----------------------------------
                  ----------------------------------
                  ---------------------------------- --------------------
                  {/* Counter  */}
                  <div className="price-total">
                    <div className="title">
                      <h3>
                        {" "}
                         <strong>Title: </strong>
                        {item.title}
                      </h3>
                      <div className="counter">
                      <strong><Display message={counter}/>x</strong>
                      </div>
                    </div>
  
                    <div className="increase">
                    <button onClick={() => setCounter(counter + 1)}>+</button>
                      
                    </div>
                    <div className="decrease">
                    <button onClick={() => setCounter(counter - 1)}>-</button>
                    </div>
  
                    {/* Price and total */}
  
                    <div className="price">
                      <h4>
                        <strong>Price: {parseFloat(item.price)}$</strong>
                      </h4>
                    </div>
  
                    <div className="total">
                      
                      <h4>
                      Total: {parseFloat(item.price*counter)}$
                      </h4>
                    </div>
                  </div>
                  
                </React.Fragment>
              ))}
          </div>
        </div>
  
        <div className="button-path">
          <Link to="/">
            <div className="button">
              <button className="main-button">Analyse Receipt</button>
            </div>
          </Link>
        </div>
  
        <Switch>
          <Route path="/bills/:id" /> 
        </Switch>
        <div>ID: {params.id}</div>
  
        
      </div>
    );
  
  }
  


const mapStateToProps = (state) => {
  return {
    items: state.items,
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    getItems: () => dispatch(getItems()),
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(BillList);
karim
  • 75
  • 1
  • 10

2 Answers2

1

You will need to store the total price in some kind of state:


const [totalPrice, setTotalPrice] = useState(0);

You will then be able to update the total price by either...

  1. returning the desired summation from that UpdateTotalPrice function and wrapping it in a setTotalPrice:
setTotalPrice(UpdateTotalPrice(event));
  1. Or, using setTotalPrice therein.

Once you have that, you can use that setTotalPrice logic in some kind of event handler.

const handleClick = ()=>{
   // total price update logic
}

It looks like you may want UpdateTotalPrice to be that handler, which works just as well. But, whatever the handler may be, you then need to pass it as the onClick prop for your Buttons.

onClick={handleClick}

Couple additional notes:

  1. You are mixing imperative Javascript with React. You'll have an easier time if you conform to React's (generally) declarative style. This post might help.
  2. Use const instead of let or var.

Edit: Sorry, it looks like you would like to be using redux to manage your state. In that case, you will need make use of your dispatch and a useSelector. The pattern remains the same though.

lmonninger
  • 831
  • 3
  • 13
  • Also, his `UpdateTotalPrice` function does not return `Total`, it just `console.log`s it. – Dillan Wilding Aug 27 '21 at 15:31
  • @Dillan Wilding Yeah, noticed that. Let me bold the returning bit... – lmonninger Aug 27 '21 at 15:33
  • @Imonninger It also looks like he's using redux for state management and has total price there. – Dillan Wilding Aug 27 '21 at 15:36
  • Thanks for the additional notes and the post they were really helpful ....I used the state approach instead of the redux, i'm also still learning it so i'm kinda confused ....sorry if i didn't mention the redux part....so i created the state and passed the **setTotalPrice(UpdateTotalPrice(e));** but nothing happens when i click on the buttons, it just displays 0 because of the **useState**, do you think it's because of the **currentTarget** ? maybe i need to change it to **onClick**! – karim Aug 27 '21 at 16:00
  • @karimtariq Yeah, should have clarified that. You will need to trigger some kind of handler that will call `setTotalPrice`, let me update my response. It looks like you want `UpdateTotalPrice` to be that handler... – lmonninger Aug 27 '21 at 16:28
  • Thanks, it's working fine now... i just had a question is there any draw backs with this approach in contrast to redux ? – karim Aug 27 '21 at 17:12
  • 1
    The biggest drawback is that your *state is restricted in context to the component in which it is created*. If this is a component that just needs to know the total price for a UI output but may need to share this total price with other components, then go with the `Context API`. If this total price needs to communicate with some backend, then I might do `Redux`, but you can accomplish the same with `Context`. Hope that helps! Separation of concerns can be tricky in React! – lmonninger Aug 27 '21 at 19:03
1

Did you try that? I can't see why it wouldn't work

Total: {parseFloat(item.price*counter)}$

Extract your item to a component:

function Item({item}) {
    const [counter, setCounter] = useState(1)
    return (
        <div>
           ...
           <Button onClick={() => setCounter(counter + 1)}>+</Button>
           <Button onClick={() => setCounter(counter - 1)}>-</Button>
           ...
           Total: {parseFloat(item.price*counter)}$
           ...
        </div>
    )
}