Add/delete draggable item in beautiful drag and drop (dnd) - reactjs

First, I'm new to React.
So, I've been making some drag and drop feature while there are also add and delete item feature on it. There are only 2 jsx file that I use, first is DragDropContext and the second is Column (Column with draggable item on it).
Here some code for your better understanding
<DragDropContext onDragEnd={onDragEnd}>
<div className="w-full md:w-[80vw] h-screen p-5 lg:p-20 overflow-y-scroll text-gray-800 bg-slate-100">
<h3 className='text-2xl font-bold'>Favorite Page</h3>
<div className='flex justify-between items-center mt-8'>
<div>
<input type="text" placeholder='type something...' className='p-2 rounded' />
<input type="button" value="Add" className='p-2 rounded bg-indigo-300 ml-4' />
</div>
<div>
<button onClick={onOff}
className={`px-4 py-2 rounded-full text-white ${isToggled ? 'bg-indigo-500': 'bg-slate-400'}`}>{`${isToggled ? 'Edit Page' : 'Save Page'}`}</button>
</div>
</div>
{isToggled ?
<div className='flex mt-5 w-full gap-5 h-fit'>
{state.columnOrder.map((columnId) => {
const column = state.columns[columnId];
const tasks = column.taskIds.map(taskId => state.tasks[taskId]);
// console.log(tasks);
return <Column key={column.id} column={column} tasks={tasks} dataPost={dataPost} enable={true} color={'bg-slate-100'} toggle={isToggled}/>
})}
</div>
:
<div className='flex mt-5 w-full gap-5 h-fit'>
{state.columnOrder.map((columnId) => {
const column = state.columns[columnId];
const tasks = column.taskIds.map(taskId => state.tasks[taskId]);
// console.log(tasks);
return <Column key={column.id} column={column} tasks={tasks} dataPost={dataPost} enable={false} color={'bg-white'} deleteItem={deleteItem}/>
})}
</div>
}
</div>
</DragDropContext>
and this one is for Column
const Column = ( {column, tasks, enable, color, deleteItem, toggle}) => {
return(
<div className={`${column.colorBody} w-full rounded-xl overflow-hidden`}>
<p className={` ${column.colorHead} w-full p-4 text-center text-lg font-light text-white`}>{column.title}</p>
<Droppable droppableId={column.id}>
{(droppableProvided, droppableSnapshot) => (
<div key={column.id} className='w-full h-fit p-5 flex flex-col gap-4' ref={droppableProvided.innerRef} {...droppableProvided.droppableProps}>
{tasks.map((task, index) =>(
<Draggable key={task.id} draggableId={`${task.id}`} index={index} isDragDisabled={enable}>
{(draggableProvided, draggableSnapshot) => (
<div className={`${color} w-full flex justify-between rounded h-fit overflow-hidden ${draggableSnapshot.isDragging? 'border-4 border-indigo-400' : ''}`} id={task.id}
ref={draggableProvided.innerRef}
{...draggableProvided.draggableProps}
{...draggableProvided.dragHandleProps}
>
<div className="flex">
<img className="w-[25%] object-cover" src={`http://127.0.0.1:8000/storage/${task.image}`} alt="" />
<p className='p-4 w-[75%]'>{task.title}</p>
</div>
<button onClick={() => {deleteItem(task.id, column.id)}} className={`button-x ${toggle? 'hidden' : 'block'} h-full bg-red-400 text-white flex items-center justify-center pt-2 pr-2 pb-4 pl-4 rounded-bl-full`}><i className="bi bi-x-lg"></i></button>
</div>
)}
</Draggable>
))}
{droppableProvided.placeholder}
</div>
)}
</Droppable>
</div>
Actually, I'm successful at deleting the item. Still, it throws errors in console and when I drop item on the place that I delete the item before, it'll go to the top left corner and back to the deleted position (place that I drop earlier, like a boomerang). The way I deleted the item is only with deleting the div (draggable item), and when i tried to update the state, it completely not rendering on browser.
The error that throws by console are
Unable to find drag handle with id "1" as no handle with a matching id was found -> in yellow
and
`A setup problem was encountered.
Invariant failed: Draggable[id: 1]: Unable to find drag handle` -> in red
Probably if PublicDraggable key="xx" component is deleted, the error would be gone, but it can't be done that way, right?
So, maybe I need some enlightenment, which function or where is the thing that needs and store Draggable Id except on the div.

Related

How to fix Navbar design in React ?? Is there any change for Navbar design in Tailwind?

Initially I made a project and there the Navbar was completely ok. But I want to use the same Navbar on similar kind of project. But while type or copy paste the code the design is completely change. Even after a lot of search I can't find the actual problem as well as the solution also.
Both having same CSS file as well. Then where the problem occurs ?? Is there any change happened for Tailwind CSS design ?? Kindly let me know.
Navbar of previous project :
Navbar of present project :
Even though all codes are same. I put all the Navbar code below.
import { HiMenuAlt4 } from 'react-icons/hi';
import { AiOutlineClose } from 'react-icons/ai';
import logo from '../../images/logo.png';
const NavbarItem = ({ title, classProps }) => {
return (
<li className={`mx-4 cursor-pointer ${classProps}`}>
{title}
</li>
)
}
const Navbar = () => {
const [toggleMenu, setToggleMenu] = useState(false); //Mobile View On or Not
return (
<nav className="w-full flex md:justify-center justify-between items-center p-4">
<div className="md:flex-[0.5] flex-initial justify-center items-center">
<img src={logo} alt="logo" className="w-32 cursor-pointer"/>
</div>
<ul className="text-white md:flex hidden list-none flex-row justify-between items-center flex-initial">
{["Buy","Sell","Transfer","Wallets","About Us"].map((item, index) => (
<NavbarItem key={item + index} title={item} />
))}
<li className="bg-[#3d4f79] py-2 px-7 mx-4 rounded-full cursor-pointer hover:bg-[#2546]">
SIGN IN
</li>
</ul>
{/* Mobile View */}
<div className="flex relative">
{toggleMenu
? <AiOutlineClose fontSize={28} className="text-white md:hidden cursor-pointer" onClick={() => setToggleMenu(false)} />
: <HiMenuAlt4 fontSize={28} className="text-white md:hidden cursor-pointer" onClick={() => setToggleMenu(true)} />
}
{toggleMenu && (
<ul
className="z-10 fixed top-0 -right-2 p-3 w-[70vw] h-screen shadow-2x1 md:hidden list-none
flex flex-col justify-start items-end rounded-md blue-glassmorphism text-white animate-slide-in"
>
<li className="text-xl w-full my-2">
<AiOutlineClose onClick={() => setToggleMenu(false)} />
</li>
{["Market","Exchange","Tutorials","Wallets"].map((item, index) => (
<NavbarItem key={item + index} title={item} classProps="my-2 text-lg"/>
))}
</ul>
)}
</div>
</nav>
);
}
export default Navbar;```
by adding classname navbar fixed <nav className="fixed w-full flex md:justify-center justify-between items-center p-4">

How do I use like & unlike functionality on every element while using map to render those elements?

I have social media posts stored in firebase and each post has a like button. I am using map() function to render those posts but I have declared a single state for like button using useState().
When I click on like button in any of the posts, the state is getting changed for all the posts and same is happening when I dislike.
How do I change the state for that particular post on which like is cliked??
function Feed(){
const [like, setLike] = useState(false);
const [heart, setHeart] = useState(false);
{posts.map((item) => (
<div
key={item.id}
className=" flex flex-col gap-2 bg-white rounded-xl p-3 border border-gray-300 shadow-
lg mb-2"
>
<div className=" flex gap-2 items-center">
<img
src={userImage}
className=" w-[48px] h-[48px] rounded-full "
alt=""
/>
<span className=" text-black font-semibold text-sm">
{userName}
</span>
</div>
<hr />
{item.body && <p>{item.body}</p>}
{item.imageUrl && <img src={item.imageUrl} alt="" />}
{item.videoUrl && (
<iframe
src={item.videoUrl}
title={item.id}
frameBorder="0"
className=" w-full h-[20rem] "
></iframe>
)}
<hr />
<div className=" flex gap-2">
{like ? (
<ThumbUpIcon
className=" cursor-pointer text-blue-600 hover:bg-gray-100 px-2 py-2
hover:rounded-md"
fontSize="large"
onClick={() => setLike(!like)}
/>
) : (
<ThumbUpOutlinedIcon
className=" cursor-pointer text-gary-500 hover:bg-gray-100 px-2 py-2
hover:rounded-md"
fontSize="large"
onClick={() => setLike(!like)}
/>
)}
{heart ? (
<FavoriteOutlinedIcon
className=" cursor-pointer text-red-500 hover:bg-gray-100 px-2 py-2
hover:rounded-md"
fontSize="large"
onClick={() => setHeart(!heart)}
/>
) : (
<FavoriteBorderOutlinedIcon
className=" cursor-pointer text-gary-500 hover:bg-gray-100 px-2 py-2
hover:rounded-md"
fontSize="large"
onClick={() => setHeart(!heart)}
/>
)}
</div>
</div>
))}
}
I suggest instead of a boolean variable for keeping like for posts, define an array and add the id of each element that liked
const [likes, setLikes] = useState([]);
And
likes.findIndex(x=>x===item.id)<0 ?
onClick={() => {likes.add(item.id);setLikse(...likes)}}
Sandbox: Simple Sample is here

How to delete the parent div when the button inside of it is clicked?

I have a button,
<div
key={index}
className='flex items-center justify-between px-1 bg-accent-tm mr-2 mb-1 text-white-tm text-sm rounded-sm'
>
<span className="pr-2">{tag}</span>
<button>
<XCircleIcon className="h-4" />
</button>
</div>
Which looks like this,
I'm trying to remove the whole <div> element when the <button> element is clicked. How can I do that?
I added an event to the button like this,
<div
key={index}
className='flex items-center justify-between px-1 bg-accent-tm mr-2 mb-1 text-white-tm text-sm rounded-sm'
>
<span className="pr-2">{tag}</span>
<button onClick={handleRemoveClick}>
<XCircleIcon className="h-4" />
</button>
</div>
and passed the following handleRemoveClick function,
function handleRemoveClick(event: MouseEvent<HTMLButtonElement>) {
const target = event.target as SVGPathElement
const removingText = target.parentElement!.parentElement!.parentElement!.children.item(0)!.innerHTML
setTags(prev => (prev?.filter(tag => tag !== removingText)))
}
But this only works when I click the white coloured parts of the button not red coloured parts of it. Then I looked around and found that the event.target changes depending on where I click on the button. Solution I came up with is to add an if else to figure out where I clicked.
So, is there a better way to do this?
Here is a simple solution to hide the button on click
export default function App() {
const [hideButton, setHideButton] = useState(false);
return (
<div className="App">
{hideButton ? null : (
<div
key={index}
className="flex items-center justify-between px-1 bg-accent-tm mr-2 mb-1 text-white-tm text-sm rounded-sm"
onClick={() => setHideButton(true)}
>
<span className="pr-2" onClick={(e) => e.stopPropagation()}>{tag}</span>
<button>
<XCircleIcon className="h-4" />
</button>
</div>
)}
</div>
);
}

How to style a icon inside an input using tailwind and styled-components

const StyledInput = styled.input`w-full focus:ring-indigo-500 focus:border-indigo-500 block p-2 border-gray-300 border-2 rounded-md`;
export const Input = (props: StyledInputProps) => {
return props.iconPosition === 'trailing' ? (
<div>
{props.label && <div tw="text-coolGray-800">{props.label}</div>}
<div tw="w-full relative rounded-md shadow-sm flex">
<StyledInput {...props} />
<div tw="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
{props.icon}
</div>
</div>
</div>
) : (
<div>
{props.label && <div tw="text-coolGray-800">{props.label}</div>}
<div tw="w-full relative rounded-md flex bg-white">
{props.icon && (
<div tw="z-10 h-full leading-snug font-normal absolute text-center rounded text-base items-center justify-center w-8 pl-3 py-3">
{props.icon}
</div>
)}
<StyledInput {...props} />
</div>
</div>
);
};
No Matter how I try to style the leading input Icon, I always get this:
I'm trying to get the icon to go inside the input element, like Put icon inside input element in a form
But Even trying all the normal answers, I can't figure it out, is there something really dumb I'm missing?

how to show a hidden element on hover on tailwind

how would it be possible to display a hidden menu through a hover. im getting confused as to how a hidden element can be connected to a visible element. this example is on the headlessui website. however instead of clicking on it, would it be possible to hover to show the popover?
return (
<div className='fixed w-full max-w-sm px-4 top-16'>
<Popover className='relative'>
{({ open }) => (
<>
<Popover.Button></Popover.Button>
<Transition>
<Popover.Panel className='absolute z-10 w-screen max-w-sm px-4 mt-3 transform -translate-x-1/2 left-1/2 sm:px-0 lg:max-w-3xl'></Popover.Panel>
</Transition>
</>
)}
</Popover>
</div>
);
Try using the onMouse in Events
return (
<div onMouseEnter={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
className='fixed w-full max-w-sm px-4 top-16'>
<Popover className='relative'>
{({ open }) => (
<>
<Popover.Button></Popover.Button>
<Transition>
<Popover.Panel className='absolute z-10 w-screen max-w-sm px-4 mt-3 transform -translate-x-1/2 left-1/2 sm:px-0 lg:max-w-3xl'></Popover.Panel>
</Transition>
</>
)}
</Popover>
</div>
);

Resources