how do i toggle disabled between two buttons in react map - reactjs

I have a list of candidates with two buttons hire and reject. when i press hire it should be disabled and reject stays enabled. When i press reject it should be disabled and hire must be enabled.
{result && result.map(appliedCandidate => {
if (joblist.id === appliedCandidate.jobid) {
return (
<div className="row pb-3">
<div className=" col-md-4 text-left font-weight-bold">
<p className={this.state.applystatus==="hire" ? "text- info" : "text-danger"}>
{appliedCandidate.firstName}
</p>
</div>
<div className="col-md-8">
<div className="row">
<div className="col-4">
<div className="back-btn">
<input id='hire' type='button' ref='hire' data-id={appliedCandidate.jobid} name={appliedCandidate.id} data-tag={appliedCandidate.phoneno} onClick={this.hireReject} className="btn btn-success card-btn-width" value='hire' />
</div>
</div>
<div className="col-4">
<div className="back-btn">
<input id='reject' type='button' ref='reject' data-id={appliedCandidate.jobid} name={appliedCandidate.id} data-tag={appliedCandidate.phoneno} onClick={this.hireReject} className="btn btn-danger card-btn-width" value='reject' />
</div>
</div>
<div className="col-4">
<div className="back-btn">
<Link to={{ pathname: '/individualchat', state: { name: appliedCandidate.firstName, jobid: appliedCandidate.jobid, id: appliedCandidate.id, Title: appliedCandidate.Title } }}>
<button type="button" className="btn btn-info">chat</button>
</Link>
</div>
</div>
</div>
</div>)
}
})}
hireReject = (event) => {
var dis = event.target.setAttribute('disabled','true')
const phoneno = event.target.getAttribute('data-tag');
const id = event.target.getAttribute('name');
const jobid = event.target.getAttribute('data-id');
const applystatus = event.target.value;
{ applystatus === 'hire' ? toastr.success('Successfully hired') : toastr.error('Successfully rejected') }
{ applystatus === 'hire' ? document.getElementById('reject').disabled = false : document.getElementById('hire').disabled = false }
this.setState({
jobid: jobid, id: id, candidatephoneno: phoneno, applystatus: applystatus
}, () => {
this.props.hireReject(this.state)
})
{return applystatus === 'hire' ? 'hired' : 'rejected'}
}

Consider separating the buttons and hiring/rejecting logic into its own component like the following so you can better handle the toggling.
Index.js
import React from "react";
import ReactDOM from "react-dom";
import Candidate from "./Candidate";
import "./styles.css";
class App extends React.Component {
state = {
text: ""
};
render() {
const candidates = [{ name: "Bob" }, { name: "Sam" }, { name: "Jessie" }];
return candidates.map(candidate => {
return <Candidate candidate={candidate} />;
});
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Candidate.js
import React from "react";
class Candidate extends React.Component {
state = {
hired: null
};
handleHire = () => {
this.setState({
hired: true
});
};
handleReject = () => {
this.setState({
hired: false
});
};
render() {
const hired = this.state.hired;
return (
<div>
<h4>{this.props.candidate.name}</h4>
<button
onClick={this.handleHire}
disabled={hired == null ? false : hired}
>
Hire
</button>
<button
onClick={this.handleReject}
disabled={hired == null ? false : !hired}
>
Reject
</button>
</div>
);
}
}
export default Candidate;
Here is a sandbox for your reference as well: https://codesandbox.io/s/zrlyq0l29m

Related

how to add data in localstorage in react

I am arslan Chaudhry. currently, I am working on an eCommerce site where I will store data in local storage because I don't have too much backend knowledge. how I can add functionality like delete and update on another folder.
my code is given below.
Books.js
import React from "react";
import "./components/book.css";
import Carousel from "react-multi-carousel";
import "react-multi-carousel/lib/styles.css";
import { FaShoppingCart } from "react-icons/fa";
import { useEffect } from "react";
import { useState, useRef } from "react";
import { useNavigate } from "react-router-dom";
import { createContext } from "react";
const Books = () => {
let arr=()=>{
let dat=localStorage.getItem("products")
if (dat) {
return JSON.parse(dat)
}
else{
return []
}
}
const [booksData, setbooksData] = useState([]);
const [productData, setproductData] = useState(arr());
let nav = useNavigate();
// slider
const responsive = {
superLargeDesktop: {
breakpoint: { max: 4000, min: 3000 },
items: 5,
},
desktop: {
breakpoint: { max: 3000, min: 1024 },
items: 3,
},
tablet: {
breakpoint: { max: 1024, min: 464 },
items: 2,
},
mobile: {
breakpoint: { max: 464, min: 0 },
items: 1,
},
};
let croser = useRef("");
let loding = useRef("");
const getJason = async () => {
try {
let fea = await fetch(
"https://script.google.com/macros/s/AKfycbxFCG7S-kjncQZwvcMnqq4wXoBAX8ecH1zkY2bLP7EE-YHlnKbiJ3RUuHtWLe6sIK30Kw/exec"
);
let acData = await fea.json();
let itemsData = acData.shop.filter((element) => {
if (element.name) {
return element;
}
});
setbooksData(itemsData);
if (itemsData) {
croser.current.style.filter = "blur(0px)";
loding.current.style.display = "none";
}
} catch (error) {
croser.current.style.filter = "blur(0px)";
loding.current.style.display = "none";
}
};
// get product data from api
useEffect(() => {
getJason();
}, []);
// go to cart button
const goto = () => {
nav("/Cart");
};
// local data
let addNow=(e)=>{
let data=productData.find((element)=>{return element.id === e.id });
let cart;
if (data) {
cart=productData.map((element)=>{
return element.id === e.id ? {...element, quantity:element.quantity+1}:element
})
}
else{
cart=[...productData,{...e, quantity:1}]
}
setproductData(cart);
};
useEffect(() => {
localStorage.setItem("products",JSON.stringify(productData))
}, [productData])
console.log(productData);
return (
<>
<div className="row " style={{ marginTop: "10px" }}>
<div className="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div className="section-headline text-center">
<h2>Books Shop</h2>
</div>
</div>
</div>
<div className="lodingBooks" ref={loding}>
<div class="spinner-border" role="status"></div>
<h4>Please wait....</h4>
</div>
<div ref={croser}>
<div className=" shadow go_to_cart" onClick={goto}>
<i class="bi bi-cart-check text-white"></i>
</div>
<Carousel responsive={responsive} className="container">
{booksData.map((element) => {
return (
<>
<div class="container page-wrapper">
<div class="page-inner">
<div class="row">
<div class="el-wrapper">
<div class="box-up">
<img class="img" src={element.images} alt="" />
<div class="img-info">
<div class="info-inner">
<span class="p-name text-info">
{element.name}
</span>
<span class="p-company ">Author:CHAUDHRY</span>
</div>
<div class="a-size ">
About:This is a complete book on javascript
<span class="size"></span>
</div>
</div>
</div>
<input
type="text"
value={1}
style={{ display: "none" }}
/>
<div class="box-down">
<div class="h-bg">
<div class="h-bg-inner"></div>
</div>
<a class="cart">
<span class="price">{element.price + "$"}</span>
<span
class="add-to-cart btn btn-sm"
style={{ backgroundColor: "#3EC1D5" }}
onClick={()=>{addNow(element)}}
>
<span class="txt">
ADD TO CART <FaShoppingCart />
</span>
</span>
</a>
</div>
</div>
</div>
</div>
</div>
</>
);
})}
</Carousel>
</div>
</>
);
};
export default Books;
and here is my cart file. where i want to perform the action like update and delete.
Cart.js
import React from "react";
import "./components/cart.css";
import { useEffect } from "react";
const Cart = () => {
let data = localStorage.getItem("products");
let javaData = JSON.parse(data);
let removeData = (e) => {
};
useEffect(() => {
localStorage.clear()
}, [])
return (
<>
<div class="container mt-5 mb-5">
<div class="d-flex justify-content-center row">
<div class="col-md-8">
<div class="p-2 shoingTitle">
<h4>Shop Now</h4>
<span class="text-danger">Remove all</span>
</div>
{javaData ? (
javaData.map((item) => {
return (
<>
<div class="d-flex flex-row justify-content-between align-items-center p-2 bg-white mt-4 px-3 rounded">
<div class="mr-1 imageandpara">
<img class="rounded" src={item.images} width="70" />
<span class="font-weight-bold">{item.name}</span>
</div>
<div class="d-flex flex-column align-items-center product-details">
<div class="d-flex flex-row product-desc"></div>
</div>
<div class="d-flex flex-row align-items-center qty">
<i class="minusSign shadow">
<i class="bi bi-dash"></i>
</i>
<span class="text-grey quantityNumber">
{item.quantity}
</span>
<i class="minusSign shadow">
<i class="bi bi-plus"></i>
</i>
</div>
<div>
<span class="text-grey productAmount">{`${
item.quantity * item.price
}$`}</span>
</div>
<div
class="d-flex align-items-center text-dark "
style={{
cursor: "pointer",
fontWeight: "900",
fontSize: "15px",
}}
onClick={() => {
removeData(item);
}}
>
<i class="bi bi-x text-danger"></i>
</div>
</div>
</>
);
})
) : (
<h3 style={{ textAlign: "center" }}>Cart is empety</h3>
)}
<div class="d-flex flex-row align-items-center mt-3 p-2 bg-white rounded">
<input
type="text"
class="form-control gift-card "
placeholder="discount code/gift card"
/>
<button
class="btn btn-sm ml-3 shadow"
type="button"
style={{
outline: "#3EC1D5",
backgroundColor: "#3EC1D5",
color: "white",
}}
>
Apply
</button>
</div>
<div class="totalItems">
Total Items: <strong>12</strong>
</div>
<span class="TotalPrice">
Total price: <strong>12$</strong>
</span>
<div class="d-flex flex-row align-items-center mt-3 p-2 bg-white rounded">
<button
class="btn btn-block btn-sm ml-2 pay-button shadow"
type="button"
style={{ backgroundColor: "#3EC1D5" }}
>
Proceed to Pay
</button>
</div>
</div>
</div>
</div>
</>
);
};
export default Cart;
Try this for add:
let removeData = (e) => {
localStorage.setItem("name of the item") // e.target.name
};
There's alot going on in your site :)
I think it will be responsible to create a context, that will serve the cart to all other components.
Things to note here, (Found some little improvements)
Run the function in the useState hook, don't just leave it there like you did
When using Array.filter you need to return a boolean iorder for it too filter your array properly.
This is the code I brought up hope it helps you out.
CartContext.js file.
import React, { createContext, useContext, useEffect, useState } from "react";
export const CartContext = createContext();
function Cart({ children }) {
const arr = useCallback(() => {
let dat = localStorage.getItem("products");
if (dat) {
return JSON.parse(dat);
} else {
return [];
}
}, []);
const [productData, setproductData] = useState(() => arr());
const getJason = async () => {
try {
let fea = await fetch(
"https://script.google.com/macros/s/AKfycbxFCG7S-kjncQZwvcMnqq4wXoBAX8ecH1zkY2bLP7EE-YHlnKbiJ3RUuHtWLe6sIK30Kw/exec"
);
let acData = await fea.json();
// filter callback function should return a boolean. That is either true or false in order to make it work.
// SO i think this function isn't going to function properly
let itemsData = acData.shop.filter((element) => {
if (element.name) {
return element;
}
});
setbooksData(itemsData);
if (itemsData) {
croser.current.style.filter = "blur(0px)";
loding.current.style.display = "none";
}
} catch (error) {
croser.current.style.filter = "blur(0px)";
loding.current.style.display = "none";
}
};
// get product data from api
useEffect(() => {
getJason();
}, []);
const addProduct = (e) => {
// check if product id available on cart
const findProduct = productData.find((element) => {
return element.id === e.id;
});
// add first quantity if not available
if (!findProduct)
return setproductData([...productData, { ...e, quantity: 1 }]);
// increase quantity by 1
const newCart = productData.map((element) => {
return {
...element,
quantity: element.id === e.id ? element.quantity + 1 : element.quantity,
};
});
setproductData(newCart);
};
const removeProduct = (e) => {
// check if product id available on cart
const findProductQuantity = productData.find((element) => {
return element.id === e.id && element.quantity >= 1;
});
// add first quantity if not available
if (!findProduct)
// Your ui should prevent this
return;
// decrease quantity by 1
const reducedQuantityCart = productData.map((element) => {
return {
...element,
quantity: element.id === e.id ? element.quantity - 1 : element.quantity,
};
});
// filter out all products with quantity less than 1 (quantity : 0)
const newCart = productData.filter((element) => {
return element.quantity >= 1;
});
setproductData(newCart);
};
const deleteProduct = (e) => {
// check if product id available on cart
const findProduct = productData.find((element) => {
return element.id === e.id;
});
// add first quantity if not available
if (!findProduct)
// Your ui should prevent this
return;
const productIndex = productData.findIndex((element) => {
return element.id === e.id;
});
// splice (delete) product from the productData array
const newCart = [productData].splice(productIndex, 1);
setproductData(newCart);
};
const value = {
productData,
addProduct,
removeProduct,
deleteProduct,
};
return <CartContext.Provider value={value}>{children}</CartContext.Provider>;
}
In here you create a context, create all your function you will use to update your cart, and pass them to your Context provider
// create a hook can you use anywhere in the app
export const useCart = () => {
const context = useContext(CartContext);
if (!context) {
throw new Error("Must use useCart in CartContext Child");
}
const { productData, addProduct, removeProduct, deleteProduct } = context;
return { productData, addProduct, removeProduct, deleteProduct };
};
For this you create a custom hook that you can use inside any component provided it is a child of the Cart context. So make sure you wrap it all around your app
// Use Case
const SomeComponent = () => {
const { productData, addProduct, removeProduct } = useCart();
return (
<div>
<p> Number of Products: {productData.length}</p>
<div>
{productData?.map((product) => (
<div>
<p>{product?.name}</p>
<button onClick={() => addProduct(product)}>add</button>
<button onClick={() => removeProduct(product)}>
subtract/reduce
</button>
<button onClick={() => deleteProduct(product)}>delete</button>
</div>
))}
</div>
</div>
);
};
Use case Scenario od how this code will work. Hope you find this helful

I am trying to pass date object and other nested objects in query which is getting undefined in the search page

//searchbar.tsx
import format from 'date-fns/format'
import moment from 'moment'
import { useRouter } from 'next/router'
import React, { useState } from 'react'
import { DateRangePicker } from 'react-date-range'
import { FaBed } from 'react-icons/fa'
import { MdDateRange, MdOutlineEmojiPeople } from 'react-icons/md'
import styles from './Header.module.css'
interface options {
adult: number
children: number
rooms: number
}
const SearchSection = () => {
const [destination, setDestination] = useState('')
const [openCalendar, setOpenCalendar] = useState(false)
const router = useRouter()
const [date, setDate] = useState<any>([
{
startDate: new Date(),
endDate: new Date(),
key: 'selection',
},
])
const [openOptions, setOpenOptions] = useState(false)
const [options, setOptions] = useState<any>({
adult: 1,
children: 0,
rooms: 1,
})
const { adult, children, rooms } = options
const handleOption = (name: string, operation: string) => {
setOptions((prevState: options) => ({
...prevState,
[name]: operation === 'i' ? options[name] + 1 : options[name] - 1,
}))
}
const handleSearch = () => {
const searchOptions = {
destination,
date,
options,
}
console.log(searchOptions) //(it's all properties are filled as intended)
//passing this data to the /search page in the query
router.push({ pathname: '/search', query: searchOptions })
}
return (
<div className={styles.headerSearch}>
<div className={styles.headerSearchItem}>
<FaBed className={styles.headerIcon} />
<input
type="text"
placeholder="Where are you going"
className={styles.searchInput}
value={destination}
onChange={(e) => setDestination(e.target.value)}
/>
</div>
<div className={styles.headerSearchItem}>
<MdDateRange className={styles.headerIcon} size={20} />
<span
className={styles.headerSearchText}
onClick={() => setOpenCalendar((prevState) => !prevState)}
>
{`${format(date[0].startDate as any, 'MM/dd/yy')}`} to{' '}
{`${format(date[0].endDate as any, 'MM/dd/yy')}`}
</span>
{openCalendar && (
<DateRangePicker
ranges={date}
onChange={(ranges) => {
setDate([ranges.selection])
}}
editableDateInputs={false}
className={styles.date}
//this is to disable all dates before today
minDate={moment().toDate()}
/>
)}
</div>
<div className={styles.headerSearchItem}>
<MdOutlineEmojiPeople className={styles.headerIcon} size={20} />
<span
className={styles.headerSearchText}
onClick={() => setOpenOptions((prevState) => !prevState)}
>
{adult} adults {children} chilren {rooms} room{' '}
</span>
{openOptions && (
<div className={styles.options}>
<div className={styles.optionItem}>
<span className="optionText">Adult</span>
<div className={styles.counter}>
<button
className={styles.counterBtn}
onClick={() => handleOption('adult', 'i')}
>
+
</button>
<span className={styles.countNumber}>{adult}</span>
<button
className={styles.counterBtn}
onClick={() => handleOption('adult', 'd')}
disabled={adult <= 1}
>
-
</button>
</div>
</div>
<div className={styles.optionItem}>
<span className="optionText">Children</span>
<div className={styles.counter}>
<button
className={styles.counterBtn}
onClick={() => handleOption('children', 'i')}
>
+
</button>
<span className={styles.countNumber}>{children}</span>
<button
className={styles.counterBtn}
onClick={() => handleOption('children', 'd')}
disabled={children < 1}
>
-
</button>
</div>
</div>
<div className={styles.optionItem}>
<span className="optionText">Rooms</span>
<div className={styles.counter}>
<button
className={styles.counterBtn}
onClick={() => handleOption('rooms', 'i')}
>
+
</button>
<span className={styles.countNumber}>{rooms}</span>
<button
className={styles.counterBtn}
onClick={() => {
handleOption('rooms', 'd')
}}
disabled={rooms <= 1}
>
-
</button>
</div>
</div>
</div>
)}
</div>
<div className={styles.headerSearchItem}>
<button className={styles.headerBtn} onClick={handleSearch}>
Search
</button>
</div>
</div>
)
}
export default SearchSection
//searchpage.tsx
import { useRouter } from 'next/router'
import React, { useState } from 'react'
const Search = () => {
const router = useRouter()
const {
query: { destination, date, options },
} = router
console.log(destination, date, options)
//here I am getting "undefined" or nothing for date and options
return (
<div className="search">
<div className="searchWrapper">
<div className="searchOption">
<h1 className="searchTitle">Search</h1>
<div className="searchOption">
<label>Destination</label>
<input type="text" />
</div>
<div className="searchOption">
<label>Check-in Date</label>
</div>
</div>
<div className="searchResult">a</div>
</div>
</div>
)
}
export default Search
I am trying to pass the selected date and options as you can see in the nextjs router query while pushing to the "/search page". The searchOptions that I passed has all it's properties filled while pushing. But the query only has destination property filled, and other date and options field are undefined. I don't know why does query only accepts simple kind of object and doesn't allow array of objects and nested objects?
You need to stringify your value before push to router and at search page, you need to parse you params
//searchbar.tsx
const searchOptions = {
destination,
date: JSON.stringify(date),
options: JSON.stringify(options),
}
router.push({ pathname: '/search', query: searchOptions })
//searchpage.tsx
const {
query: { destination },
} = router
const date = JSON.parse(router.query.date);
const options = JSON.parse(router.query.options);
Hope it help!!

Cannot add item to cart when click on the button

When i click on the cart symbol, it changes its value to be in cart but actually my product is not rendered on the cart component, is there something wrong or missing in my code, please help me to fix it! Thank you so much!
Context.js:
class ProductProvider extends React.Component {
state = {
products: storeProducts,
detailProduct: detailProduct,
cart: [],
modalOpen: false,
modalProduct: detailProduct
};
getItem = (id) => {
const product = this.state.products.find((item) => item.id === id);
return product;
};
addToCart = (id) => {
console.log("add to cart");
let tempProducts = [...this.state.products];
const index = tempProducts.indexOf(this.getItem(id));
const product = tempProducts[index];
product.inCart = true;
product.count = 1;
const price = product.price;
product.total = price;
this.setState(() => {
return (
{ products: tempProducts, cart: [...this.state.cart, product] },
() => console.log(this.state)
);
});
};
openModal = (id) => {
const product = this.getItem(id);
this.setState(() => {
return { modalProduct: product, openModal: true };
});
};
closeModal = (id) => {
this.setState(() => {
return { modalOpen: false };
});
};
Cart.js:
import React from "react";
import CartColumns from "./CartColumns";
import CartList from "./CartList";
import EmptyCart from "./EmptyCart";
import { ProductContext } from "../App";
export default class Cart extends React.Component {
render() {
return (
<div>
<ProductContext.Consumer>
{(value) => {
console.log(value, "inside Product COnt");
if (value.length > 0) {
return (
<div>
<CartColumns />
<CartList items={items} />
</div>
);
} else {
<EmptyCart />;
}
}}
</ProductContext.Consumer>
</div>
);
}
}
CartList.js:
import React from "react";
import CartItem from "./CartItem";
export default function CartList(props) {
const { items } = props;
return (
<div>
{items.cart.map((item) => (
<CartItem
key={item.id}
item={item}
increment={item.increment}
decrement={item.decrement}
/>
))}
</div>
);
}
CartItem.js:
import React from "react";
function CartItem(props) {
const { id, title, img, price, total, count } = props.item;
const { increment, decrement, removeItem } = props;
return (
<div className="row my-1 text-capitalize text-center">
<div className="col-10 mx-auto col-lg-2">
<img
src={img}
style={{ width: "5rem", heigth: "5rem" }}
className="img-fluid"
alt=""
/>
</div>
<div className="col-10 mx-auto col-lg-2 ">
<span className="d-lg-none">product :</span> {title}
</div>
<div className="col-10 mx-auto col-lg-2 ">
<strong>
<span className="d-lg-none">price :</span> ${price}
</strong>
</div>
<div className="col-10 mx-auto col-lg-2 my-2 my-lg-0 ">
<div className="d-flex justify-content-center">
<div>
<span className="btn btn-black mx-1">-</span>
<span className="btn btn-black mx-1">{count}</span>
<span className="btn btn-black mx-1">+</span>
</div>
</div>
</div>
<div className="col-10 mx-auto col-lg-2 ">
<div className=" cart-icon">
<i className="fas fa-trash" />
</div>
</div>
<div className="col-10 mx-auto col-lg-2 ">
<strong>item total : ${total} </strong>
</div>
</div>
);
}
export default CartItem;
Sandbox link for better observation:https://codesandbox.io/s/cart-code-addict-forked-l6tfm?file=/src/cart/CartItem.js
There were few issues
Change following
this.setState(() => {
return (
{ products: tempProducts, cart: [...this.state.cart, product] },
() => console.log(this.state)
);
});
to
this.setState(
{
products: tempProducts,
cart: [...this.state.cart, product]
},
() => console.log(this.state)
);
And need to use value.cart to check for length and when passing as a prop.
Instead of
if (value.length > 0) {
return (
<div>
<CartColumns />
<CartList items={items} />
</div>
);
}
It should be
if (value.cart.length > 0) {
return (
<div>
<CartColumns />
<CartList items={value.cart} />
</div>
);
}
And in CartList,
Instead of
{
items.cart.map(item => (
<CartItem
key={item.id}
item={item}
increment={item.increment}
decrement={item.decrement}
/>
));
}
it should be
{
items.map(item => (
<CartItem
key={item.id}
item={item}
increment={item.increment}
decrement={item.decrement}
/>
));
}
Now it shows the cart with items
Code sandbox => https://codesandbox.io/s/cart-code-addict-forked-c3kug?file=/src/cart/CartList.js

Reactjs Update the state without reload the page

I built a shopping cart in my app. This is the flow:
- The customer sees a list of items and clicks on one he wants;
- The next page is where he chooses the quantity of products and then I save in localStorage;
- By clicking Confirm, he goes to the shopping cart with the same products he has chosen. On this page (shopping cart) he can change the quantity and in this moment the total and quantity must change (see the image).
I was able to do this reloading the page, but when in production the page is not working properly. I need to do this without reload the page.
How to do this without reload the page?
I got 3 components: Header (with the icon cart), ChooseQuantity and Cart.
See below the code:
//My Choose Quantity Component
import React from 'react';
import '../../components/ChooseQuantity/ChooseQuantity.css';
class ChooseQuantity extends React.Component {
constructor(props) {
super(props);
const { lotQuantity, totalQuantity, maxTotalItems, maxPurchase, lot, totalTickets, events, onChange } = this.props;
this.state = {
counter: 0,
lotQuantity: lotQuantity,
totalQuantity: totalQuantity,
maxTotalItems: maxTotalItems,
maxPurchase: maxPurchase,
totalTickets: totalTickets,
onChange: onChange,
events: events,
lot: lot,
tickets: events.tickets,
cart: []
}
this.increment = this.increment.bind(this);
this.decrement = this.decrement.bind(this);
}
componentDidMount() {
// console.log(this.state.lot);
// localStorage.setItem('teste', JSON.stringify(this.state.lotQuantity));
}
// static getDerivedStateFromProps(props, state) {
// console.log(props.lot);
// // console.log(state);
// if (props.selected !== state.selected) {
// return {
// selected: props.selected,
// };
// }
// }
// componentDidUpdate(prevProps, prevState) {
// console.log(this.props.lot);
// localStorage.setItem('teste', JSON.stringify(this.props.lot.quantity));
// if (this.props.lot !== prevProps.lot) {
// // this.selectNew();
// }
// }
async increment() {
await this.setState({
lotQuantity: this.state.lotQuantity + 1,
totalQuantity: + 1,
});
let lotUniqueNumber = this.state.lot.lotUniqueNumber;
let lotQuantity = this.state.lotQuantity;
var ar_lot = [];
this.state.tickets.lot.forEach(function (item) {
if (lotUniqueNumber === item.lotUniqueNumber) {
item.quantity = lotQuantity;
item.total = item.totalLotPrice * item.quantity
}
ar_lot.push(item);
})
// console.log(ar_lot);
//CALCULATING A QUANTITY
var ob_qtd = ar_lot.reduce(function (prevVal, elem) {
const ob_qtd = prevVal + elem.quantity;
return ob_qtd;
}, 0);
await this.setState({ totalTickets: ob_qtd })
//CALCULATING A QUANTITY
//CALCULATING THE TOTAL
var ob_total = ar_lot.reduce(function (prevVal, elem) {
const ob_total = prevVal + elem.total;
return ob_total;
}, 0);
// CALCULATING THE TOTAL
//RIDING THE SHOPPING CART
let total = {
price: ob_total,
totalQuantity: ob_qtd,
};
let tickets = {
name: this.state.tickets.name,
prevenda: this.state.tickets.prevenda,
unique_number: this.state.tickets.unique_number,
lot: ar_lot
}
let events = {
banner_app: this.state.events.banner_app,
installments: this.state.events.installments,
max_purchase: this.state.events.max_purchase,
name: this.state.events.name,
tickets: tickets
}
var cart = { events: events, total: total };
this.setState({
cart: cart
})
// console.log(cart);
localStorage.setItem('cart', JSON.stringify(cart));//RECORDING CART IN LOCALSTORAGE
localStorage.setItem('qtd', JSON.stringify(ob_qtd));
window.location.reload();//UPDATE PAGE FOR CHANGES TO BE UPDATED
}
async decrement() {
await this.setState({
lotQuantity: this.state.lotQuantity - 1,
totalQuantity: - 1,
totalTickets: this.state.totalTickets - 1,
});
let lotUniqueNumber = this.state.lot.lotUniqueNumber;
let lotQuantity = this.state.lotQuantity;
var ar_lot = [];
this.state.tickets.lot.forEach(function (item) {
if (lotUniqueNumber === item.lotUniqueNumber) {
item.quantity = lotQuantity;
item.total = item.totalLotPrice * item.quantity
}
ar_lot.push(item);
})
//CALCULANDO A QUANTIDADE
var ob_qtd = ar_lot.reduce(function (prevVal, elem) {
const ob_qtd = prevVal + elem.quantity;
return ob_qtd;
}, 0);
//CALCULANDO A QUANTIDADE
//CALCULANDO O TOTAL
var ob_total = ar_lot.reduce(function (prevVal, elem) {
const ob_total = prevVal + elem.total;
return ob_total;
}, 0);
//CALCULANDO O TOTAL
let total = {
price: ob_total,
totalQuantity: ob_qtd,
};
let tickets = {
name: this.state.tickets.name,
prevenda: this.state.tickets.prevenda,
unique_number: this.state.tickets.unique_number,
lot: ar_lot
}
let events = {
banner_app: this.state.events.banner_app,
installments: this.state.events.installments,
max_purchase: this.state.events.max_purchase,
name: this.state.events.name,
tickets: tickets
}
var cart = { events: events, total: total };
localStorage.setItem('cart', JSON.stringify(cart));
localStorage.setItem('qtd', JSON.stringify(ob_qtd));
window.location.reload();
}
render() {
return (
<div className="choose-quantity">
{
this.state.lotQuantity <= 0 ?
<div className="space-button"></div> :
<button className='minus' onClick={this.decrement}><i className="fas fa-minus"></i></button>
}
<div id='counter' className="qtd" value={this.state.lotQuantity} onChange={this.onChange}>{this.state.lotQuantity}</div>
{
this.state.totalTickets >= this.state.maxPurchase ?
<div className="space-button"></div> :
<button className="plus" onClick={() => this.increment(this.state.lotQuantity)}><i className="fas fa-plus"></i></button>
}
</div>
)
}
}
export default ChooseQuantity;
//My Shopping Cart Component
import React, { Component } from 'react';
import Swal from "sweetalert2";
import { Link } from 'react-router-dom';
import './Cart.css';
import '../../components/Css/App.css';
import Lot from './Lot';
import ChooseQuantity from './ChooseQuantity';
import Header from '../../components/Header/Header';
import Tabbar from '../../components/Tabbar/Tabbar';
const separator = '/';
class Cart extends Component {
constructor(props) {
super(props);
this.state = {}
this.choosePayment = this.choosePayment.bind(this);
}
async componentDidMount() {
const company_info = JSON.parse(localStorage.getItem('company_info'));
await this.setState({
company_image: company_info.imagem,
company_hash: company_info.numeroUnico,
})
const cart = JSON.parse(localStorage.getItem('cart'));
const total = cart.total;
if(cart){
const {
events,
events: { tickets },
total
} = cart;
await this.setState({
cart,
events,
tickets: tickets,
banner_app: events.banner_app,
eventName: cart.events.name,
priceTotal: total.price,
quantity: total.totalQuantity,
lots: tickets.lot,
maxTotalItems: cart.events.max_purchase,
selectedLots: tickets.lot,
total: total.totalQuantity
});
}
const teste = JSON.parse(localStorage.getItem('teste'))
this.setState({teste: teste})
}
choosePayment() {
Swal.fire({
title: 'Método de Pagamento',
text: 'Qual o médtodo de pagamento que você deseja usar?',
confirmButtonText: 'Cartão de Crédito',
confirmButtonColor: '#007bff',
showCancelButton: true,
cancelButtonText: 'Boleto Bancário',
cancelButtonColor: '#007bff',
}).then((result) => {
if (result.value) {
this.props.history.push('/checkout');
} else{
this.props.history.push('/checkout-bank-slip');
}
})
}
render() {
return (
<div>
<Header Title="Carrinho" ToPage="/" />
{
this.state.total <= 0 ?
<Tabbar />
:
null
}
<div className="cart">
<div className="container-fluid">
{
this.state.total > 0 ?
<div>
<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="row">
<div className="col-12 col-image no-padding">
<img src={this.state.banner_app} alt="" />
</div>
</div>
<div className="row">
<div className="col">
<h1 className="event-title text-center">{this.state.eventName}</h1>
</div>
</div>
<div className="padding-15">
{
this.state.lots.map((lot, l) =>
<div key={l}>
{
lot.quantity > 0 ?
<div>
<div className="row">
<div className="col">
<h5 className="ticket-name">{lot.ticketName}</h5>
</div>
</div>
<div className="row">
<div className="col-8">
<h5 className="lot-name">
{ lot.lotName } - ({lot.lotNumber}º Lote)
</h5>
<h6 className="lot-price">
R$ {lot.lotPrice.replace('.', ',')} ({lot.lotPrice.replace('.', ',')} + {lot.lotPriceTax.replace('.', ',')})
</h6>
</div>
<div className="col-4">
<h3 className='lot-big-price'>
{lot.lotPrice.replace('.', ',')}
</h3>
</div>
</div>
<div className="row">
<div className="col align-items">
<ChooseQuantity
lotQuantity={lot.quantity}
maxPurchase={this.state.events.max_purchase}
totalTickets={this.state.total}
lot={lot}
events={this.state.events}
maxTotalItems={this.state.maxTotalItems}
onCLick={this.onClick}
/>
</div>
</div>
</div>
:
null
}
</div>
)
}
<div className="row cart-footer" style={{ marginRight: '-15px', marginLeft: '-15px', backgroundColor: '#f4f7fa' }}>
<button className="col col-purchase" style={{ justifyContent: 'center', alignItems: 'center' }} onClick={this.choosePayment}>
Confirmar Comprar
</button>
</div>
</div>
</div>
:
<div className='padding-15'>
<div className="mt-5 no-margin box-default row">
<div className="col">
<h3 className="text-center">
Não há nenhum item em seu carrinho.
</h3>
<p className="text-center">
Toque no botão <strong>Buscar Eventos</strong> para iniciar uma nova pesquisa.
</p>
<Link className="btn btn-primary btn-block" to="/">
Buscar Eventos
</Link>
</div>
</div>
<div className="row no-margin box-default mt-3">
<div className="col">
<img src={`//www.yeapps.com.br/admin/files/empresa/${this.state.company_hash}/${this.state.company_image}`} alt={`${this.state.company_name}`} />
</div>
</div>
</div>
}
</div>
</div>
</div>
);
}
}
export default Cart;
//My Header Component
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
// import { withRouter } from 'react-router';
import './Header.css';
import BackButton from '../BackButton/BackButton';
class Header extends Component {
constructor(props){
super(props);
this.state = {
qtd: 0
}
}
componentDidMount() {
const qtd = JSON.parse(localStorage.getItem('qtd'));
this.setState({qtd: qtd});
}
render() {
const { Title } = this.props;
return (
<div>
<nav className="navbar">
{ this.props.Title === 'Home' ? null : <BackButton />}
<Link to="/cart" className="icon-cart">
<i className="fas fa-shopping-cart"></i>
<span className="badge badge-danger">
{this.state.qtd}
</span>
</Link>
<div className="navbar-brand">
{Title}
</div>
</nav>
</div>
);
}
}
export default Header;
You need to update your presentational components(Card,Header) state in componentDidUpdate the same way as you did it in componentDidMount. componentDidMount works only one time with first render and there you set your state variables which you use in render. Do the same setState in componentDidUpdate
P.S. but you need to be sure that with counter increasing your presentational components get new props which will trigger componentDidUpdate.In your case you use localStorage but it will be better to pass data through common parent container(the one which holds those 3 components) as props to Card and Header.

Reactjs use function from parent

I have 2 files. One is my app.js and the other one is productmodal.js
app.js gets a productlist from an api call. It views these productst in a list.
When a user clicks on the image productmodal.js is showed.
productmodal.js shows a popup with a bigger image, productname(title) and a button called "Product niet aanwezig" (product unavailable) if the user clicks on this link a mail is send to an other user.
When the button is click I also want to activate an other function (getUpdatedProduct). This function is gonna do a long polling call to a link to check when the product is updated to a new product and update this product in the app.
The problem is: I don't know how to call the function 'getUpdatedProduct' in productmodal.js
I get an error: Uncaught TypeError: Cannot read property 'getUpdatedProduct' of undefined
I tried some of these solutions https://reactjs.org/docs/faq-functions.html. Especially the arrow function in render, because its generating a new function every time when the modal is clicked (which I need).
But nothing seems to work. Has anyone some idea's?
App.js:
import React from 'react';
import image from '../images/sogyologo.svg';
import ProductModal from './ProductModal.js';
class App extends React.Component {
constructor(props) {
super(props);
this.toggleModal = this.toggleModal.bind(this);
this.state = {
isLoading: true,
orders: [],
dealtOrders: [],
productDetail: [],
open: false,
modal: []
}
}
toggleModal(event)
{
console.log(event);
let itemIndex = event.target.getAttribute("data-itemIndex");
console.log(itemIndex);
const productModal = this.state.orders[itemIndex];
console.log(productModal);
this.setState({
open: true,
modal: this.state.orders[itemIndex]
});
}
handleClose() {
this.setState({
open: !this.state.open
});
}
componentWillMount() {
localStorage.getItem('orders') && this.setState({
orders: JSON.parse(localStorage.getItem('orders')),
isLoading: false
})
}
componentDidMount() {
if (!localStorage.getItem('orders')){
this.fetchData();
} else {
console.log('Using data from localstorage');
}
}
fetchData() {
fetch('http://localhost:54408/api/orders/all/testing-9!8-7!6/10-04-2018')
.then(response => response.json())
.then(parsedJSON => parsedJSON.map(product => (
{
productname: `${product.ProductName}`,
image: `${product.Image}`,
quantity: `${product.Quantity}`,
isconfirmed: `${product.IsConfirmed}`,
orderid: `${product.OrderId}`
}
)))
.then(orders => this.setState({
orders,
isLoading: false
}))
.catch(error => console.log('parsing failed', error))
}
// componentWillUpdate(nextProps, nextState) {
// localStorage.setItem('orders', JSON.stringify(nextState.orders));
// localStorage.setItem('ordersDate', Date.now());
// }
render() {
this.handleDoneAction = event =>
{
let itemIndex = event.target.getAttribute("data-itemIndex");
let prevOrders = [...this.state.orders];
let dealtOrders = [...this.state.dealtOrders];
const itemToMoveAtLast = prevOrders.splice(itemIndex, 1);
const addToDealtOrders = dealtOrders.concat(itemToMoveAtLast);
this.setState({dealtOrders: addToDealtOrders});
this.setState({orders: prevOrders});
};
this.handleUndoAction = event =>
{
let itemIndex = event.target.getAttribute("data-itemIndex");
let orders = [...this.state.orders];
let dealtOrders = [...this.state.dealtOrders];
const undoDealtOrder = dealtOrders.splice(itemIndex, 1);
const addToOrders = orders.concat(undoDealtOrder);
this.setState({orders: addToOrders});
this.setState({dealtOrders: dealtOrders});
};
const {isLoading, orders, dealtOrders} = this.state;
return (
<div>
<header>
<img src={image}/>
<h1>Boodschappenlijstje <button className="btn btn-sm btn-danger">Reload</button></h1>
</header>
<div className={`content ${isLoading ? 'is-loading' : ''}`}>
<div className="panel">
{
!isLoading && orders.length > 0 ? orders.map((order, index) => {
const {productname, image, quantity, orderid} = order;
return<div className="product" key={orderid}>
<div className="plaatjediv" onClick={this.toggleModal.bind(this) }>
<img className="img-responsive" data-itemIndex={index} src={image} />
</div>
<div className="productInfo">
<p>{productname}</p>
<p>Aantal: {quantity}</p>
</div>
<div className="bdone">
<button className="btn btn-lg btn-default btndone" data-itemIndex={index} onClick={this.handleDoneAction}>Done</button>
</div>
</div>
}) : null
}
</div>
<h2>Mandje</h2>
<div className="panel">
{
!isLoading && dealtOrders.length > 0 ? dealtOrders.map((dorder, index) => {
const {productname, image, quantity} = dorder;
return<div className="productDone" key={index}>
<div className="plaatjediv">
<img className="img-responsive" src={image} />
</div>
<div className="productInfo">
<p>{productname}</p>
<p>Aantal: {quantity}</p>
</div>
<div className="bdone">
<button className="btn btn-lg btn-default btndone" data-itemIndex={index} onClick={this.handleUndoAction}>Undo</button>
</div>
</div>
}) : null
}
</div>
<ProductModal open={this.state.open} handleClose={this.handleClose.bind(this)}
title={this.state.modal.productname} plaatje={this.state.modal.image} orderid={this.state.modal.orderid}/>
<div className="loader">
<div className="icon"></div>
</div>
</div>
</div>
);
}
}
export default App;
productmodal.js
import React from 'react';
class ProductModal extends React.Component {
constructor() {
super();
this.getUpdatedProduct = this.getUpdatedProduct.bind(this);
}
handleClose() {
this.props.handleClose();
}
UserAction(event) {
let orderid = event.target.value;
fetch('http://localhost:54408/api/orders/change/testing-9!8-7!6/' + orderid + '/10-04-2018');
console.log("order id = " + event.target.value);
this.getUpdatedProduct();
}
getUpdatedProduct() {
console.log("fetching new product");
}
render() {
//const open = this.props.open;
const {title, plaatje, open, orderid} = this.props;
return (
<div className={'modal fade in '+(open?'show':'')} role="dialog">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button type="button" onClick={this.handleClose.bind(this)} className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 className="modal-title">{title}</h4>
</div>
<div className="modal-body">
<img className="plaatjediv img-responsive" src={plaatje} />
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default"
onClick={this.handleClose.bind(this)}>Sluiten
</button>
<button type="button" onClick={this.UserAction.bind()} value={orderid} className="btn btn-primary">Product niet aanwezig</button>
</div>
</div>
</div>
</div>
)
}
}
export default ProductModal;

Resources