Reputation: 366
With the help of a user here I was able to make a component, however now I need a variation of that component. The component is an increment / decrement button with some details:
1 - The button is in an array coming from an API
2 - The increment / decrement must follow a rule defined in the bank, that is, a maximum number of items
3 - A footer with the Buy button should appear automatically when one of the items exists
4 - When I click the Buy button, the items will be saved in the localStorage and a new screen will open, called a shopping cart that will contain the same increment / decrement buttons but with the items saved in the localStorage selected in the list and the buttons should increment / decrement the items and clicking the Confirm Purchase button the localStorage must be updated.
Until item 3 and half of item 4 I was able to do, but I'm having problem with the increment / decrement buttons. Below is the code for my components
//Change Quantity Button
import React from 'react';
import './ChooseQuantity.css';
const ChooseQuantity = ({ value, onChange, additionEnabled }) => {
const shouldIncrement = additionEnabled;
const shouldDecrement = value > 0;
const decrement = () => {
if (shouldDecrement) {
onChange(value - 1);
}
}
const increment = () => {
if (shouldIncrement) {
onChange(value + 1);
}
}
const decrementButton = shouldDecrement ? (
<button className="minus" onClick={decrement}>
<i className="fas fa-minus"></i>
</button>
) : <div className="space-button"></div>
const incrementButton = shouldIncrement ? (
<button className='plus' onClick={increment}>
<i className="fas fa-plus"></i>
</button>
) : <div className="space-button"></div>
return (
<div>
{decrementButton}
<span className="qtd">{value}</span>
{incrementButton}
</div>
)
}
ChooseQuantity.defaultProps = {
value: 0,
additionEnabled: true,
}
export default ChooseQuantity
//Lot Component
import React from 'react'
import ChooseQuantity from '../../components/ChooseQuantity/ChooseQuantity.js';
const Lot = ({
ticketName,
ticketPrevenda,
lotUniqueNumber,
ticketUniqueNumber,
name,
lot,
lotType,
lotNumber,
lotPrice,
lotPriceTax,
lotQuantity,
onQuantityChange,
additionEnabled,
maxPurchase,
separator = '/',
quantity,
newValue,
}) => {
const onQuantityChangeInternal = (newValue) => {
onQuantityChange(ticketName, ticketPrevenda, ticketUniqueNumber, lotType, lotNumber, lotUniqueNumber, lotPrice, lotPriceTax, newValue, lotQuantity, maxPurchase)
}
return (
<div className="row">
<div className="col-8">
<h5 className="lot-name">{name}</h5>
<h5 className="lot-name">
{
lotType === 'U' ? 'Unissex ' : ''
}
{
lotType === 'M' ? 'Masculino ' : ''
}
{
lotType === 'F' ? 'Feminino ' : ''
}
({lotNumber}º Lote)
</h5>
<h6 className="lot-price">
R$ {lotPrice.replace('.', ',')} <br />
<small>(R$ {lotPrice.replace('.', ',')} + R$ {lotPriceTax.replace('.', ',')})</small>
</h6>
</div>
<div className="col-4">
<ChooseQuantity
value={lotQuantity}
onChange={onQuantityChangeInternal}
additionEnabled={additionEnabled}
maxPurchase={maxPurchase}
lot={lot}
lotPrice={lotPrice}
lotPriceTax={lotPriceTax}
lotQuantity={lotQuantity}
newValue={newValue}
/>
</div>
</div>
)
}
export default Lot
import React, { Component } from 'react';
import Lot from '../Cart/Lot';
import './Cart.css';
import '../../components/Css/App.css';
import Header from '../../components/Header/Header';
const separator = '/';
class Cart extends Component {
constructor(props) {
super(props);
this.state = {
cart: [],
lot: [],
qtd: 0,
events: null,
banner_app: null,
event_name: null,
priceTotal: null,
quantity: null,
selectedQuantities: {},
maxTotalItems: 0,
}
}
async componentDidMount() {
const cart = JSON.parse(localStorage.getItem('cart'));
await this.setState({ cart: cart });
this.setState({ events: this.state.cart.events });
this.setState({ banner_app: this.state.cart.events.banner_app });
this.setState({ event_name: this.state.cart.events.name });
this.setState({ priceTotal: this.state.cart.total.price });
this.setState({ quantity: this.state.cart.total.totalQuantity });
this.setState({ lot: this.state.cart.events.tickets.lot });
this.setState({ maxTotalItems: this.state.events.max_purchase });
this.setState({ selectedLots: this.state.cart.events.tickets.lot });
}
onQuantityChange = (ticketName, ticketPrevenda, ticketUniqueNumber, lotType, lotNumber, lotUniqueNumber, lotPrice, lotPriceTax, newValue, lotQuantity) => {
// console.log(lotQuantity);
this.setState(prevState => {
this.setState({
selectedQuantities: { ...prevState.selectedQuantities, [`${ticketName}${separator}${ticketPrevenda}${separator}${ticketUniqueNumber}${separator}${lotType}${separator}${lotNumber}${separator}${lotUniqueNumber}${separator}${lotPrice}${separator}${lotPriceTax}`]: newValue },
})
}, () => {
const selectedArray = Object.entries(this.state.selectedQuantities).map(
([key, quantity]) => {
const [ticketName, ticketPrevenda, ticketUniqueNumber, lotType, lotNumber, lotUniqueNumber, lotPrice, lotPriceTax] = key.split(separator)
const totalLotPrice = parseFloat(lotPrice + lotPriceTax);
const total = parseFloat(totalLotPrice * quantity);
return {
ticketName,
ticketPrevenda,
ticketUniqueNumber,
lotType,
lotNumber,
lotUniqueNumber,
lotPrice,
lotPriceTax,
quantity,
totalLotPrice,
total
}
},
)
// console.log(selectedArray);
// console.log(this.state.quantity);
//SOMANDO A QTD E ATUALIZANDO O STATE
// var lotQuantity = selectedArray.reduce(function(prevVal, elem) {
// console.log(elem.quantity)
// const lotQuantity = prevVal + elem.quantity;
// return lotQuantity;
// }, 0);
// this.setState({ qtd: lotQuantity });
// console.log(this.state.lotQuantity);
// //SOMANDO O TOTAL E ATUIALIZANDO O STATE
// var total = selectedArray.reduce(function(prevVal, elem) {
// const total = prevVal + elem.total;
// return total;
// }, 0);
// this.setState({priceTotal: total})
// //MOSTRAR/OCULTAR FOOTER
// if (lotQuantity > 0) {
// this.setState({ totalZero: true });
// } else {
// this.setState({ totalZero: false });
// }
// //OBJETO CART
// var lot = selectedArray;
// var tickets = {
// name: ticketName,
// prevenda: ticketPrevenda,
// unique_number: ticketUniqueNumber,
// lot: lot
// }
// total = {
// price: total,
// quantity: lotQuantity,
// };
// var events = {
// banner_app: this.state.event.banner_app,
// installments: this.state.event.installments,
// max_purchase: this.state.event.max_purchase,
// name: this.state.event.name,
// tickets: tickets,
// unique_number: this.state.event.unique_number,
// total_tickets: lotQuantity
// };
// var cart = { events: events, total: total };
// localStorage.setItem('cart', JSON.stringify(cart));
// localStorage.setItem('qtd', JSON.stringify(lotQuantity));
// console.log(lotQuantity);
// console.log(JSON.parse(localStorage.getItem('cart')));
//OBJETO CART
})
}
// getSelectedQuantity = (ticketName, ticketPrevenda, ticketUniqueNumber, lotType, lotNumber, lotUniqueNumber, lotPrice, lotPriceTax) => this.state.selectedQuantities[`${ticketName}${separator}${ticketPrevenda}${separator}${ticketUniqueNumber}${separator}${lotType}${separator}${lotNumber}${separator}${lotUniqueNumber}${separator}${lotPrice}${separator}${lotPriceTax}`];
//HERE IS THE FUNCTION THAT INCREMENT/DECREMENT ITEMS
getSelectedQuantity = (ticketName, ticketPrevenda, ticketUniqueNumber, lotType, lotNumber, lotUniqueNumber, lotPrice, lotPriceTax, lotQuantity) => {
// console.log(lotQuantity);
// console.log(this.state.selectedQuantities);
// lot.reduce(function(prevVal, elem) {
// // const soma = parseInt(elem) + parseInt(lotQuantity);
// console.log(elem)
// // return soma;
// }, 0);
// console.log(myLotQuantity);
// return myLotQuantity;
// console.log(this.state.selectedQuantities);
return this.state.selectedQuantities[
`${ticketName}${separator}${ticketPrevenda}${separator}${ticketUniqueNumber}${separator}${lotType}${separator}${lotNumber}${separator}${lotUniqueNumber}${separator}${lotPrice}${separator}${lotPriceTax}`
];
// return lotQuantity;
}
getAdditionEnabled = () => Object.values(this.state.selectedQuantities).reduce((acc, i) => acc + i, 0) < this.state.maxTotalItems;
onCheckoutButtonClick = () => {
const selectedArray = Object.entries(this.state.selectedQuantities).map(
([key, quantity]) => {
const [ticketName, ticketPrevenda, ticketUniqueNumber, lotType, lotNumber, lotUniqueNumber, lotPrice, lotPriceTax] = key.split(separator)
const totalLotPrice = parseFloat(lotPrice + lotPriceTax);
const total = parseFloat(totalLotPrice * quantity);
return {
ticketName,
ticketPrevenda,
ticketUniqueNumber,
lotType,
lotNumber,
lotUniqueNumber,
lotPrice,
lotPriceTax,
quantity,
totalLotPrice,
total
}
},
)
console.log(selectedArray);
}
render() {
return (
<div>
<Header Title="Carrinho" ToPage="/" />
<div className="cart">
<div className="container-fluid">
<div className="box-price">
<div className="row box-default ">
<div className="col col-price">
<h6>{this.state.quantity} INGRESSO{this.state.quantity > 1 ? 'S' : ''}</h6>
<h5>R$ {parseFloat(this.state.priceTotal).toFixed(2).replace('.', ',')}</h5>
</div>
</div>
</div>
<div className="box-default">
<div className="row no-margin">
<div className="col-12 col-image no-padding">
<img src={this.state.banner_app} alt="" />
</div>
<div className="col-12 no-padding">
<h5 className="event-name">{this.state.event_name}</h5>
</div>
</div>
{
this.state.lot.map((lot, l) =>
// <div className="row" key={l}>
// <div className="col-8">
// <h5 className="lot-name">{lot.name}</h5>
// <h5 className="lot-name">
// {
// lot.lotType === 'U' ? 'Unissex ' : ''
// }
// {
// lot.lotType === 'M' ? 'Masculino ' : ''
// }
// {
// lot.lotType === 'F' ? 'Feminino ' : ''
// }
// ({lot.lotNumber}º Lote)
// </h5>
// <h6 className="lot-price">
// R$ {lot.lotPrice.replace('.', ',')} <br />
// <small>(R$ {lot.lotPrice.replace('.', ',')} + R$ {lot.lotPriceTax.replace('.', ',')})</small>
// </h6>
// </div>
// <div className="col-4">
// <ChooseQuantity
// value={this.getSelectedQuantity(lot.quantity)}
// onChange={this.onQuantityChange}
// additionEnabled={this.additionEnabled}
// maxPurchase={this.state.events.max_purchase}
// lotPrice={lot.lotPrice}
// lotPriceTax={lot.lotPriceTax}
// lotQuantity={lot.lotQuantity}
// />
// </div>
// <div className="col-12">
// {this.state.lot.length > 1 ? <hr /> : ''}
// </div>
// </div>
<div key={l}>
<Lot
events={this.state.events}
ticketName={this.state.cart.events.tickets.name}
ticketPrevenda={this.state.cart.events.tickets.prevenda}
ticketUniqueNumber={this.state.cart.events.tickets.unique_number}
lotUniqueNumber={lot.lotUniqueNumber}
lotName={lot.name}
lotType={lot.lotType}
lotNumber={lot.lotNumber}
lotPrice={lot.lotPrice}
lotPriceTax={lot.lotPriceTax}
onQuantityChange={this.onQuantityChange}
maxPurchase={this.state.events.max_purchase}
lotQuantity={this.getSelectedQuantity(this.state.cart.events.tickets.name, this.state.cart.events.tickets.prevenda, this.state.cart.events.tickets.unique_number, lot.lotType, lot.lotNumber, lot.lotUniqueNumber, lot.lotPrice, lot.lotPriceTax, lot.quantity)}
// quantity={lot.quantity}
additionEnabled={this.getAdditionEnabled()}
/>
{this.state.lot.length > 1 ? <hr /> : ''}
</div>
)
}
<div className="row cart-footer" style={{ marginRight: '-15px', marginLeft: '-15px', backgroundColor: '#f4f7fa' }}>
<button className="col col-purchase" to="/cart" style={{ justifyContent: 'center', alignItems: 'center' }} onClick={this.onCheckoutButtonClick}>
Confirmar Comprar
</button>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Cart;
In the getSelectedQuantity function if I put
return this.state.selectedQuantities[
`${ticketName}${separator}${ticketPrevenda}${separator}${ticketUniqueNumber}${separator}${lotType}${separator}${lotNumber}${separator}${lotUniqueNumber}${separator}${lotPrice}${separator}${lotPriceTax}`
];
It updates the items on the increment / decrement button, but I need it to show the quantity of items that exist in the localStorage and update the quantity. I've been trying for a few days and nothing
Upvotes: 0
Views: 399
Reputation: 676
This might not be a complete answer for your problem, but you're causing a bloody hell in your componentDidMount, especially by calling this.setState() so many times. Remember a thing - each time you call this.setState you're re-rendering the component.
Also, this.setState() doesn't return a promise, so await this.setState({...})
doesn't make any sense.
So, the first improvement for your component will be:
componentDidMount() {
const cart = JSON.parse(localStorage.getItem('cart'));
const {
events,
events: { tickets },
total
} = cart;
this.setState({
cart,
events,
banner_app: events.banner_app,
event_name: events.event_name,
priceTotal: total.price,
quantity: total.totalQuantity,
lot: tickets.lot,
maxTotalItems: events.max_purchase,
selectedLots: tickets.lot,
});
}
Upvotes: 1