How to add popconfirm to upload in antd react? - reactjs

i need to add popconfirm element to upload element. i've tried to do this:
<Popconfirm
title="Add file to CDS?"
onConfirm={() => this.cleanGroup(group.key)}
okText="Да"
cancelText="Отмена"
disabled={group.items.length === 0}
open={this.state.open}
>
<Upload
style={{ width: '100%' }}
name="fileManager"
action={uploadUrl}
headers={headers}
data={{
group: group.key,
}}
showUploadList={false}
onChange={(info => this.uploadHandler(info))}
}}
>
<Tooltip title="Add file">
<Button icon={<PlusOutlined />} type="primary" />
</Tooltip>
</Upload>
</Popconfirm>
But in such case it ignore popconfirm. then i hsve tired manual download in upload element:
title="Вы хотите добавить файл в анкету ЦДС?"
onConfirm={() => this.cleanGroup(group.key)}
okText="Да"
cancelText="Отмена"
disabled={group.items.length === 0}
open={this.state.open}
>
<Upload
style={{ width: '100%' }}
name="fileManager"
beforeUpload={(file) => {
console.log("fgfd");
this.setState({
fileList: [...this.state.fileList, file],
});
this.setState({
open: true,
})
return false;
}}
>
<Tooltip title="Добавить файл">
<Button icon={<PlusOutlined />} type="primary" />
</Tooltip>
</Upload>
</Popconfirm>
this solution works, but the problem is that popconfirm and upload components are being rendered in array, so i get 5 popconfirms modals insteasd of one. i don't understand how to render popconfirm only for this upload element, not for all elements. any help will be appreciated!

Related

How to swap MUI icon on IconButton when hovering

I have these tabs that have a close button on them, if the content in them has edits then the close icon turns to a circle, similar to visual code.
{tabs.map((tab, index) => {
const child = (
<StyledTab
label={
<span>
{tab.label + ':' + tab.hasEdit}
<IconButton size="small" component="span" onClick={() => closeClickHandler(tab.value)}>
{tab.hasEdit ? (
<CircleIcon style={{ fontSize: "12px" }} />
) : (
<CloseIcon style={{ fontSize: "18px" }} />
)}
</IconButton>
</span>
}
value={tab.value}
key={index}
/>
);
return (
<DraggableTab
label={
<span>
{tab.label}
<IconButton size="small" component="span" onClick={() => {
closeClickHandler(tab.value);
}}>
{tab.hasEdit ? (
<CircleIcon style={{ fontSize: "12px" }} />
) : (
<CloseIcon style={{ fontSize: "18px" }} />
)}
</IconButton>
</span>
}
value={tab.value}
index={index}
key={index}
child={child}
/>
);
})}
What I'm having trouble with is getting the icon to change from a circle to a close icon while hovering over the button.
Could someone give me a hand on a good way to implement this please?!
You could do this by adding a state for the items. Then add a onMouseEnter and onMouseLeave events on the IconButton. When hovering we can add the index to the array and finally remove when we're leaving. To determine if a icon needs to change we can check if the index in in the hoveringItems.
const [hoveringItems, setHoveringItems] = useState([]);
function handleHover(index, isLeaving) {
setHoveringItems((prevItems) => {
if (isLeaving) return prevItems.filter((item) => item !== index);
return [...prevItems, index];
});
}
return (
<IconButton
size="small"
component="span"
onClick={() => {
closeClickHandler(tab.value);
}}
onMouseEnter={() => handleHover(index, false)}
onMouseLeave={() => handleHover(index, true)}
>
{tab.hasEdit || hoveringItems.includes(index) ? (
<CircleIcon style={{ fontSize: "12px" }} />
) : (
<CloseIcon style={{ fontSize: "18px" }} />
)}
</IconButton>
);

How to use useEffect to change icon of a button on cursor hover in react

How to change the button icon on mouse hover with useEffect?
<Button
style={{ backgroundColor: "transparent" }}
type="primary"
icon={<img src={plusCart} />}
onClick={addToBasket}
/>
You can change your code to something like this:
const [icon, setIcon] = useState(plusCart)
<Button
style={{ backgroundColor: "transparent" }}
type="primary"
icon={<img src={icon} />}
onClick={addToBasket}
onMouseEnter={() => setIcon(minusCart /**for example */)}
onMouseLeave={() => setIcon(plusIcon /**for example */)}
/>;

React material UI split button align

I am trying to align to the left the dropdown menu list, whatever values I put in are not yielding this result can somone advise how to do this?
https://material-ui.com/components/button-group/#split-button
Here is what my template looks like:
<Grid container direction="column" alignItems="flex-start">
<Grid item xs={12}>
<ButtonGroup variant="contained" color="primary" ref={anchorRef} aria-label="split button">
<Button onClick={() => handleClick(options[selectedIndex])}>
{options[selectedIndex]}
</Button>
<Button
color="primary"
size="small"
aria-controls={open ? "split-button-menu" : undefined}
aria-expanded={open ? "true" : undefined}
aria-label="select mode type"
aria-haspopup="menu"
onClick={handleToggle}
>
<ArrowDropDownIcon />
</Button>
</ButtonGroup>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin: placement === "bottom" ? "left top" : "left bottom",
}}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList id="split-button-menu">
{options &&
options.map((option, index) => (
<MenuItem
key={option}
disabled={index === selectedIndex}
selected={index === selectedIndex}
onClick={(event) => handleMenuItemClick(event, index)}
>
{option}
</MenuItem>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</Grid>
</Grid>
Try this:
<Grow
{...TransitionProps}
anchorOrigin={{
horizontal: 'left',
vertical: 'bottom',
}}
transformOrigin={{
horizontal: 'left',
vertical: 'top',
}}
>
{insert children here}
</Grow>
UPDATE
This is what you want, i.e, add placement='bottom-start' to your Popper component. Thanks for giving me more context.
<Popper
open={open}
anchorEl={anchorRef.current}
role={undefined}
transition
disablePortal
placement='bottom-start'
>
{...children...}
</Popper>

How to use jquery in Reactjs tag

render() {
return (
LargeData
To represent large amounts of data in the browser, a large
<DataGrid
height={this.state.height}
style={{ fontSize: '12px' }}
columns={this.state.columns}
data={this.state.data}
options={this.state.options}
/>
<Divider />
<Button
type="primary"
onClick={() => this.changeConfig('setHeight', 300)}
>
height : 300
</Button>
<Button
type="primary"
onClick={() => this.changeConfig('setHeight', 400)}
>
height : 400
</Button>
<Button
type="primary"
onClick={() => this.changeConfig('setHeight', 500)}
>
height : 500
</Button>
</Segment>
</Wrapper>
);
I want to use the J-Query property inside that DataGrid tag.
The jquery property is $('.child').resizable({handles: 'se'});
And DataGrid tag is a spread sheet in this project.

React map always calls method with data of last element

I am making a social media app. I am looping through all the comments and showing it on UI. When I click on edit, always the last comment's text show up on input. I tried many different things, changed structure, used bind to bind the context, but nothing has helped.
I am using React Material UI.
Here is the code:
render() {
const { anchorEl } = this.state;
const open = Boolean(anchorEl);
return(
<Panel>
<form noValidate autoComplete="off" onSubmit={this.onSubmit}>
<TextField
id={`comment${this.state.post_id}`}
name="comment"
fullWidth
placeholder="Comment here"
margin="normal"
value={this.state.comment}
onChange={this.handleChange}
InputProps={{
endAdornment : <InputAdornment position="end">
<IconButton onClick={this.resetTextField}>
<CloseIcon/>
</IconButton>
</InputAdornment>
}}
/>
</form>
{this.props.comments && this.props.comments.length > 0 &&
<RenderComments
comments={this.state.comments}
open={open}
anchorEl={this.state.anchorEl}
handleClick={this.handleClick}
handleClose={this.handleClose}
handleDelete={this.handleDelete}
handleEdit={this.handleEdit}
/>
}
</Panel>
)
}
const RenderComments = (props) => {
return props.comments.map(comment =>
<CommentBase
key={comment.id}
comment={comment}
open={props.open}
anchorEl={props.anchorEl}
handleClick={props.handleClick}
handleClose={props.handleClose}
handleDelete={props.handleDelete}
handleEdit={props.handleEdit}
/>
);
};
const CommentBase = ({comment, open, anchorEl, handleClick, handleClose, handleDelete, handleEdit}) => (
<CommentBasePanel>
<CommentText>
{comment.text}
<span style={{ float: 'right', fontSize: 10, color: '#A9A9A9' }}>{moment(comment.created_at).fromNow()}</span>
</CommentText>
<HelperAction>
<MoreVertIcon
id={comment.id}
aria-owns={open ? `simple-popper${comment.id}` : null}
aria-haspopup="true"
variant="contained"
onClick={handleClick}
/>
<Popover
id={`simple-popper${comment.id}`}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
>
<Typography style={{ padding: 10, cursor: 'pointer' }} onClick={() => handleEdit(comment)}>
Edit
</Typography>
<Typography style={{ padding: 10, color: red[500], cursor: 'pointer' }} onClick={() => handleDelete(comment.id)}>
Delete
</Typography>
</Popover>
</HelperAction>
</CommentBasePanel>
);
handleEdit = (comment) => {
this.setState({ comment: comment.text, comment_id: comment.id })
};
A console log on comment here in handleEdit method always logs the last comment no matter what comment I edit. Edit on first comment gives last comment text as you can see in the image.
Bad Popovers management
map copies the same open and anchorEl props to all Popover instances - handleClick (you didn't show this) *opens all of them in the same place** (the last one is on top).
FIX: include id in handleClick, save in state and use in condition for open property
FIX2: You can use one <Popover/> instance especially when not displaying any content related to specific comment.
PS. I spent more time recreating this (guessing missing parts) in stackblitz than real debugging (in fact only checking html structure for <Popover/> with rendered {comment.id}). Next time show more complete code or provide minimal working example.
If you update your RenderComments render method as follows, it should resolve your problem:
const RenderComments = (props) => {
return props.comments.map(comment =>
<CommentBase
key={comment.id}
comment={comment}
open={props.open}
anchorEl={props.anchorEl}
handleClick={ props.handleClick }
handleClose={ props.handleClose }
handleDelete={ () => props.handleDelete(comment.id) }
handleEdit={ () => props.handleEdit(comment) }
/>
);
};

Resources