Update quantity of duplicate product in cart reactjs - reactjs

I have a cart. I'm adding item to cart on click addToCart. However, it adds a duplicates of the same items, and not increasing it's quantity in cart. I also have an incrementCount and decrementCount for updating quantity of added items in cart. I want to make a function which will both add to cart and update the quantity in cart if item is the same
I also have a problem with my increment/decrement - it changes quantity of all added items, not the particular one I clicked. Also I want it to update cartTotal every time I'm clicking on incrementCount/decrementCount.
Here is the sandbox code
https://codesandbox.io/s/epic-night-s575k?file=/src/components/Menu.jsx

You need to have separate state variable count for each product thats in your cart.
You need to have your components like so
Cart component:
import React from "react";
import { FaTimes } from "react-icons/fa";
export default function Cart({
product,
removeFromCart,
count,
incrementCount,
decrementCount
}) {
const { image, title, price } = product;
return (
<>
<li className="cart-item__container">
<img src={image} alt={title} className="cart-item__image" />
<h4 className="cart-item__title">{title}</h4>
<h5 className="cart-item__price">{price}$</h5>
<button disabled={count === 1} onClick={() => decrementCount(product)}>
-
</button>
<span>{count}</span>
<button onClick={() => incrementCount(product)}>+</button>
<FaTimes
className="icon__remove"
onClick={() => removeFromCart(product)}
></FaTimes>
</li>
</>
);
}
Menu component:
import React, { useState } from "react";
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
import "react-tabs/style/react-tabs.css";
import { FaShoppingCart } from "react-icons/fa";
import products from "./products";
import Product from "./Product";
import Cart from "./Cart";
const Menu = () => {
const [cart, setCart] = useState([]);
const addToCart = (el) => {
const cartCopy = cart.slice();
const index = cartCopy.findIndex((product) => el.id === product.id);
if (index === -1) {
cartCopy.push({ ...el, count: 1 });
} else {
const pr = cartCopy[index];
cartCopy[index] = { ...pr, count: pr.count + 1 };
}
setCart(cartCopy);
};
const removeFromCart = (el) => {
const cartCopy = cart.filter((product) => el.id !== product.id);
setCart(cartCopy);
};
const decrementCount = (el) => {
const cartCopy = cart.slice();
const index = cartCopy.findIndex((product) => el.id === product.id);
const pr = cartCopy[index];
cartCopy[index] = { ...pr, count: pr.count - 1 };
setCart(cartCopy);
};
const getCartTotal = () => {
return cart.reduce(
(total, product) => total + product.price * product.count,
0
);
};
const getCartCount = () => {
// return cart.length;
// =======OR=========
return cart.reduce((total, product) => total + product.count, 0);
};
return (
<>
<Tabs className="tabs-wrapper" id="menu">
<TabList className="tabs">
<Tab className="tab-item">Burgers</Tab>
<Tab className="tab-item">Lunch of the day</Tab>
<Tab className="tab-item">Crepes</Tab>
</TabList>
<TabPanel>
<div className="burgers">
<ul>
{products
.filter((product) => product.category === "burger")
.map((product) => (
<Product
key={product.id}
product={product}
addToCart={addToCart}
/>
))}
</ul>
</div>
</TabPanel>
<TabPanel>
<div className="lunch">
<h4>Sweet lunch today!</h4>
<span>7$</span>
<p>
You can choose one of our 3 sweet crepes + one of our 4 cold
drinks!
<br />
Nutella crepe, Crepe with salted caramel and nuts or Oreo Bang
crepe with whipped cream and raspberries.
<br />
For drink - one of our homemade lemonades - Melon, Orange or
Lemon-Mint. Or a Frozen Coffee!
</p>
</div>
</TabPanel>
<TabPanel>
<div className="crepes">
<ul>
{products
.filter((product) => product.category === "crepe")
.map((product) => (
<Product
key={product.id}
product={product}
addToCart={addToCart}
/>
))}
</ul>
</div>
</TabPanel>
</Tabs>
<FaShoppingCart className="cart-icon">{getCartCount()}</FaShoppingCart>
{cart.map((el) => (
<Cart
key={el.id}
product={el}
count={el.count}
removeFromCart={removeFromCart}
incrementCount={addToCart}
decrementCount={decrementCount}
/>
))}
<h4 className="cart__total">Your Order Total Price: {getCartTotal()}$</h4>
<button className="btn__clear" onClick={() => setCart([])}>
Clear cart
</button>
</>
);
};
export default Menu;

Related

How can i use a hook in a conditional statement?

how can i use a hook like below in an if statement? I am trying use a button click to indicate a change in category. once the change in category is set, pagination aligns the count in accordance to.
const [category, setCategory] = useState('')
let count = ContentsCount
if (category) {
count = filteredContentCount
}
/// ...
<ul className="dropdown-menu">
{categories.map(category => (
<li
style={{
cursor: 'pointer',
listStyleType: 'none'
}}
key={category}
onClick={() => setCategory(category)}
>
<a className='dropdown-item'>{category}</a>
</li>
))}
</ul>
...
{resPerPage <= count && (
<div className="d-flex justify-content-center mt-5">
<Pagination
activePage={currentPage}
itemsCountPerPage={resPerPage}
totalItemsCount={contentsCount}
onChange={setCurrentPageNo}
nextPageText={'Next'}
prevPageText={'Prev'}
firstPageText={'First'}
lastPageText={'Last'}
itemClass="page-item"
linkClass="page-link"
/>
</div>
)}
this is the request in the backend for content and its item counts. ideally the goal is to get total count per category.
exports.getContents = asyncErrors (async (req,res,next) =>{
const contentsCount = await Content.countDocuments(); //162
console.log(contentsCount)
const resPerPage = 9;
const apiFeatures = new APIFeatures(Content.find(),req.query).search().filter().pagination(resPerPage)
let contents = await apiFeatures.query;
console.log(contents)
let filteredContentCount = contents.length;
console.log(filteredContentCount)
/* check for category request
assign total amount of objects within a category to a variable/constant
if(category.req){
let contentCount = category.counter
}
*/
setTimeout(() => {
res.status(200).json({
success:true,
contents,
contentsCount,
resPerPage,
filteredContentCount
})
}, 2000);
})
filtering and pagination:
class APIFeatures {
constructor(query,queryStr){
this.query = query;
this.queryStr = queryStr;
}
search(){
const keyword = this.queryStr.keyword ? {
name:{
$regex:this.queryStr.keyword,
$options:'i'
}
}:{}
console.log(keyword)
this.query = this.query.find({...keyword})
return this;
}
filter(){
const queryCopy = {... this.queryStr}
//removing fields from the query
// console.log(queryCopy)
const removeFields =['keyword','limit','page']
removeFields.forEach(el => delete queryCopy[el]);
// console.log(queryCopy)
//advance filter for title,etc..
let queryStr = JSON.stringify(queryCopy)
queryStr = queryStr.replace(/\b(gt|gte|lt|lte)\b/g,match=>`$${match}`)
console.log(queryCopy)
console.log(queryStr)
this.query = this.query.find(JSON.parse(queryStr));
return this;
}
pagination(resPerPage){
const currentPage = Number(this.queryStr.page) || 1;
const skip = resPerPage * (currentPage-1)
this.query = this.query.limit(resPerPage).skip(skip)
return this
}
}
module.exports = APIFeatures
main react code:
import React, { Fragment, useEffect, useState } from 'react'
import '../App.css'
import { MetaData } from './MetaData'
import { Textarea } from '#nextui-org/react';
import Pagination from 'react-js-pagination'
import ContCard from './Card/ContCard'
import { useDispatch, useSelector } from 'react-redux'
import { getContents } from '../actions/contentActions'
import { useAlert } from 'react-alert'
// import Dropdown from 'react-bootstrap/Dropdown';
import { Dropdown } from 'rsuite';
import { MDBDropdown, MDBDropdownMenu, MDBDropdownToggle, MDBDropdownItem } from 'mdb-react-ui-kit';
import ReactPaginate from 'react-paginate';
export default function Content() {
const [currentPage, setCurrentPage] = useState(1)
const dispatch = useDispatch();
const alert = useAlert()
const [category, setCategory] = useState('')
const { loading, error, contents, contentsCount, resPerPage, filteredContentCount } = useSelector(state => state.contents);
const categories = [
...
]
useEffect(() => {
if (error) {
return alert.error(error)
}
dispatch(getContents(currentPage, category));
}, [dispatch, alert, error, currentPage, category])
function setCurrentPageNo(pageNumber) {
setCurrentPage(pageNumber)
}
// const setCategories = (category)=>{
// setCategory(category)
// }
var count = contentsCount;
console.log('before:' + count)
function setCategories(category) {
// count = filteredContentCount
// console.log(' filtered:' + count)
setCategory(category)
}
console.log('after count:' + count)
return (
<Fragment>
{loading ? <h1>Loading ...</h1> : (
<Fragment>
<section id="contents" className="container mt-5">
<div className="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Categories
</button>
<ul className="dropdown-menu">
{categories.map(category => (
<li
style={{
cursor: 'pointer',
listStyleType: 'none'
}}
key={category}
// onClick={() => setCategory(category)}
onClick={() => setCategories(category)}
>
<a className='dropdown-item'>{category}</a>
</li>
))}
</ul>
</div>
<div className="row" id='cards'>
<Fragment>
<div className="col-6 col-md-9" >
{category}
<div className="row" >
{contents && contents.map(content => (
<ContCard key={content._id} content={content} col={4} />
))}
</div>
</div>
</Fragment>
</div>
</section>
{(resPerPage <= count) && (
<div className="d-flex justify-content-center mt-5">
<Pagination
activePage={currentPage}
itemsCountPerPage={resPerPage}
totalItemsCount={contentsCount}
onChange={setCurrentPageNo}
nextPageText={'Next'}
prevPageText={'Prev'}
firstPageText={'First'}
lastPageText={'Last'}
itemClass="page-item"
linkClass="page-link"
/>
</div>
)}
</Fragment>
)}
</Fragment>
)
}
I am looking to fix pagination. It disappears once you have clicked to set the category button also pagination doesnt keep track of all the possible pages per category.

How to show one component and hide others using useState and useEffect?

I want to make a component in the front page that displays list of vehicles with navigation buttons that shows list of the selected button.
Is there a better way I could write this code below because I want the list of categories to be much longer? Or are there other methods I can use other than useState & useEffect? I'm using Next.js
const Vehicles = () => {
const [selectedCategory, setSelectedCategory] = useState("cars")
const [cars, setCars] = useState(true)
const [bikes, setBikes] = useState(false)
const [motorcycles, setMotorcyles] = useState(false)
const [scooters, setScooters] = useState(false)
useEffect(() => {
if (selectedCategory === "cars") {
setCars(true)
setBikes(false)
setMotorcyles(false)
setScooter(false)
}
if (selectedCategory === "bikes") {
setBikes(true)
setCars(false)
setMotorcyles(false)
setScooters(false)
}
if (selectedCategory === "motorcycles") {
setMotorcyles(true)
setCars(false)
setBikes(false)
setScooters(false)
}
if (selectedCategory === "scooters") {
setScooters(true)
setCars(false)
setBikes(false)
setMotorcyles(false)
}
}, [selectedCategory])
return (
<div>
<div>
<button onClick={() => setSelectedCategory("cars")}> Cars </button>
<button onClick={() => setSelectedCategory("bikes")}> Bikes </button>
<button onClick={() => setSelectedCategory("motorcycles")}> Motorcycles </button>
<button onClick={() => setSelectedCategory("scooters")}> Scooters </button>
</div>
{cars && (
<div>
<Cars />
</div>
)}
{bikes && (
<div>
<Bikes />
</div>
)}
{motorcycles && (
<div>
<Motorcycles />
</div>
)}
{scooters && (
<div>
<Scooters />
</div>
)}
</div>
);
};
export default Vehicles;
These things like abstraction and code refactor tend to differ from person to person. But what I would generally prefer is something between abstraction and readability. Since readability is much more important I would go along this way
const allCategory = {
cars: 0,
bikes: 1,
motorcycles: 2,
scooters: 3
}
const Vehicles = () => {
// set cars as default category. If you don't want it change it to be any integer before 0
const [category, setCategory] = useState(allCategory.cars)
return (
<div>
<div>
<button onClick={() => setCategory(allCategory.cars)}> Cars </button>
<button onClick={() => setCategory(allCategory.bikes)}> Bikes </button>
<button onClick={() => setCategory(allCategory.motorcycles)}> Motorcycles </button>
<button onClick={() => setCategory(allCategory.scooters)}> Scooters </button>
</div>
<div>
{category === allCategory.cars && <Cars />}
{category === allCategory.bikes && <Bikes />}
{category === allCategory.motorcycles && <Motorcycles />}
{category === allCategory.scooters && <Scooters />}
</div>
</div>
);
};
export default Vehicles;
If you want to go absolutely crazy. You can decrease this to be in about 4-5 lines in return statement. But I prefer this to be much cleaner
I think you could do something more like
const Vehicles = () => {
const [selectedCategory, setSelectedCategory] = useState("cars")
const renderCat = (category) =>{
switch(category){
case "cars":
return <Cars />
//etc...
}
}
return (
<div>
<div>
<button onClick={() => setSelectedCategory("cars")}> Cars </button>
<button onClick={() => setSelectedCategory("bikes")}> Bikes </button>
<button onClick={() => setSelectedCategory("motorcycles")}> Motorcycles </button>
<button onClick={() => setSelectedCategory("scooters")}> Scooters </button>
</div>
<div>
{renderCat(selectedCategory)}
</div>
</div>
);
};
export default Vehicles;
You could do like this:
const categories = [
{
name: "cars",
title: "Cars",
component: Cars
},
{
name: "bikes",
title: "Bikes",
component: Bikes
},
{
name: "motorcyles",
title: "Motorcyles",
component: Motorcyles
},
{
name: "scooters",
title: "Scooters",
component: Scooters
}
];
const Vehicles = () => {
const [selectedCategory, setSelectedCategory] = useState("cars")
return (
<div>
<div>
{categories.map(({ name, title }) => (
<button onClick={() => setSelectedCategory(name)}>
{title}
</button>
))}
</div>
{categories.map(({ component: Component, name }) => {
if(selectedCategory !== name) return;
return (
<div>
<Component />
</div>
);
})}
</div>
);
};
export default Vehicles;
The category objects can be different depending on what you want to display. Having both name and title is not essential, it's just an example.

Getting error when adding a function to my react app

I'm new to react and followed a tutorial to do a shopping cart. In the end, I added a function that would give me the total cost of the products, but I get an error when adding products and clicking on Cart "productList.reduce is not a function". You can see this function (getTotalCost) in Cart. I tried to solve this but I get other errors. These are my files:
ProductsPage :
import React, {useState} from 'react'
import './ProductsPage.css'
import Products from '../../components/Products'
import Cart from '../../components/Cart'
const PAGE_PRODUCTS = 'products';
const PAGE_CART = 'cart';
function ProductsPage() {
const [cart, setCart] = useState ([]);
const [page, setPage] = useState (PAGE_PRODUCTS);
const addToCart = (product) => {
setCart ([...cart, {...product}])
}
const removeFromCart = (productToRemove) => {
setCart(cart.filter(product => product !== productToRemove))
}
const navigateTo = (nextPage) => {
setPage(nextPage);
};
return (
<div className="productspage">
<header>
<button className="cart-btn" onClick={()=> navigateTo(PAGE_CART)}>
Go to Cart ({cart.length})
</button>
<button className="products-btn" onClick={()=> navigateTo(PAGE_PRODUCTS)}>
View Products
</button>
</header>
{page === PAGE_PRODUCTS && <Products addToCart={addToCart}/>}
{page === PAGE_CART && <Cart cart={cart} removeFromCart={removeFromCart} />}
<div>
</div>
</div>
);
};
export default ProductsPage;
Products:
import React, {useState} from 'react'
function Products ({ addToCart }) {
const [products] = useState ([
{
name: 'Breakfast ',
cost:'9.99$',
image: 'https://images.unsplash.com/photo-1569420067112-b57b4f024595?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80',
},
{
name: 'Breakfast box ',
cost:'8.99$',
image: 'https://images.unsplash.com/photo-1569419910356-f63064754fc9?ixlib=rb-1.2.1&auto=format&fit=crop&w=700&q=80',
},
{
name: 'Snack box ',
cost:'6.99$',
image: 'https://images.unsplash.com/photo-1569419882964-7db5d339951b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80',
},
{
name: '4 small breakfast bowls ',
cost:'9.99$',
image: 'https://images.unsplash.com/photo-1570649857669-4ad9f896435d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=703&q=80',
}
])
return (
<>
<h1 className="products-title">Products</h1>
<div className="products">
{products.map((product , index) => (
<div className="product" key={index}>
<h3>{product.name}</h3>
<h4>{product.cost}</h4>
<img src={product.image} alt={product.name}/>
<p></p>
<button onClick={() => addToCart(product)}>
Add to Cart
</button>
</div>
))}
</div>
</>
)
}
export default Products;
Cart
import React from 'react'
import products from '../../components/Products'
function Cart ({ cart, removeFromCart }) {
const getTotalCost = (productList) => (
productList.reduce((totalCost, { cost: itemCost }) => totalCost += parseFloat(itemCost), 0)
);
return (
<>
<h1>Cart</h1>
<div className="products">
{cart.map((product , index) => (
<div className="product" key={index}>
<h3>{product.name}</h3>
<h4>{product.cost}</h4>
<img src={product.image} alt={product.name}/>
<button onClick={() => removeFromCart(product)}>
Remove
</button>
{getTotalCost(products)}
</div>
))}
</div>
</>
)
}
export default Cart;
In the second code snippet, where you are calling {getTotalCost(products)}, you are using the products component you are importing on line 2, which is a Component, not a List, so the reduce function does not exist on it, which is why you're seeing that error.
You probably want {getTotalCost(cart)} instead.

Reset pagination to the first page by clicking a button outside the component

I'm using material UI usePagination hook to create a custom pagination component, so far so good, the functionality works as expected but I was wondering how I can be able to reset the pagination to the first page by triggering a button that is not part of the pagination component.
Does anyone has an idea on how to trigger that?
This is my component.
import React from "react";
import PropTypes from "prop-types";
import { usePagination } from "hooks";
function arrow(type) {
return (
<i
className={`fa fa-chevron-${
type === "next" ? "right" : "left"
} page-icon`}
/>
);
}
function Pagination({ data, itemCount, onChange }) {
const { items } = usePagination({
count: Math.ceil(data.length / itemCount, 10),
onChange
});
return (
<nav aria-label="Paginator">
<ul className="pagination-component">
{items.map(({ page, type, selected, ...item }, index) => {
let children;
if (type === "start-ellipsis" || type === "end-ellipsis") {
children = "…";
} else if (type === "page") {
children = (
<button
type="button"
automation-tag={`page-${page}`}
className={`page-button ${selected ? "selected" : ""}`}
{...item}
>
{page}
</button>
);
} else {
children = (
<button
automation-tag={type}
className="page-button"
type="button"
{...item}
>
<span className="d-none">{type}</span>
{arrow(type)}
</button>
);
}
return (
// eslint-disable-next-line react/no-array-index-key
<li key={index} className="page-item">
{children}
</li>
);
})}
</ul>
</nav>
);
}
What I'm trying is to create a select component that the onChange function will sort the data, depending on the selection, but when the data is sorted I want to return the pagination component to the first page
const TableVizContainer = props => {
const [currentPage, setCurrentPage] = useState(1);
const [sortColumn, setSortColumn] = useState(1);
const [range, setRange] = useState({
start: 0,
end: 25
});
const onChangePage = (_event, page) => {
setCurrentPage(page);
setRange({
start: 25 * (page - 1),
end: 25 * page
});
};
const onSelectChange = event => {
const { value } = event.target;
setCurrentPage(1);
setSortColumn(parseInt(value, 10));
};
return (
<div
className="table-viz-container container-fluid my-4 float-left"
automation-tag={`table-viz-${automationId}`}
>
<div className="d-flex justify-content-between mb-3 leaderboard-meta">
<span className="leaderboard-title">{visualization.title}</span>
<div className="mr-5">
<label htmlFor="sort-table-select">
Sort By:
<select
id="sort-table-select"
onChange={onSelectChange}
value={sortColumn}
>
{visualization.columns.map((column, index) => {
const uniqueId = uuidv1();
return (
<option key={uniqueId} value={index}>
{setSelectValue(column, visualization.metrics)}
</option>
);
})}
</select>
</label>
</div>
</div>
<div className="d-block d-sm-flex justify-content-between align-items-center my-2 px-2">
<span className="page-items-count" automation-tag="pagination-count">
{`Showing ${range.start === 0 ? 1 : range.start + 1} - ${
range.end <= visualization.rows.length
? range.end
: visualization.rows.length
} of ${visualization.rows.length}.`}
</span>
<Pagination
currentPage={currentPage}
data={visualization.rows}
itemCount={25}
onChange={onChangePage}
/>
</div>
</div>
);
};
Does anyone has an idea on how to reset and move the pagination page to the first one without clicking the component?
There are two ways.
1. Passing Props
Let's just say you have a function called jump() and passing 1 as an argument will reset the pagination. So, you can pass the jump function as a property and reuse that on other components.
function jump(){
setCurrentPage(1)
}
<MyCompnent resetPage={jump} />
// MyComponent
function MyComponent({resetPage}){
return (
<button onClick={resetPage(1)}></button>
)
}
2. On Changing Route
You can reset your pagination when your route will change. For example, you are using a router npm package and that package has a method called onChange or routeChangeStart. With those methods or after creating that method you can implement a function like below.
Router.events.on("routeChangeStart", () => {
jump(1);
});

React - Warning: Each child in a list should have a unique "key" prop

In this simple React App, I don't understand why I get the following warning message:
Warning: Each child in a list should have a unique "key" prop.
To me it seems that I put the key at the right place, in form of key={item.login.uuid}
How can I get rid of the warning message?
Where would be the right place to put the key?
App.js
import UserList from './List'
const App = props => {
const [id, newID] = useState(null)
return (
<>
<UserList id={id} setID={newID} />
</>
)
}
export default App
List.js
const UserList = ({ id, setID }) => {
const [resources, setResources] = useState([])
const fetchResource = async () => {
const response = await axios.get(
'https://api.randomuser.me'
)
setResources(response.data.results)
}
useEffect(() => {
fetchResource()
}, [])
const renderItem = (item, newID) => {
return (
<>
{newID ? (
// User view
<div key={item.login.uuid}>
<div>
<h2>
{item.name.first} {item.name.last}
</h2>
<p>
{item.phone}
<br />
{item.email}
</p>
<button onClick={() => setID(null)}>
Back to the list
</button>
</div>
</div>
) : (
// List view
<li key={item.login.uuid}>
<div>
<h2>
{item.name.first} {item.name.last}
</h2>
<button onClick={() => setID(item.login.uuid)}>
Details
</button>
</div>
</li>
)}
</>
)
}
const user = resources.find(user => user.login.uuid === id)
if (user) {
// User view
return <div>{renderItem(user, true)}</div>
} else {
// List view
return (
<ul>
{resources.map(user => renderItem(user, false))}
</ul>
)
}
}
export default UserList
The key needs to be on the root-level element within the loop. In your case, that's the fragment (<>).
To be able to do that, you'll need to write it out fully:
const renderItem = (item, newID) => {
return (
<Fragment key={item.login.uuid}>
{newID ? (
...
)}
</Fragment>
);
}
(You can add Fragment to your other imports from react).
Note that the fragment isn't actually needed in your example, you could drop it and keep the keys where they are since then the <div> and <li> would be the root element:
const renderItem = (item, newId) => {
return newID ? (
<div key={item.login.uuid}>
...
</div>
) : (
<li key={item.login.uuid}>
...
</li>
)
}
What if you create 2 separate components, one for the user view and one for the list item. That way you only need to pass the user prop. Also, use JSX and pass wht key from there.
const UserList = ({ id, setID }) => {
const [resources, setResources] = useState([])
const fetchResource = async () => {
const response = await axios.get(
'https://api.randomuser.me'
)
setResources(response.data.results)
}
useEffect(() => {
fetchResource()
}, [])
const User = ({user}) => (
<div key={user.login.uuid}>
<div>
<h2>
{user.name.first} {user.name.last}
</h2>
<p>
{user.phone}
<br />
{user.email}
</p>
<button onClick={() => setID(null)}>
Back to the list
</button>
</div>
</div>
)
const ListItem = ({user}) => (
<li key={user.login.uuid}>
<div>
<h2>
{user.name.first} {user.name.last}
</h2>
<button onClick={() => setID(user.login.uuid)}>
Details
</button>
</div>
</li>
)
const user = resources.find(user => user.login.uuid === id)
if (user) {
// User view
return <User user={user}</div>
} else {
// List view
return (
<ul>
{resources.map((user, index) => <ListItem key={index} user={user} />)}
</ul>
)
}
}
export default UserList

Resources