React-Bootstrap modal only show and delete last mapped element - reactjs

i'm building eccommerce and in my cart i want to show a modal when user tap on delete icon but my modal always show and delete last element of my cart
how can i resolve this issue
here's my modal component:
const VerticalModal = ({ item, mShow, hide, name }) => {
return (
<Modal
show={mShow}
size="md"
centered
>
<Modal.Header>
<Modal.Title >
<h6>Remove from cart</h6>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<p className="text-center">Are you sure you want to remove {name}</p>
</Modal.Body>
<Modal.Footer className="d-flex justify-content-between">
<Button variant="outline-secondary" size="sm" onClick={hide}>
Cancel
</Button>
<Button variant="outline-danger" size="sm" onClick={item}>
Remove
</Button>
</Modal.Footer>
</Modal>
);
};
here's my cart code :
{cart &&
cart.cartItems.length > 0 &&
cart.cartItems.map((item, index) => (
<Card
key={index}
className=" cart-card-magninn cart-card-shadow"
>
<Row className="p-3">
<Col>{item.img}</Col>
<Col>{item.name}</Col>
<Col md={2} xs={2}>
<button
onClick={() => setModalShow(true)}
>
<FontAwesomeIcon icon={faTrashAlt} />
</button>
<VerticalModal
mShow={modalShow}
hide={() => setModalShow(false)}
item={() => removeFromCartHandler(item.prodid)}
name={item.prodname}
/>
</Col>
</Row>
)}

You're creating four modals and whenever, the modal opens, it has the value of the last item. You should move modal out of the map function and store the selected item in a separate state and use that to delete the info.
Initialize the selected item as empty object.
const [selectedItem, setSelectedItem] = useState({})
Then, update the click method on the button.
<button
onClick={() => {
setModalShow(true)
setSelectedItem(item)
}}>
<FontAwesomeIcon icon={faTrashAlt} />
</button>
After that, move the modal code outside of the map function.
{modalShow ?
<VerticalModal
mShow={modalShow}
hide={() => {
setModalShow(false)
setSelectedItem({})
}}
item={() => {
removeFromCartHandler(selectedItem.prodid)
setSelectedItem({})
}
name={selectedItem.prodname}
/>
: null}
Updated code could be something like this
{cart &&
cart.cartItems.length > 0 &&
cart.cartItems.map((item, index) => (
<Card
key={index}
className=" cart-card-magninn cart-card-shadow"
>
<Row className="p-3">
<Col>{item.img}</Col>
<Col>{item.name}</Col>
<Col md={2} xs={2}>
<button
onClick={() => {
setModalShow(true)
setSelectedItem(item)
}}>
<FontAwesomeIcon icon={faTrashAlt} />
</button>
</Col>
</Row>
)}
{modalShow ?
<VerticalModal
mShow={modalShow}
hide={() => {
setModalShow(false)
setSelectedItem({})
}}
item={() => {
removeFromCartHandler(selectedItem.prodid)
setSelectedItem({})
}
name={item.prodname}
/>
: null}

Related

reactjs pop up opened and closed while re-rendering the parent component

I am trying to simulate the Trello board, with reactjs and signalR (.netCore).
I created the board with list of cards and each card item has card details which is a pop up.
that card details pop up opens when the user clicks on the card title. I am using signalR (Websocket) to make multiusers interact within the same board by listening to an event which re-render the whole board when any user change a card.
The issue happens when :
User A is Opening the pop up modal for task 1 and user B is dragging task 2 from todo card list to the in progress card list for example.
when that action happened the pop up close and open again as the whole trello board was rerendered based on the event that each user is listening to.
How can I fix that opening closing issue with the pop up an keep it open as it's ??
and if the logic is wrong please feel free to inform me!
note: I am using react-beautiful-dnd package for the drag and drop feature.
Trello Board
<DragDropContext
onDragEnd={(result) => {
ondragend(result);
}}
>
<div className="App">
<div>
{
sprintLoading ?
sprints.map((card, index) => (
// our sprints
<TrelloList
sprintType={card.sprintType}
index={index}
listId={card.sprintId}
sprintSchemaId={card.sprintSchemaId}
key={card.sprintId}
title={card.sprintName}
cards={card.tasks}
/>
))
: null
}
</DragDropContext >
);
}
Trello List
useEffect(async () => {
}, [tasks, socketState, trelloRerender]);
return (
<Droppable droppableId={String(listId)} >
{(provided) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
style={styles.container}>
<h4>{title}</h4>
{cards ? cards.map((card, index) =>
(
// our tasks
<TrelloCard
sprintType={sprintType}
listId={listId}
index={index}
cardId={card.taskId}
key={card.taskId}
text={card.taskDescription}
projectId={card.projectId}
userId={card.userId}
sprintId={card.sprintId}
sprintSchemaId={card.sprintSchemaId}
title={card.taskName}
schemaId={card.sprintSchemaId}
groupId={card.groupId}
taskStatus={card.taskStatus}
userName={card.user ? card.user.userName : ''}
taskCreatedDate={card.taskCreatedDate}
taskDueDate={card.taskDueDate}
comments={card.comments}
/>
)) : null}
{provided.placeholder}
</div>
)}
</Droppable>
)
};
Trello card
const { showTaskDetails, setShowTaskDetails } = useContext(ShowTaskDetailsContext);
useEffect(async () => {
await axios.get(`${BACKEND_URL}/tasks/${cardId}`).then(res => {
console.log(res.data.comments);
setCurrentTaskComments(res.data.comments)
console.log(currentTaskComments);
});
}, [rerenderForComments]);
useEffect(async () => {
const sprintId = location.pathname.split('/')[2];
setRerenderforCards(false);
setSprintId(sprintId);
setIsRolledback(false);
await fetchObject(`${BACKEND_URL}/sprintschemas/${sprintSchemaId}`)
.then(res => {
if (res.sprintTaskRollback !== null) {
setIsRolledback(true);
}
})
.catch(err => console.log(err));
}, []);
const handleShowTaskDetails = () => setShowTaskDetails(true);
const handleCloseTaskDetails = () => setShowTaskDetails(false);
return (
<Draggable draggableId={String(cardId)} index={index} key={cardId} >
{provided => (
// as provided.innerdiv need to refer to an action DOM node and card is a material-ui node
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps} >
<Card style={styles.cardContainer} >
{/* testing generic hooks */}
<CardContent>
<Typography component={'div'}
gutterBottom>
<span
// href={`/loboard/${sprintId}`}
style={{ display: "block", fontWeight: "bold" }}
onClick={handleShowTaskDetails}
>
{title}
</span>
<TrelloCardDetails
showTaskDetails={showTaskDetails}
handleCloseTaskDetails={handleCloseTaskDetails}
title={title}
description={text}
comments={currentTaskComments}
assignto={userName}
cardId={cardId}
handleDropDownchanged={handleDropDownchanged}
handleMarkCompleted={handleMarkCompleted}
markCompletedBtnTxt={markCompletedBtnTxt}
markBtnStyle={markBtnStyle}
userId={userId}
setComments={setCurrentTaskComments}
rerenderForComments={rerenderForComments}
setRerenderForcommented={setRerenderForcommented}
/>
{/* onchange == move task to it's new list of cards */}
<Form.Group className="mt-2" controlId="exampleForm.ControlSelect2">
<Form.Row>
<Form.Label column="sm" sm={4}>Move to:</Form.Label>
<Col>
{/* adding default value to reset */}
<Form.Control size="sm" as="select"
onChange={handleDropDownchanged}
defaultValue={'select'}
>
<option disabled value="select">select status</option>
<option value="backlog" name='setBacklog'>backlog</option>
<option value="todo" name='setTodo'>todo</option>
<option value="inprogress" name='setInProgress'>inprogress</option>
<option value="done" name='setInProgress'>done</option>
</Form.Control>
</Col>
</Form.Row>
</Form.Group>
<Form.Group>
<Form.Row>
<Form.Label column="sm" sm={4}>assigned to:</Form.Label>
<Col>
<Form.Control
type="text"
disabled
value={userName} />
</Col>
</Form.Row>
</Form.Group>
<Row>
<Button className={markBtnStyle}
onClick=
{() =>
handleMarkCompleted(cardId)
}
style={{ display: "block" }}
>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" className="bi bi-check" viewBox="0 0 16 16">
<path d="M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425a.267.267 0 0 1 .02-.022z" />
</svg>
{markCompletedBtnTxt}
</Button>
</Row>
{/* <Row>
<Col> */}
<span className="text-sm float-right mt-2">
<small title="created at" className="text-muted d-block ">
<BsCalendar /> {taskCreatedDate.split('T')[0]}
</small>
</span>
</Typography>
</CardContent>
</Card>
</div>
)}
</Draggable>
)
Card details component
export const TrelloCardDetails = ({
showTaskDetails,
description,
comments,
title,
handleCloseTaskDetails
, assignto, cardId,
handleDropDownchanged,
handleMarkCompleted,
markBtnStyle,
markCompletedBtnTxt,
userId,
setComments, rerenderForComments,
setRerenderForcommented
}) => {
useEffect(() => {
console.log("card details")
}, [comments]);
return (
<div>
<Modal
show={showTaskDetails}
onHide={handleCloseTaskDetails}>
<Modal.Header closeButton>
<Modal.Title>{title}</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form.Group className="mt-2" controlId="exampleForm.ControlSelect2">
<Form.Row>
<Form.Label column="sm" sm={4}>Move to:</Form.Label>
<Col>
{/* adding default value to reset */}
<Form.Control size="sm" as="select"
onChange={handleDropDownchanged}
defaultValue={'select'}
>
<option disabled value="select">select status</option>
<option value="backlog" name='setBacklog'>backlog</option>
<option value="todo" name='setTodo'>todo</option>
<option value="inprogress" name='setInProgress'>inprogress</option>
<option value="done" name='setInProgress'>done</option>
</Form.Control>
</Col>
</Form.Row>
</Form.Group>
<Form.Group>
<Form.Row>
<Form.Label column="sm" sm={4}>assigned to:</Form.Label>
<Col>
<Form.Control
type="text"
disabled
value={assignto} />
</Col>
</Form.Row>
</Form.Group>
<Form.Group>
<Form.Row>
<Form.Label column="sm" sm={4}>Description: </Form.Label>
<Col>
<Form.Control style={{ resize: 'none' }} as="textarea" value={description} disabled />
</Col>
</Form.Row>
</Form.Group>
<Row>
<Button
className={markBtnStyle}
onClick=
{() =>
handleMarkCompleted(cardId)
}
style={{ display: "block" }}
>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" className="bi bi-check" viewBox="0 0 16 16">
<path d="M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425a.267.267 0 0 1 .02-.022z" />
</svg>
{markCompletedBtnTxt}
</Button>
</Row>
{/* <div style={{marginTop:"20px", backgroundColor: "#e9ecef", opacity: "1", border: "1px solid #ced4da", borderRadius: "5px" }}> */}
<CommentList rerenderForComments={rerenderForComments} setRerenderForcommented={setRerenderForcommented} assignto={assignto} comments={comments} setComments={setComments} taskId={cardId} userId={userId} />
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleCloseTaskDetails}>
Close
</Button>
<Button variant="primary" onClick={handleCloseTaskDetails}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</div >
);
}

A second React Router Swtich inside a component not working correctly

Hey I have a main route /admin/influencers in my react app. And when I reach this path I want to display a tab button so user can switch to /admin/influencers/active and /admin/influencers/invited for example.
here is my implementation:
return (
<>
<div className="header pb-8 pt-5 pt-md-8">
<Container fluid>
<Card className="tab-container" fluid={true}>
<CardBody className="card-body">
<ButtonGroup className="button-group">
<Button size="lg" outline color="warning" onClick={() => setSelectedTab(1)} active={rSelected === 1}>Active</Button>
<Button size="lg" outline color="warning" onClick={() => setSelectedTab(2)} active={rSelected === 2}>Invited</Button>
<Button size="lg" outline color="warning" onClick={() => setSelectedTab(3)} active={rSelected === 3}>New Verification Request</Button>
</ButtonGroup>
<img onClick={toggle} className="add-influencer" src={Add} alt="add" width="40px" height="40px" />
</CardBody>
</Card>
</Container>
<Switch>
<Route
path="/admin/influencers/active?page=1"
component={ActiveInfluencer}
/>
</Switch>
</div>
<AddInfluencerModal toggle={toggle} isOpen={modal} inviteInfluencers={handleInviteInfluencers} updateInvitedInfluencers={fetchInvitedInfluencers}/>
</>
);
but this isn't displaying anything. Any help would be aprreciated.
Thank you

How to pass parameter value into modal box with react

I am still not familiar with react.js and I am doing a NFT app whereby you click a button and each individual NFT profile will show in a popup modal box which I have already successful integrate the modal box and able to pass the value to a function handleShow(owner) but I have no idea how to send or display this value (owner) into my modal box. Appreciate you guys, can help on my situation. thank you.
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
function handleShow(owner) {
alert(owner);
setShow(true);
}
<div className="min-h-screen bg-gray-100">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8 ">
<div className="text-black-100 text-6xl pt-28 pb-10">Monkey</div>
{mintedNftState.state === "PENDING" && (
<div className="text-xl text-white">LOADING...</div>
)}
{mintedNftState.state === "SUCCESS" && (
<div className="grid grid-cols-3 gap-4">
{mintedNftState.data.map(
({ id, image, name, description, owner }) => {
return (
<div key={id} className="bg-white rounded p-2">
<img src={image} className="mx-auto p-4" alt={name} />
<div className="text-xl">{name}</div>
<div className="font-myfont">{description}</div>
<hr className="my-4" />
<div className="text-left text-sm">Owned By:</div>
<div className="text-left text-xs">{owner}</div>
<div className="mt-12">
<Button variant="primary" onClick={() => handleShow(owner)}>
Launch demo modal
</Button>
</div>
</div>
);
}
)}
</div>
)}
</div>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
close
</Button>
<Button variant="primary" onClick={handleClose}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</div>
I would first add an owner state
const [owner, setOwner] = useState(null);
In handleShow you can set the owner like this
function handleShow(owner) {
setOwner(owner)
setShow(true);
}
You can finally display the owner value between <Modal.Body> tags
<Modal.Body>
<p>{owner}</p>
</Modal.Body>
When closing the modal you can set the owner to null
const handleClose = () => {
setShow(false);
setOwner(null);
}

I want to add a "download button on modal carousel using react-images, the button should be available on modal popup

can i add a button as a parameter to the carousel,i tried all possible ways to add a button to this
<div>
<h2>Using with a Lightbox component</h2>
<Gallery photos={photos} onClick={openLightbox} />
<ModalGateway>
{viewerIsOpen ? (
<Modal onClose={closeLightbox}>
<Carousel
currentIndex={currentImage}
views={photos.map(x => ({
...x,
srcset: x.srcSet,
caption: x.title
}))}
/>
</Modal>
) : null}
</ModalGateway>
<div>
<Down />
</div>
</div>
You can create your own component:
const CustomFooter = ({ isModal, currentView }) => isModal && (
<div className="react-images__footer">
<button
className="btn some-stylin"
type="button"
onClick={() => { downloadImage(currentView.src); }}
>
Download
</button>
</div>
);
<ModalGateway>
{modalIsOpen ? (
<Modal onClose={this.toggleGallery}>
<Carousel
views={this.imgs}
currentIndex={currentIndex}
frameProps={{ autoSize: 'height' }}
components={{ Footer: CustomFooter }}
/>
</Modal>
) : null}
</ModalGateway>

How do I pass the parameter in every call to a react.js class method to a modal contained inside it?

I have two classes. In the render() method of Timeslots, when I pass the parameter to this.colhour and use it in an instance of TsModal, modalid is always assigned as '11:00-11:30'. How do I assign modalid as the unique parameter that is passed in the function call?
class Timeslots extends Component {
popoverHoverFocus() {
return (
<Popover id="popover-trigger-hover-focus" title="Table status">
<strong>P1 -> </strong> <br />
<strong>P2 -> </strong> <br />
<strong>S1 -> </strong> <br />
<strong>S2 -> </strong> <br />
<strong>S3 -> </strong> <br />
</Popover>
);
}
colhour(time) {
return (
<Col className='halfhour' xs={4} md={1}>
<TsModal modalid = {time} show={this.state.show} onhide={this.handleClose} onclick={this.handleClose} />
<OverlayTrigger overlay={this.popoverHoverFocus()}>
<Button bsStyle="primary" bsSize="small" onClick={this.handleShow}>
{time}
</Button>
</OverlayTrigger>
</Col>
);
}
render() {
return (
<Grid>
<br></br>
<Row className="timeslot">
{this.colhour('10:00-10:30')}
{this.colhour('10:30-11:00')}
{this.colhour('11:00-11:30')}
</Row>
</Grid>
);
}
}
class TsModal extends React.Component {
render() {
return (
<Modal show={this.props.show} onHide={this.props.onhide}>
<Modal.Header closeButton>
<Modal.Title>Book Tables</Modal.Title>
</Modal.Header>
<Modal.Body>
<hr />
<Button bsStyle="primary" bsSize="small" href={'http://localhost:4000/?id=' + this.props.modalid}>Pool table 1</Button>
</Modal.Body>
<Modal.Footer>
<Button onClick={this.props.onclick}>Close</Button>
</Modal.Footer>
</Modal>
);
}
}
Well, I found a way to pass the value of the button that is clicked to the TsModal instance.
I made a handler function handleButPush and passed keeptimeto it. Then I stored that value in a state buttonPush and passed the state value to the TsModal instance. By this, modalid is assigned the different keeptime value everytime.
this.state = {
show: false,
buttonPush: 'invalid',
list : [],
popoverlist : [{status: "Available"},{status: "Available"},{status:"Available"},{status: "Available"},{status:"Available"}]
};
handleButPush(val) {
this.setState({ buttonpush: val });
}
colhour(keeptime,butdisable) {
return(
<Col className='halfhour' xs={4} md={1}>
<TsModal modalid = {this.state.buttonpush} show={this.state.show} onhide={this.handleClose} onclick={this.handleClose} />
<OverlayTrigger overlay = {() => {this.popoverHoverFocus({keeptime},{butdisable})} } >
<Button bsStyle="primary" bsSize="small" onClick={() => { this.handleShow(); this.handleButPush({keeptime}); }}>
{keeptime}
</Button>
</OverlayTrigger>
</Col>
);
}

Resources