I'm creating a cart and I need to add the item, the function has the id of the item as a requirement, but my item only generates the _id and not just the id. The problem to be simple for those who have a lot of knowledge, thanks in advance to the collaborators
https://www.npmjs.com/package/react-use-cart
Index.js ( Product details )
import React, { useState, useEffect } from "react";
import { useParams } from "react-router";
import Popup from "reactjs-popup";
import "reactjs-popup/dist/index.css";
import { ThreeDots } from "react-loader-spinner";
import { useCart } from "react-use-cart";
//Local
import Nav from "../../components/Nav";
import api from "../../../services/api";
import Best from "../Best/index";
import { TitleCaurosel } from "../style";
//Icons / Images
import { AiFillStar } from "react-icons/ai";
import { BsArrowLeft, BsArrowRight } from "react-icons/bs";
//Style
import {
Product,
Images,
Main,
Other,
Details,
Title,
Description,
Stars,
Colors,
Color,
ColorSelected,
Price,
Cart,
} from "./style";
const Index = () => {
const params = useParams();
const { addItem } = useCart();
const [data, setData] = useState(undefined);
const [error, setError] = useState(undefined);
const [color, setColor] = useState(undefined);
const [nameColor, setNameColor] = useState(undefined);
const [index, setIndex] = useState(0);
const [popup, setPopup] = useState(false);
const [current, setCurrent] = useState(0);
const [main, setMain] = useState(undefined);
const ref = React.createRef();
const { height, width } = useWindowDimensions();
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height,
};
}
function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(
getWindowDimensions()
);
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowDimensions;
}
const config = {
headers: {
"Content-type": "application/json",
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
};
useEffect(() => {
api.get(`/items/${params.id}`).then((response) => setData(response.data));
}, []);
const addToCart = () => {
if (color !== undefined) {
api
.post(
`/cart`,
{
itemId: params.id,
quantity: 1,
colors: data.images,
colorSelected: color,
img: data.images[0].src,
},
config
)
.then((response) => {
if (response.status === 200 || response.status === 201) {
window.location.pathname = "/Cart";
}
});
} else {
setError(1);
}
};
const numberFormat = (value) =>
new Intl.NumberFormat("pt-br", {
style: "currency",
currency: "BRL",
}).format(value);
const handleTab = (index) => {
setMain(undefined);
setIndex(index);
if (color !== undefined && nameColor !== undefined) {
setColor(undefined);
setNameColor(undefined);
}
};
const nextSlide = () => {
setCurrent(current === data.images.length - 1 ? 0 : current + 1);
};
const prevSlide = () => {
setCurrent(current === 0 ? data.images.length - 1 : current - 1);
};
useEffect(() => {
if (data !== undefined) {
if (!Array.isArray(data.images) || data.images.length <= 0) {
return null;
}
}
});
const changeColor = (id, name) => {
setColor(id);
setNameColor(name);
setError(undefined);
const filter = data.images.filter((item) => item._id === id);
setMain(filter[0].src);
};
return data !== undefined ? (
<div>
{/*Popup*/}
{popup === true && (
<Popup
open={true}
position="center center"
onClose={() => setPopup(false)}
>
<section className="slider">
<BsArrowLeft className="left-arrow" onClick={prevSlide} />
<BsArrowRight className="right-arrow" onClick={nextSlide} />
{data.images.map((slide, index) => {
return (
<div
className={index === current ? "slide active" : "slide"}
key={index}
>
{index === current && (
<div
style={{
width: width / 2,
height: height / 2,
backgroundImage: `url(${slide.src})`,
backgroundRepeat: "no-repeat",
backgroundSize: "contain",
backgroundPosition: "center",
}}
/>
)}
</div>
);
})}
</section>
</Popup>
)}
<Nav />
<div
style={{
height: "90vh",
display: "grid",
justifyContent: "center",
alignItems: "center",
gridTemplateColumns: "85%",
gridTemplateRows: "100%",
gridColumnGap: "5px",
}}
>
<Product key={data._id}>
<Images>
<div
style={{
display: "grid",
marginRight: "3%",
height: height / 1.3,
}}
ref={ref}
>
<Other
style={{
width: width / 10,
backgroundImage: `url(${data.images[0].src})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "60%",
}}
alt={`Image de ${data.name}`}
key={0}
onClick={() => handleTab(0)}
/>
{data.images[1] !== undefined && (
<Other
style={{
marginTop: "5%",
width: width / 10,
backgroundImage: `url(${data.images[1].src})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "60%",
}}
alt={`Image de ${data.images[1].name}`}
key={1}
onClick={() => handleTab(1)}
/>
)}
{data.images[2] !== undefined && (
<Other
style={{
marginTop: "5%",
width: width / 10,
backgroundImage: `url(${data.images[2].src})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "60%",
}}
alt={`Image de ${data.name}`}
key={2}
onClick={() => handleTab(2)}
/>
)}
{data.images[3] !== undefined && (
<Other
style={{
marginTop: "5%",
width: width / 10,
backgroundImage: `url(${data.images[3].src})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "60%",
}}
alt={`Image de ${data.name}`}
key={1}
onClick={() => handleTab(3)}
/>
)}
{data.images[4] !== undefined && (
<div>
{data.images.length < 5 ? (
<Other
style={{
width: width / 10,
backgroundImage: `url(${data.images[3].src})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "60%",
}}
alt={`Image de ${data.name}`}
key={2}
onClick={() => handleTab(3)}
/>
) : (
<Other
style={{
width: width / 10,
}}
onClick={() => setPopup(true)}
alt={`Image de ${data.name}`}
>
<p>+ 5</p>
</Other>
)}
</div>
)}
</div>
<div
style={{
backgroundColor: "#F6F6F6",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<Main
style={{
backgroundImage: `url(${
main === undefined ? data.images[index].src : main
})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "80%",
width: width / 2.8,
height: height / 1.5,
}}
/>
</div>
</Images>
<Details>
<Title>{data.name}</Title>
<Description>{data.description}</Description>
<Stars>
<AiFillStar />
<AiFillStar />
<AiFillStar />
<AiFillStar />
<AiFillStar />
<p>441 Avaliações</p>
</Stars>
<Colors>
{error === undefined && color === undefined && (
<p style={{ color: "#000" }}>Selecione uma cor:</p>
)}
{error === 1 && color === undefined && (
<p style={{ color: "#ff0000" }}>
Selecione uma cor: (Obrigatório)
</p>
)}
{error === undefined &&
color !== undefined &&
nameColor !== undefined && (
<p style={{ color: "#000" }}>Cor selecionada: {nameColor}</p>
)}
<div
style={{
display: "flex",
marginTop: "1%",
width: "100%",
flexWrap: "wrap",
alignItems: "center",
}}
>
{data.images.map((item) =>
color === item._id ? (
<ColorSelected onClick={() => setColor(undefined)}>
<div style={{ backgroundColor: item.color }} />
</ColorSelected>
) : (
<Color
style={{ backgroundColor: item.color }}
onClick={() => {
changeColor(item._id, item.name);
}}
/>
)
)}
</div>
</Colors>
<Price>{numberFormat(data.price)}</Price>
{console.log(data)}
<Cart onClick={() => addItem(data)}>
Adicionar ao carrinho
</Cart>
</Details>
</Product>
</div>
<div style={{ paddingLeft: "130px" }}>
<TitleCaurosel>Você pode gostar!</TitleCaurosel>
<Best />
</div>
</div>
) : (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
width: width,
height: height,
}}
>
<ThreeDots
height="300"
width="300"
radius="9"
color="#8c6d55"
ariaLabel="three-dots-loading"
wrapperStyle={{}}
wrapperClassName=""
visible={true}
/>
</div>
);
};
export default Index;
Cart.js
import React, { useState, useEffect } from "react";
import Nav from "../components/Nav";
import Select from "react-select";
import api from "../../services/api";
import { ThreeDots } from "react-loader-spinner";
import { useCart } from "react-use-cart";
//Icons
import { BiTrash } from "react-icons/bi";
import { MdOutlineEditLocationAlt } from "react-icons/md";
import { HiOutlineShoppingBag } from "react-icons/hi";
//Style
import {
Container,
Box1,
Box2,
Box3,
Title,
Product,
Image,
Name,
Price,
Border,
Stock,
PriceTotal,
Delete,
Cupom,
BorderTraced,
Subtotal,
Items,
Total,
Checkout,
NextToBuy,
Empty,
} from "./style";
const Index = () => {
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height,
};
}
function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(
getWindowDimensions()
);
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowDimensions;
}
const { height, width } = useWindowDimensions();
const {
isEmpty,
items,
cartTotal,
updateItemQuantity,
removeItem,
emptyCart,
} = useCart();
return (
<Container>
{isEmpty ? (
<Empty>
<Nav />
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
textAlign: "center",
height: "80vh",
}}
>
<div>
<HiOutlineShoppingBag className="icon-empty" />
<h1>Sua sacola está vazia</h1>
<p className="text-empty">
Parece que você não adicionou nada a sua sacola. <br /> Vá em
frente e explore as principais categorias.
</p>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
textAlign: "center",
}}
>
<a className="button" href="/#Produtos">
Explorar produtos
</a>
</div>
</div>
</div>
</Empty>
) : (
<Container>
<Nav />
<div
style={{
display: "flex",
justifyContent: "center",
height: height,
marginTop: "3%",
marginBottom: "10%",
}}
>
<Box1 style={{ width: width / 2.8, height: height }}>
<Title>Seus items</Title>
</Box1>
<div>
<Box2 style={{ width: width / 4, height: height / 5 }}>
<Title>Frete</Title>
<p className="title">Endereço:</p>
<span></span>
<span></span>
<p className="title">Estimativa de entrega:</p>
<span>30/12/2022</span>
<MdOutlineEditLocationAlt />
</Box2>
<Box3 style={{ width: width / 4, height: height / 1.4 }}>
<Cupom>
<input placeholder="Cupom de desconto" />
<button>Aplicar</button>
</Cupom>
<BorderTraced />
<Subtotal>
<p>Subtotal</p>
<p></p>
</Subtotal>
<Items>
<div>
<p>Frete</p>
<p>R$ 399,99</p>
</div>
</Items>
<BorderTraced />
<Total>
<p>Total</p>
<p></p>
</Total>
<Checkout>Finalizar compra</Checkout>
<NextToBuy
onClick={() => {
window.location.pathname = "/Products";
}}
>
Continuar comprando
</NextToBuy>
</Box3>
</div>
</div>
</Container>
)}
</Container>
);
};
export default Index;
Index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import Routes from './routes';
import { CartProvider } from 'react-use-cart';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<CartProvider>
<Routes />
</CartProvider>
</React.StrictMode>
);
Not sure if this is the best/most efficient approach, but you could always create an Item object with the attributes required for the addItem() method. Then map the required data from your data object to the new item object, and instead of using addItem(data) you could use addItem(item).
Add the property when setting the value:
useEffect(() => {
api.get(`/items/${params.id}`)
.then(({ data }) => {
setData({
...data,
id: data._id
});
});
}, []);
I am visualising a List of Cards with content and what I want to achieve is to set contentEditable=true to the clicked card via its button. I am able to select the content of the element, however contentEditable is not set to true and it returns the following error instead:
Uncaught TypeError: Cannot create property 'contentEditable' on string
And I cant figure out why. What am I doing wrong here and how can I set contentEditable to true for the clicked element via its button?
Here is my code:
import * as React from 'react';
import { ListView } from '#progress/kendo-react-listview';
import { Input } from '#progress/kendo-react-inputs';
import {
Card,
CardTitle,
CardImage,
CardActions,
CardBody,
} from '#progress/kendo-react-layout';
import { Pager } from '#progress/kendo-react-data-tools';
import articles from '../data/articles.json';
import { BubbleChart } from "../components/products/BubbleChart"
const onEdit = (item) => {
console.log(item.Content)
let cardContent = item.Content.contentEditable = "true";
return cardContent
}
const MyItemRender = (props) => {
let item = props.dataItem;
return (
<div
style={{
padding: '20px 20px',
}}
className="parent-container"
>
<div className="k-card-list">
<Card
style={{
width: 260,
height: 340
}}
>
<CardBody
style={{
borderBottom: 'solid 1px rgba(0,0,0,.08)'
}}
>
<CardImage
src={require(`../assets/article-images/${item.Image}`)}
style={{
width: 260,
height: 140,
maxWidth: 260,
}}
/>
<CardTitle
style={{
fontSize: 18,
}}
/>
<CardTitle>{item.Title}</CardTitle>
<CardTitle>{item.Subtitle}</CardTitle>
<p className="content">
Some quick example text to build on the card title and make up the
bulk of the card content.
</p>
</CardBody>
<CardActions>
<div className="footer-buttons-container">
<span>
<span className="k-button k-button-md k-button-rectangle k-rounded-md k-button-flat k-button-flat-base">
<span className="k-icon k-i-preview"></span>Review
</span>
</span>
<span>
<span className="k-button k-edit-button k-button-md k-button-rectangle k-rounded-md k-button-flat k-button-flat-primary" onClick={() => onEdit(item)}>
<span className="k-icon k-i-edit"></span>Edit
</span>
</span>
</div>
</CardActions>
</Card>
</div>
</div>
);
};
export const Products = () => {
const [filteredList, setFilteredList] = React.useState(articles);
const [value, setValue] = React.useState('');
const [page, setPage] = React.useState({
skip: 0,
take: 10,
});
const handlePageChange = (e) => {
setPage({
skip: e.skip,
take: e.take,
});
};
const handleChange = React.useCallback((event) => {
setValue(event.target.value);
const results = articles.filter(post => {
if (event.target.value === "") return articles
return post.Title.includes(event.target.value)
})
console.log(results)
setFilteredList(results)
});
const { skip, take } = page;
return <div>
<div className="chart-container">
<br/>
<br/>
<BubbleChart/>
</div>
<div className="input-container">
<Input
style={{
border: '2px solid #ccc',
boxShadow: 'inset 0px 0px 0.5px 0px rgba(0,0,0,0.0.1)',
}}
placeholder={'Search'}
value={value}
onChange={handleChange}
/>
</div>
<div className="listbox-card-container">
<ListView
data={filteredList.slice(skip, skip + take)}
item={MyItemRender}
style={{
width: '100%',
height: '100%',
}}
/>
<Pager
skip={skip}
take={take}
onPageChange={handlePageChange}
total={articles.length}
/>
</div>
</div>
}
Can't do multiple assigning in one line. add separate lines
const onEdit = (item) => {
console.log(item.Content)
const content = {...item.Content }
content.contentEditable = "true";
return content
}
I'm writing a code where I'm using react-range to create a range bar. along with it, I've got 2 textboxes that have the min and max values of the range. Currently, I'm able to update the range values by dragging and the text boxes get updated automatically. And I also want to update the price range using the textboxes mentioned, currently, the min box value works fine, but, when I try to update the max value, the value gets appended instead of updating. Unable to know where I'm going wrong.
Here is the code of the same.
import { useState } from "react";
import { Range, getTrackBackground } from "react-range";
export const PriceRange = () => {
const [priceValues, setPriceValues] = useState([1, 100]);
let step = 1;
const handleChange = (values: number[]) => {
if (values[0] > values[1]) {
values[0] = values[1];
}
if (values[1] < values[0]) {
values[1] = values[0];
}
setPriceValues(values);
};
return (
<>
{
<div
style={{
width: "50%",
maxWidth: "50%",
marginLeft: "auto",
marginRight: "auto"
}}
>
<div className="mb-8 text-gray-900 text-sm font-medium text-left">
Price
</div>
<div
style={{ padding: "1rem", marginTop: "1rem", marginBottom: "1rem" }}
>
<Range
step={step}
min={priceValues[0]}
max={priceValues[1]}
values={priceValues}
onChange={(values) => handleChange(values)}
renderTrack={({ props, children }) => (
<div
{...props}
style={{
...props.style,
background: getTrackBackground({
values: priceValues,
colors: ["#c4c4c442", "black", "#c4c4c442"],
min: priceValues[0],
max: priceValues[1]
}),
height: "0.5rem",
width: "100%"
}}
>
{children}
</div>
)}
renderThumb={({ index, props }) => (
<div
{...props}
style={{
...props.style
}}
className="thumbs"
>
<div className="priceValues">{`$${
priceValues[index] === priceValues.length - 1
? priceValues[index] + "+"
: priceValues[index]
}`}</div>
</div>
)}
/>
</div>
<div className="rangeBoxesContainer">
<div className="rangeBox">
<div style={{ display: "flex" }}>Min $</div>
<input
className="rangeInputbox"
type="number"
value={priceValues[0]}
onChange={(e) => {
if (Number(e.target.value) < Number(priceValues[1])) {
let newValue = [...priceValues];
newValue[0] = Number(e.target.value);
setPriceValues(newValue);
}
}}
/>
</div>
<div className="rangeBox">
<div style={{ display: "flex" }}>Max $</div>
<input
className="rangeInputbox"
type="number"
value={priceValues[1]}
onChange={(e) => {
if (Number(e.target.value) > Number(priceValues[1])) {
let newValue = [...priceValues];
newValue[1] = Number(e.target.value);
setPriceValues(newValue);
}
}}
/>
</div>
</div>
</div>
}
</>
);
};
And here is a working code sandbox link. Can someone let me know where I'm going wrong?
Thanks
I want to synchronize a divs scroll with a body scroll.
I tried some examples with two divs but I couldn't manage fix it with the body scroll.
Sample code with two divs: https://codesandbox.io/s/react-custom-scroll-sync-of-2-divs-10xpi
My Code
https://codesandbox.io/s/funny-rain-ditbv
import "./styles.css";
import { useRef } from "react";
export default function App() {
const firstDivRef = useRef();
const secondDivRef = useRef();
const handleScrollFirst = (scroll) => {
secondDivRef.current.scrollTop = scroll.target.scrollTop;
};
const handleScrollSecond = (scroll) => {
firstDivRef.current.scrollTop = scroll.target.scrollTop;
};
return (
<div
className="App"
style={{
display: "flex",
}}
>
<div
onScroll={handleScrollFirst}
ref={firstDivRef}
style={{
height: "500px",
overflow: "scroll",
backgroundColor: "#FFDAB9",
position: "sticky",
top: "0px"
}}
>
<div style={{ height: 5000, width: 300 }}>
The first div (or it can be tbody of a table and etc.)
{[...new Array(1000)].map((_, index) => {
const isEven = index % 2 === 0;
return (
<div style={{ backgroundColor: isEven ? "#FFFFE0 " : "#FFDAB9" }}>
{index}
</div>
);
})}
</div>
</div>
<div
onScroll={handleScrollSecond}
ref={secondDivRef}
style={{
height: "100%",
backgroundColor: "#EEE8AA"
}}
>
<div style={{ height: 5000, width: 200 }}>
The second div
{[...new Array(1000)].map((_, index) => {
const isEven = index % 2 === 0;
return (
<div style={{ backgroundColor: isEven ? "#FFFFE0 " : "#FFDAB9" }}>
{index}
</div>
);
})}
</div>
</div>
</div>
);
}
It was easy to use different divs rather than using a div and window.
But finally managed to run it with a div and the body.
The trick is they block each other since they listen each others values.
import "./styles.css";
import { useEffect, useRef, useState } from "react";
export default function App() {
const firstDivRef = useRef();
const [scrollTop, setScrollTop] = useState(0);
const [disableBodyScroll, setDisableBodyScroll] = useState(false);
const handleScrollFirst = (scroll) => {
setScrollTop(scroll.target.scrollTop);
};
useEffect(() => {
if (firstDivRef.current && !disableBodyScroll) {
firstDivRef.current.scrollTop = scrollTop;
}
if (disableBodyScroll) {
window.scrollTo(0, scrollTop);
}
}, [firstDivRef, scrollTop, disableBodyScroll]);
useEffect(() => {
const onScroll = () => {
console.log(disableBodyScroll, window.scrollY);
if (!disableBodyScroll) {
setScrollTop(window.scrollY);
}
};
// clean up code
window.removeEventListener("scroll", onScroll);
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, [disableBodyScroll]);
return (
<div
className="App"
style={{
display: "flex"
}}
>
<div
onMouseEnter={() => setDisableBodyScroll(true)}
onMouseLeave={() => setDisableBodyScroll(false)}
onScroll={handleScrollFirst}
ref={firstDivRef}
style={{
height: "500px",
overflow: "scroll",
backgroundColor: "#FFDAB9",
position: "sticky",
top: "0px"
}}
>
<div style={{ height: 5000, width: 300 }}>
The first div (or it can be tbody of a table and etc.)
{[...new Array(1000)].map((_, index) => {
const isEven = index % 2 === 0;
return (
<div style={{ backgroundColor: isEven ? "#FFFFE0 " : "#FFDAB9" }}>
{index}
</div>
);
})}
</div>
</div>
<div
style={{
height: "100%",
backgroundColor: "#EEE8AA"
}}
>
<div style={{ height: 5000, width: 200 }}>
The second div
{[...new Array(1000)].map((_, index) => {
const isEven = index % 2 === 0;
return (
<div style={{ backgroundColor: isEven ? "#FFFFE0 " : "#FFDAB9" }}>
{index}
</div>
);
})}
</div>
</div>
</div>
);
}
https://codesandbox.io/s/ancient-dream-tzuel?file=/src/App.js
Try the next example. This is a quick sketch but maybe it will help you.
https://codesandbox.io/s/gallant-goldwasser-19g4d?file=/src/App.js
I am trying to hide the <li></li> element when it's overflowing (while scrolling, and just before scrolling after adding some products to the shopping cart), however, the clientHeight on the overflowingRef, which refers to the <li></li> element does not change when its content is overflowing. Any idea what i m doing wrong?
Please see the code for reference below:
import React, {useState, useRef, useEffect} from 'react';
import products from './mock.json';
export default function App() {
return (
<div style={{display: 'flex', flexDirection: 'row'}}>
<ShoppingCart products={products} />
</div>
);
}
function List({products, title, addProduct, removeProduct}) {
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'start-end',
}}
>
{title}
<ul
style={{
listStyle: 'none',
paddingInlineStart: '0px',
width: '500px',
height: '260px',
overflow: 'scroll',
paddingRight: '10px',
}}
>
{products.length === 0 ? (
<div>No products</div>
) : (
products.map(({category, price, stocked, name}, index) => (
<SuspendDisplayIfOverflowing>
{ref => (
<li
style={{
padding: '10px',
border: '1px solid blue',
display: 'flex',
justifyContent: 'space-between',
height: '18px',
overflow: 'scroll',
}}
ref={ref}
key={price}
>
<div style={{color: `${stocked ? 'green' : 'red'}`}}>
{`${name} - ${category} - available: ${stocked} - price: ${price}`}
</div>
{addProduct && stocked ? (
<button
onClick={() =>
addProduct({category, price, stocked, name})
}
>
Add
</button>
) : null}
{removeProduct ? (
<button onClick={() => removeProduct(index)}>Remove</button>
) : null}
</li>
)}
</SuspendDisplayIfOverflowing>
))
)}
</ul>
<Total prices={products.map(({price}) => getCleanPrice(price))} />
</div>
);
}
function ShoppingCart({products}) {
const [productsInCart, manipulateProduct] = useState([]);
const addProduct = product =>
manipulateProduct(productsInCart.concat(product));
const removeProduct = productIndex =>
manipulateProduct(
productsInCart.filter((_, index) => index !== productIndex),
);
return (
<>
<List
title="Available Products"
products={products}
addProduct={addProduct}
/>
<List
title="Shopping Cart"
products={productsInCart}
removeProduct={removeProduct}
/>
</>
);
}
function Total({prices}) {
const total = prices.reduce((accum, item) => (accum += parseFloat(item)), 0);
return <div>Total amount to pay: {total.toFixed(2)}</div>;
}
function getCleanPrice(price) {
return price.slice(1);
}
function SuspendDisplayIfOverflowing(props) {
const overflowingRef = useRef(null);
useEffect(() => {
console.log(
'oveflowing scroll height',
overflowingRef.current.scrollHeight,
);
console.log(
'oveflowing client height',
overflowingRef.current.clientHeight,
);
console.log(
'oveflowing client height',
overflowingRef.current.offsetHeight,
);
console.log(overflowingRef.current);
}, [overflowingRef]);
return props.children(overflowingRef);
}