useState being set to false but ternary operator not working - javascript

I have a simple state let [isOpen, setIsOpen] = useState(false);
It doesn't when it gets back set to false it the ternary operator doesn't seem to be doing anything.
export default function ShowContact(props) {
let [isOpen, setIsOpen] = useState(false);
...
function closeButtons() {
setIsOpen(false);
console.log(isOpen);
}
I have the following
{!isOpen ? <span>TRUE</span> : <span>FALSE</span>}
{!isOpen ? (
<div>
<div className="mt-6 flex flex-col">
<button className="mb-1 rounded bg-blue-500 px-4 py-3 capitalize text-white duration-100 ease-in-out hover:bg-blue-700">
<span className="text-center">edit</span>
</button>
<button
className="rounded bg-red-500 px-4 py-3 capitalize text-white duration-100 ease-in-out hover:bg-red-700"
onClick={closeButtons}
>
<span className="text-center tracking-wide">delete</span>
</button>
</div>
</div>
) : (
<div>
<div className="mt-6 flex flex-col">
<button className="mb-1 rounded bg-green-500 px-4 py-3 capitalize text-white duration-100 ease-in-out hover:bg-green-700">
<span className="text-center">edit</span>
</button>
<button
className="rounded bg-red-500 px-4 py-3 capitalize text-white duration-100 ease-in-out hover:bg-red-700"
onClick={deleteContact}
>
<span className="text-center tracking-wide">yes delete</span>
</button>
</div>
</div>
)}
the {isOpen ? <span>TRUE</span> : <span>FALSE</span>} is simple to test that isOpen is being set to false. Which is does as I have checked the console.
Still though the ternary isn't changing. This is very annoying as it was working earlier and something has changed I am not sure if this is an effect from other components, but I can not see why?
But I know the buttons are working as the deleteContact function is working and the isOpen is getting set to false
I am complete miffed about this, any suggestions would be welcome.
import { useEffect, useState } from 'react';
export default function ShowContact(props) {
let [isOpen, setIsOpen] = useState(false);
let [contact, setContact] = useState({});
// delete contact from api then reloads the page
function deleteContact() {
fetch(`http://localhost:8000/delete-contact/${props.contactId}`, {
method: 'DELETE',
}).catch((err) => console.log(err));
setIsOpen(false);
window.location.reload(true);
}
// get contact from api by contact id
useEffect(() => {
async function fetchContact() {
await fetch(`http://localhost:8000/get-contact/${props.contactId}`)
.then((response) => response.json())
.then((data) => {
setContact(data);
})
.catch((err) => console.log(err));
}
if (props.open) {
fetchContact();
}
}, []);
function closeButtons() {
setIsOpen(false);
console.log(isOpen);
}
function openButtons() {
setIsOpen(true);
console.log(isOpen);
}
return (
<div className="bg-gray-100 p-4">
<div>
{/* <div className="mx-auto my-4 block w-fit rounded-full bg-gray-300 p-6 ">
...
</div> */}
<div className="flex flex-col text-center">
<span className="font-bold">
{contact.first_name} {contact.last_name}
</span>
<span className="text-sm text-gray-400">{contact.company}</span>
</div>
{contact.telephone !== '' || contact.telephone === 'NULL' ? (
<div className="my-4 flex flex-col rounded-md bg-white p-4 text-left">
<span className="text-sm font-medium">telephone</span>
<a
href={`tel:${contact.telephone}`}
className="text-sm text-blue-500"
>
{contact.telephone}
</a>
</div>
) : null}
{contact.email !== '' || contact.email === 'NULL' ? (
<div className="my-4 flex flex-col rounded-md bg-white p-4 text-left">
<span className="text-sm font-medium">email</span>
<a
href={`mailto:${contact.email}`}
className="text-sm text-blue-500"
>
{contact.email}
</a>
</div>
) : null}
{contact.address !== '' || contact.address === 'NULL' ? (
<div className="my-4 flex flex-col rounded-md bg-white p-4 text-left">
<span className="text-sm font-medium">address</span>
<span className="text-sm text-blue-500">{contact.address}</span>
</div>
) : null}
{contact.notes !== '' || contact.notes === 'NULL' ? (
<div className="my-4 flex flex-col rounded-md bg-white p-4 text-left">
<span className="text-sm font-medium">notes</span>
<span className="text-sm">{contact.notes}</span>
</div>
) : null}
</div>
{!isOpen ? <span>TRUE</span> : <span>FALSE</span>}
{!isOpen ? (
<div>
<div className="mt-6 flex flex-col">
<button className="mb-1 rounded bg-blue-500 px-4 py-3 capitalize text-white duration-100 ease-in-out hover:bg-blue-700">
<span className="text-center">edit</span>
</button>
<button
className="rounded bg-red-500 px-4 py-3 capitalize text-white duration-100 ease-in-out hover:bg-red-700"
onClick={closeButtons}
>
<span className="text-center tracking-wide">delete</span>
</button>
</div>
</div>
) : (
<div>
<div className="mt-6 flex flex-col">
<button className="mb-1 rounded bg-green-500 px-4 py-3 capitalize text-white duration-100 ease-in-out hover:bg-green-700">
<span className="text-center">edit</span>
</button>
<button
className="rounded bg-red-500 px-4 py-3 capitalize text-white duration-100 ease-in-out hover:bg-red-700"
onClick={deleteContact}
>
<span className="text-center tracking-wide">yes delete</span>
</button>
</div>
</div>
)}
</div>
);
}
Update with the whole component.
I am checking for isOpen to be false as I want to set some delete buttons, but then confirm the delete once the first set of buttons set isOpen to true

Related

Make Submenu on sidebar component Nextjs

So it to loop and subMenu on sidebar component, but instead of the subMenu showUp under the parents menu, it showUp on the Right side of the parents menu as pic below:
here is my code on how i try to loop the subMenu and The parents item to the react component:
return (
<div className=" my-4 border-gray-100 pb-4">
{items.map(({ icon: Icon, iconArrow: IconArrow, ...item }, index) => {
if (item.subMenu) {
return (
<div>
<Link href={item.link}>
<a
onClick={(e) => onMouseClick(e, item.link)}
className="flex mb-2 justify-start items-center gap-4 pl-5 hover:bg-gray-900 p-2 rounded-md group cursor-pointer hover:shadow-lg m-auto"
>
<Icon className="text-2xl text-white group-hover:text-red" />
<h3 className="text-base text-white group-hover:text-red font-semibold ">
{item.label}
</h3>
{item.subMenu && dropdown ? (
<>
<IconArrow className="pl-0 text-2xl text-white group-hover:text-red" />
</>
) : (
<></>
)}{" "}
{item.subMenu && dropdown ? (
<div>
{item.subMenu.map((subitem, index) => {
return <>makan</>;
})}
</div>
) : (
<></>
)}
</a>
</Link>
</div>
);
} else {
return (
// eslint-disable-next-line react/jsx-key
<div>
<Link href={item.link}>
<a
onClick={(e) => onMouseClick(e, item.link)}
className="flex mb-2 justify-start items-center gap-4 pl-5 hover:bg-gray-900 p-2 rounded-md group cursor-pointer hover:shadow-lg m-auto"
>
<Icon className="text-2xl text-white group-hover:text-red" />
<h3 className="text-base text-white group-hover:text-red font-semibold ">
{item.label}
</h3>
</a>
</Link>
</div>
);
}
})}
</div>
);
};
Can Some one tell me where did i do wrong here, here is where i call the sidebar component into the sidebar:
return (
<div className="h-full px-4 pt-8 bg-yellow flex flex-col peer-focus:left-0 peer:transition ease-out delay-150 duration-200">
<div className="flex flex-col justify-start item-center mb-4">
<Image src={Logo_Nabati} width={123} height={75} alt="logo Nabati" />
</div>
<Sidebarcomponent items={menuItems} />;
</div>
);
try this:
return (
<div className=" my-4 border-gray-100 pb-4 relative">
{items.map(({ icon: Icon, iconArrow: IconArrow, ...item }, index) => {
if (item.subMenu) {
return (
<div className="absolute top-full left-0">...</div>
);
} else {...})}
</div>
);
};
I assume you want to display the submenu under the "Master Data"? Put the component under it. Then in the anchor tag you have a flex. Add flex-col to change the direction of flex, top-bottom.

Reactjs => Dynamic active menu change color

I'm having a problem here when I want to make dynamic color changes when the user wants to click on the menu in the sidebar.
So, when the user wants to move the page from /building to /street, then the user will click the "street" menu and hopefully the street menu will change color like the building menu which changes color to red when the menu is active.
however, when I made it not as I expected and the result is like the image below.
Maybe the masters can help me. Thank you very much
Sidebar.jsx
import React from "react";
import { useState } from "react";
import { BiBuildingHouse } from "react-icons/bi";
import { FaRoad } from "react-icons/fa";
import { Link, NavLink } from "react-router-dom";
const Sidebar = () => {
const [activeMenu, setActiveMenu] = useState(false);
return (
<div className='w-[16rem] h-[72rem] bg-[#FFFFFF] px-5 py-3 md:px-8 md:py-5 drop-shadow-xl"'>
<h1 className="text-[#92929D] font-semibold ml-3">DASHBOARD</h1>
<NavLink
to="/try/building"
className={
activeMenu === "/try/building"
? "mr-6 mt-4 w-[12rem] h-[4rem] bg-red-500 text-white py-3 md:px-8 md:py-5 rounded-2xl drop-shadow-xl cursor-pointer"
: "mr-6 mt-4 text-black py-3 md:px-8 md:py-5 rounded-2xl drop-shadow-xl cursor-pointer"
}
onClick={() => {
setActiveMenu("/try/building");
}}
active={activeMenu}
>
<div className="mr-6 mt-4 w-[12rem] h-[4rem] bg-red-500 py-3 md:px-8 md:py-5 rounded-2xl drop-shadow-xl cursor-pointer">
<div className="inline-flex gap-4 items-center">
<BiBuildingHouse size={25} className="text-white" />
<h1 className="text-white">Building</h1>
</div>
</div>
</NavLink>
<Link
to="/try/street"
className={
activeMenu === "/try/street"
? "mr-6 mt-4 w-[12rem] h-[4rem] bg-red-500 text-white py-3 md:px-8 md:py-5 rounded-2xl drop-shadow-xl cursor-pointer"
: "mr-6 mt-4 text-black py-3 md:px-8 md:py-5 rounded-2xl drop-shadow-xl cursor-pointer"
}
onClick={() => {
setActiveMenu("/try/street");
}}
active={activeMenu}
>
<div className="mr-6 w-[12rem] h-[4rem] py-3 md:px-8 md:py-5 rounded-2xl drop-shadow-xl cursor-pointer">
<div className="inline-flex gap-4 items-center">
<FaRoad size={25} className="text-[#92929D]" />
<h1 className="text-black">Street</h1>
</div>
</div>
</Link>
</div>
);
};
export default Sidebar;
You can't use useState() like that, you either have one state for text or for boolean.
You need to use it like this:
const [activeMenu, setActiveMenu] = useState(false);
const [activeLink, setActiveLink] = useState("");
Secondly, you can't use activeMenu for both links, you don't need this active={activeMenu} at all.
Please use simple CSS, whatever library you use must have a classname:active,
or simply add:
.my_className {
background: white;
color: black;
}
.my_className:active, .my_className:selected, .my_className:hover {
background: red;
}
then add the my_className to every menu item.
more easy way you can use ant.desgin library, very straight forward and easy to implement.
The main issue with the current code is that all links are attempting to use the same activeMenu state. Neither the NavLink nor Link components consume an active prop though.
The NavLink component already applies an active class by default, and can otherwise already handle the logic you are trying to do manually. The className prop can also take a callback function that is passed an isActive prop when it matches the current URL pathname.
Example:
const Sidebar = () => {
return (
<div className='w-[16rem] h-[72rem] bg-[#FFFFFF] px-5 py-3 md:px-8 md:py-5 drop-shadow-xl"'>
<h1 className="text-[#92929D] font-semibold ml-3">DASHBOARD</h1>
<NavLink
to="/try/building"
className={({ isActive }) =>
isActive
? "mr-6 mt-4 w-[12rem] h-[4rem] bg-red-500 text-white py-3 md:px-8 md:py-5 rounded-2xl drop-shadow-xl cursor-pointer"
: "mr-6 mt-4 text-black py-3 md:px-8 md:py-5 rounded-2xl drop-shadow-xl cursor-pointer"
}
>
<div className="mr-6 mt-4 w-[12rem] h-[4rem] bg-red-500 py-3 md:px-8 md:py-5 rounded-2xl drop-shadow-xl cursor-pointer">
<div className="inline-flex gap-4 items-center">
<BiBuildingHouse size={25} className="text-white" />
<h1 className="text-white">Building</h1>
</div>
</div>
</NavLink>
<NavLink
to="/try/street"
className={({ isActive }) =>
isActive
? "mr-6 mt-4 w-[12rem] h-[4rem] bg-red-500 text-white py-3 md:px-8 md:py-5 rounded-2xl drop-shadow-xl cursor-pointer"
: "mr-6 mt-4 text-black py-3 md:px-8 md:py-5 rounded-2xl drop-shadow-xl cursor-pointer"
}
>
<div className="mr-6 w-[12rem] h-[4rem] py-3 md:px-8 md:py-5 rounded-2xl drop-shadow-xl cursor-pointer">
<div className="inline-flex gap-4 items-center">
<FaRoad size={25} className="text-[#92929D]" />
<h1 className="text-black">Street</h1>
</div>
</div>
</Link>
</div>
);
};

Why react HeroIcons does not take color?

I am trying to use a hero icon from heroicons, in a react project.
import React, { useState } from 'react';
import { MenuIcon, XIcon } from '#heroicons/react/solid';
export const Sidebar = () => {
const [showSidebar, setShowSidebar] = useState<boolean>(false);
return (
<div
className="flex justify-between items-center
p-2
m-auto"
>
{showSidebar ? (
<div>
<XIcon
onClick={() => setShowSidebar(!showSidebar)}
className="h-5 w-5 text-white cursor-pointer"
/>
</div>
) : (
<div>
<MenuIcon onClick={() => setShowSidebar(!showSidebar)} className="h-5 w-5 text-white" />
</div>
)}
<div
className={`top-0 left-0 w-[45vw] bg-menubar p-10 pl-20 text-white fixed h-full z-40 ${
showSidebar ? 'translate-x-0 ' : 'translate-y-full'
}`}
>
<h2 className="mt-5 text-2xl font-semibold text-white">I am a sidebar</h2>
</div>
</div>
);
};
I am conditionally displaying a sidebar.
XIcon is hwoing in my dom.
But it does not take any color.
how about trying with fill-white instead of text-white e.g:
<XIcon
onClick={() => setShowSidebar(!showSidebar)}
className="h-5 w-5 fill-white cursor-pointer"
/>

Update quantity of items in basket page from localStorage in react

I am using react and globalContext to add items to a cart page and this adds the product to the array stored in localStorage and looks like this.
0: {id: "9", title: "Apple Watch SE 40mm (GPS) - Space Grey Aluminium Case with Midnight Sport Band",…}
id: "9"
price: 249.99
quantity: 1
src: "/static/media/se.0ca02982636517aed223.png"
title: "Apple Watch SE 40mm (GPS) - Space Grey Aluminium Case with Midnight Sport Band"
I have a quantity selector on the page for every item added to the basket which displays the quantity how do i make it so when that quantity is changed the price alters too?
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faChevronLeft, faClose, faPlus, faMinus } from '#fortawesome/free-solid-svg-icons'
import React, {useContext, useEffect, useState} from 'react'
import { NavLink } from 'react-router-dom'
import { GlobalContext } from '../context/GlobalState'
export const Basket = () => {
const {basket, removeFromCart} = useContext(GlobalContext)
let cartArray = localStorage.getItem("basket");
cartArray = JSON.parse(cartArray);
const total = cartArray.reduce((prev, cur) => (cur.price * cur.quantity) + prev, 0);
console.log(total)
const [quantity, setQuantity] = useState(0);
const handleReduceQuantity = () => {
if (quantity === 0) return;
setQuantity((prev) => prev - 1);
};
const handleIncreaseQuantity = () => {
setQuantity((prev) => prev + 1);
};
return (
<div className="h-screen bg-zinc-100 p-4">
<div className="py-5">
<div className="max-w-md mx-auto bg-white shadow-lg rounded-lg md:max-w-7xl">
<div className="md:flex">
<div className="w-full p-4">
<div className="md:grid md:grid-cols-3 gap-2 ">
<div className="col-span-2 p2 md:p-5">
<h1 className="text-xl font-bold ">Shopping Basket</h1>
<div className="flex justify-between flex-col items-center mt-6 pt-6 gap-12">
{basket.length > 0 ? (
<>
{basket.map(item => (
<>
<div className='flex flex-col w-full justify-between md:gap-44 items-start'>
<div className="flex items-center">
<img src={item.src} className="rounded w-20 " />
<div className="flex flex-col ml-3 gap-1 ">
<span className="md:text-lg text-sm font-bold w-full md:t-width ">{item.title}</span>
<span className="text-xl font-bold">£ {item.price}</span>
</div>
<div className="flex items-center justify-between py-2 bg-gray-100 rounded-md md:w-36">
<FontAwesomeIcon
icon={ faMinus }
className="ml-4 transform scale-110 cursor-pointer text-primary"
onClick={handleReduceQuantity}
/>
<span className="text-lg font-bold text-secondary-dark">
{item.quantity}
</span>
<FontAwesomeIcon
icon={ faPlus }
className="mr-4 transform scale-110 cursor-pointer text-black"
onClick={handleIncreaseQuantity}
/>
</div>
<FontAwesomeIcon icon={ faClose } onClick={() =>
removeFromCart(item.id)}/>
</div>
</div>
</>
))}
</>
) : (
<div>No Items</div>
)}
</div>
<div className="flex justify-between items-center mt-6 pt-6 border-t">
<NavLink to="/">
<div className="flex items-center"> <i className="fa fa-arrow-left text-sm pr-2"></i>
<span className="text-md font-medium text-amz hover:text-orange-500 cursor-pointer ">
<FontAwesomeIcon icon={ faChevronLeft }></FontAwesomeIcon> Continue Shopping</span>
</div>
</NavLink>
<div className="flex justify-center items-end">
<span className="text-sm font-medium text-gray-400 mr-1">Subtotal:</span>
<span className="text-lg font-bold text-gray-800 ">£ {total}</span>
</div>
</div>
</div>
<div className=" p-5 bg-gray-800 rounded overflow-visible">
<span className="text-xl font-medium text-gray-100 block pb-3">Total</span>
<div className="flex justify-center flex-col pt-3">
<label className="text-xs text-gray-400 ">Name on Card</label>
<input type="text" className="focus:outline-none w-full h-6 bg-gray-800 text-white placeholder-gray-300 text-sm border-b border-gray-600 py-4" placeholder="Giga Tamarashvili"/>
</div>
<div className="flex justify-center flex-col pt-3">
<label className="text-xs text-gray-400 ">Card Number</label>
<input type="text" className="focus:outline-none w-full h-6 bg-gray-800 text-white placeholder-gray-300 text-sm border-b border-gray-600 py-4" placeholder="**** **** **** ****"/>
</div>
<div className="grid grid-cols-3 gap-2 pt-2 mb-3">
<div className="col-span-2 ">
<label className="text-xs text-gray-400">Expiration Date</label>
<div className="grid grid-cols-2 gap-2">
<input type="text" className="focus:outline-none w-full h-6 bg-gray-800 text-white placeholder-gray-300 text-sm border-b border-gray-600 py-4" placeholder="mm"/>
<input type="text" className="focus:outline-none w-full h-6 bg-gray-800 text-white placeholder-gray-300 text-sm border-b border-gray-600 py-4" placeholder="yyyy"/>
</div>
</div>
<div className="">
<label className="text-xs text-gray-400">CVV</label> <input type="text" className="focus:outline-none w-full h-6 bg-gray-800 text-white placeholder-gray-300 text-sm border-b border-gray-600 py-4" placeholder="XXX"/>
</div>
</div>
<button className="h-12 w-full bg-blue-500 rounded focus:outline-none text-white hover:bg-blue-600">Check Out</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
At the moment the quantity selector is just a counter and doesn't change the quantity of the item in localStorage and therefore doesn't change the total price.
const items = [
{
id: "9",
price: 200,
quantity: 1,
src: "/static/media/se.0ca02982636517aed223.png",
title: "Apple Watch SE 40mm (GPS) - Space Grey Aluminium Case with Midnight Sport Band",
},
{
id: "3",
price: 300,
quantity: 1,
src: "/static/media/se.0ca02982636517aed223.png",
title: "Apple Watch SE 40mm (GPS) - Space Grey Aluminium Case with Midnight Sport Band",
}
];
const calculateTotal = (items) => {
const total = items.reduce((acc, curr) => (curr.price * curr.quantity) + acc, 0);
console.log(total);
}
const handleQuantityUpdate = (itemId, operation) => {
const newItems = items.map((i) => {
if(i.id === itemId){
return {...i, quantity: operation === 'increase' ? i.quantity + 1 : i.quantity - 1};
}
return {...i};
});
//need to store into localstorage at this point
console.log(newItems);
calculateTotal(newItems);
}
handleQuantityUpdate("9", 'increase');
handleQuantityUpdate("3", "decrease");

Inverse map and use if inside a map method

In the categories.map((category) => () I need to inverse the elements of the categories.map and check for category.isFeatured befor making a link but it doesn't let me make an if statement.
const Header = () => {
const [categories, setCategories] = useState([])
useEffect(() => {
getCategories().then((newCategories) => setCategories(newCategories))
}, [])
return (
<div className="container mx-auto mb-8 px-10">
<div className="inline-block w-full border-b border-blue-400 py-8">
<div className="block md:float-left">
<span className="cursor-pointer text-4xl font-bold text-white">
<Link href={'/'}>CRBStuffReviews</Link>
</span>
</div>
<div className="hidden md:float-left md:contents">
{categories.map((category) => (
<Link key={category.slug} href={`/category/${category.slug}`}>
<span className="mt-2 ml-4 cursor-pointer align-middle font-semibold text-white md:float-right">
{category.name}
{console.log(category.name)}
</span>
</Link>
))}
</div>
</div>
</div>
)
}
Bravo is right on the Array.reverse in the comments.
You also need to add {} in the .map, check category.isFeatured, and remove any nulls (or you'll get blank rows).
For example the following will reverse the order, return the link if category.isFeatured, else return null. Finally it will remove all nulls with filter(Boolean) - a nifty trick:
import React, { useState, useEffect } from "react";
const Header = () => {
const [categories, setCategories] = useState([]);
useEffect(() => {
getCategories().then((newCategories) => setCategories(newCategories));
}, []);
return (
<div className="container mx-auto mb-8 px-10">
<div className="inline-block w-full border-b border-blue-400 py-8">
<div className="block md:float-left">
<span className="cursor-pointer text-4xl font-bold text-white">
<Link href={"/"}>CRBStuffReviews</Link>
</span>
</div>
<div className="hidden md:float-left md:contents">
{categories
.reverse()
.map((category) => {
return category.isFeatured ? (
<Link key={category.slug} href={`/category/${category.slug}`}>
<span className="mt-2 ml-4 cursor-pointer align-middle font-semibold text-white md:float-right">
{category.name}
{console.log(category.name)}
</span>
</Link>
) : null;
})
.filter(Boolean)}
</div>
</div>
</div>
);
};
In the map callback function, you need to use curly bracket
{}
Inside the curly bracket you can use the IF statement
So, Your code will looks like this
const Header = () => {
const [categories, setCategories] = useState([])
useEffect(() => {
getCategories().then((newCategories) => setCategories(newCategories))
}, [])
return (
<div className="container mx-auto mb-8 px-10">
<div className="inline-block w-full border-b border-blue-400 py-8">
<div className="block md:float-left">
<span className="cursor-pointer text-4xl font-bold text-white">
<Link href={'/'}>CRBStuffReviews</Link>
</span>
</div>
<div className="hidden md:float-left md:contents">
{categories.map((category) => {
if(category.isFeatured){
return(
<Link key={category.slug} href={`/category/${category.slug}`}>
<span className="mt-2 ml-4 cursor-pointer align-middle font-semibold text-white md:float-right">
{category.name}
{console.log(category.name)}
</span>
</Link>
)}})}
</div>
</div>
</div>
)
}
Try it:
<div className="hidden md:float-left md:contents">
{mrGlobalRequest?.map((category) => {
if (category.isFeatured)
return (
<div key={category.slug} href={`/category/${category.slug}`}>
<span className="mt-2 ml-4 cursor-pointer align-middle font-semibold text-white md:float-right">
{category.name}
{console.log(category.name)}
</span>
</div>
);
})}
</div>

Categories

Resources