React-admin: How to pass logged in user ID to API backend - reactjs

I am using React-admin to make an application to manage articles and have many people logged in to write articles
I want to pass the USER_ID who is logged in to React-admin to CREATED_BY of API backend when posting a Article
Here is the code example for the add a Post function
export const PostCreate = (props) => {
return (
<Create {...props}>
<PostForm></PostForm>
</Create>)
};
const PostForm = (props ) => (
<FormWithRedirect
{...props}
render={(formProps) => (
// here starts the custom form layout
<form>
<Box p="1em">
<Box display="flex">
<Box flex={2} mr="1em">
<Typography variant="h6" gutterBottom>
Offer
</Typography>
<Box display="flex">
<TextInput source="title" fullWidth />
</Box>
<TextInput source="slug" fullWidth />
<ImageInput
source="pictures"
label="Related pictures"
accept="image/*"
fullWidth
>
<ImageField source="image" title="title" />
</ImageInput>
<TextInput multiline source="description" fullWidth />
<MarkdownInput source="content" fullWidth></MarkdownInput>
<Box mt="1em" />
<Typography variant="h6" gutterBottom>
Address
</Typography>
<Box display="flex">
<Box flex={1} mr="0.5em">
<BooleanInput label="Featured" source="featured" />
</Box>
<Box flex={1} mr="0.5em">
<BooleanInput label="Publish" source="published" />
</Box>
</Box>
</Box>
</Box>
</Box>
<Toolbar>
<Box display="flex" justifyContent="space-between" width="100%">
<SaveButton
saving={formProps.saving}
handleSubmitWithRedirect={formProps.handleSubmitWithRedirect}
redirect={
redirectEdit ? redirectEdit : `/posts/${formProps.record.id}`
}
/>
<DeleteButton
record={formProps.record}
redirect={`/posts/`}
/>
</Box>
</Toolbar>
</form>
)}
/>
)
I tried to get UserId from useGetIdentity
import { useGetIdentity } from "react-admin";
but don't know how to pass the value in
export const PostCreate = (props) => {
const { identity } = useGetIdentity();
return (
<Create {...props}>
<PostForm defaultValue={{ user_id: identity }}></PostForm>
</Create>)
};

Related

validateDOMNesting(...): <li> cannot appear as a descendant of <li>

I'm getting the warning message validateDOMNesting(...): cannot descendant of li
in the console and it shows the error is on the treeview and the timeline I dont know where to fix the code, the below code is facing that warning is there any solution for this?
<Box>
<TreeView >
<Timeline key={comment.id}>
<TimelineItem>
<TimelineSeparator>
<Avatar {...stringAvatar(comment.username) } />{" "}
<TimelineConnector />
</TimelineSeparator>
<TimelineOppositeContent style={{maxWidth: "1px",paddingLeft: "0px",paddingRight: "0px", }}/>
<TimelineContent>
<Stack direction="row" spacing={1}>
<Typography variant="h6" sx={{fontSize:"15px" ,fontWeight:"bold"}}>
{comment.username.charAt(0).toUpperCase() + comment.username.slice(1)}
</Typography>
<Item variant="span" sx={{fontSize:"10px"}}> {createdAt}</Item>
</Stack>
<ReactMarkdown children={comment.body} rehypePlugins={[rehypeRaw]} />
<TreeItem
nodeId="1" label={
<TimelineContent>
{canReply && (<Chip label="Reply" onClick={() => setActiveComment({ id: comment.id, type: "replying", }) }
sx={{fontSize:"10px",mb:1}} size="small" icon={<ReplyIcon /> }/> )}
{isReplying && (
<CommentForm submitLabel="Reply" hasCancelButton handleSubmit={(text) => addComment(text, replyId)} handleCancel={() => { setActiveComment(null);}} />)}
</TimelineContent> } >
<TreeItem
nodeId="2"
label={
<Timeline>
{replies.length > 0 && (
<div>
{replies.map((reply) => (
<Comment
comment={reply}
key={reply.id}
setActiveComment={setActiveComment}
activeComment={activeComment}
addComment={addComment}
parentId={comment.id}
replies={[]}
currentUserId={currentUserId}
/>
))}
</div>
)}
</Timeline>}/>
</TreeItem>
</TimelineContent>
</TimelineItem>
</Timeline>
</TreeView>
</Box>

React Material UI Cards w/Modal

I'm trying to configure this React JS / Material UI modal dialog so that when the user clicks on the card, it opens a corresponding full-sized image (with title and subtitle). Data for each card is mapped from a JSON file (via AXIOS).
I can get the modal window to open, but it is showing all of the card images in the modal and they are stacked on top of each other. The console.log("SELECTED CAMPAIGN: ", selectedCampaign) code inside the handleOpen() function is one click behind...it actually logs the object that was selected prior to the current click event.
I'm relatively new to functional components and hooks, so I know that I am making simple and fundamental mistakes...please help me figure out the proper way to set this up:
const CampaignItems = ({campaigns, loading}) => {
const classes = useStyles();
const [open, setOpen] = useState(false);
const [selectedCampaign, setSelectedCampaign] = useState();
const handleOpen = (campaign) => {
setSelectedCampaign(campaign);
console.log("SELECTED CAMPAIGN: ", selectedCampaign);
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
..................
<div>
<GridContainer>
{campaigns && search(campaigns).map((campaign) => (
<GridItem key={campaign.id} xs={12} sm={6} md={4}>
<Card className={classes.root}>
<CardActionArea>
<CardMedia
component="img"
alt={campaign.alt}
height="140"
image={campaign.image}
title={campaign.title}
onClick={() => handleOpen(campaign)}
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{campaign.title}
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
{campaign.subtitle}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<IconButton
size="medium"
color="primary"
aria-label="More Information"
onClick={() => handleOpen(campaign)}
>
<InfoIcon />
</IconButton>
<Modal
className={classes.modal}
open={open}
onClose={handleClose}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500
}}
>
<Fade
in={open}
>
<div className={classes.paper}>
<h6>{campaign.title}</h6>
<p>{campaign.subtitle}</p>
<img src={campaign.image} />
</div>
</Fade>
</Modal>
</CardActions>
</Card>
</GridItem>
))}
</GridContainer>
</div>
..................
It seems your issue is that you use only a single open state to trigger your modals to open, so they are all triggered open concurrently.
I suggest to instead using the selectedCampaign of the card you're interacting with and use the campaign id that to match which modal to open.
const CampaignItems = ({campaigns, loading}) => {
...
const [selectedCampaign, setSelectedCampaign] = useState(null);
const handleOpen = (campaign) => () => {
setSelectedCampaign(selectedCampaign =>
selectedCampaign.id === campaign.id ? null : campaign
);
};
const handleClose = () => {
setSelectedCampaign(null);
};
...
<div>
<GridContainer>
{campaigns && search(campaigns).map((campaign) => (
<GridItem key={campaign.id} xs={12} sm={6} md={4}>
<Card className={classes.root}>
<CardActionArea>
<CardMedia
...
onClick={handleOpen(campaign)}
/>
...
</CardActionArea>
<CardActions>
<IconButton
...
onClick={handleOpen(campaign)}
>
...
</IconButton>
<Modal
...
open={selectedCampaign.id === campaign.id} // <-- check id match
onClose={handleClose}
...
>
...
</Modal>
</CardActions>
</Card>
</GridItem>
))}
</GridContainer>
</div>
...

how to show the contents in one ui using reactjs

I'm new to framework, the no.of contents are getting overloaded. the problem is when we have multiple users then their name need to be displayed according to the content of the message, for that we need to give mapping at first, but the data is getting overloaded.
Can anyone help me in this query?
Here is the code:
<div>
{this.state.data.map(item => {
return (
<Card>
<CardHeader
avatar={<div>Sanjana (or) someone else</div>}
title={
<>
<InputBase
placeholder="Search Google Maps"
margin="normal"
/>
<IconButton type="submit" aria-label="search">
<SearchIcon />
</IconButton>
</>
}
/>
<Divider />
<CardContent className={classes.contentHeight} id="chatList">
<div>
<Message isSender content={item.message} />
<Message content={item.message} />
</div>
</CardContent>
<Divider />
<CardActions>
<Paper className={classes.contentPaper}>
<Input
margin="dense"
className={classes.input}
placeholder="Enter a Message"
disableUnderline
/>
</Paper>
</CardActions>
</Card>
);
})}
</div>
Can anyone help me in this? thanks in advance!
I think you may want to only map the data messages, not the chat container(s)
render() {
const { classes } = this.props;
return (
<div>
<Card>
<CardHeader
avatar={<div>Sanjana (or) someone else</div>}
title={
<>
<InputBase placeholder="Search Google Maps" margin="normal" />
<IconButton type="submit" aria-label="search">
<SearchIcon />
</IconButton>
</>
}
/>
<Divider />
<CardContent className={classes.contentHeight} id="chatList">
{this.state.data.map(item => {
return (
<div>
<Message isSender content={item.message} />
<Message content={item.message} />
</div>
);
})}
</CardContent>
<Divider />
<CardActions>
<Paper className={classes.contentPaper}>
<Input
margin="dense"
className={classes.input}
placeholder="Enter a Message"
disableUnderline
/>
</Paper>
</CardActions>
</Card>
</div>
);
}

Unable to set the content of the box in an appropraite way using reactjs

I'm new to material UI, i was going through few of the links and then i could built the content of the message.
Here is the Code:
class Data extends React.Component {
render() {
const { classes } = this.props;
return (
<Card>
<CardHeader
avatar={<Avatar aria-label="recipe">S</Avatar>}
title={
// <TextField placeholder="Search" margin="normal" />
<>
<InputBase placeholder="Search Google Maps" margin="normal" />
<IconButton type="submit" aria-label="search">
<SearchIcon />
</IconButton>
</>
}
/>
<Divider />
<CardContent className={classes.contentHeight} >
<Message isSender content="Hello" />
<Message content="Hello back" />
<Message isSender content="Anyone there" />
<Message content="Yes" />
<Message isSender content="Thank you for replying" />
</CardContent>
</Card>
);
}
}
Can anyone help me in this? Thanks in advance
You can add a div to bottom of your Card content component and scroll to it whenever your component is updated.Check here CodeSandBox
<div
style={{ float: "left", clear: "both" }}
ref={el => {
this.messagesEnd = el;
}}
/>
componentDidMount() {
this.scrollToBottom();
}
scrollToBottom = () => {
this.messagesEnd.scrollIntoView({ behavior: "smooth" });
};
componentDidUpdate() {
this.scrollToBottom();
}

Using Ref inside stateless functional component is not working in React JS

I am developing a React JS Web Application. I am new to react js. Now, I am trying to use Ref inside the stateless functional component to retrieve the input value. I followed some of the solutions I found online.
This is my component
const Login = (props) => {
const {
classes,
width
} = props;
// Flip container to column on mobile screens.
const panelDirection = width === 'xs' ? 'column' : 'row';
let emailInput = null;
let passwordInput = null;
return (
<Grid
container
direction="row"
spacing={0}
justify="center"
alignItems="center"
className={classes.background}
>
<Grid item sm={10} xs={12} className={scss.panel}>
<form className="full-height" action="post">
<Grid direction={panelDirection} container spacing={0}>
<Grid
item
sm={6}
xs={12}
>
<Card className={classNames(scss.card, classes['primary-card'])}>
<CardContent className={scss['signup-content']}>
<img src={logoImage} className={scss['signup-logo']} alt="logo" />
<Typography variant="headline" component="h2" gutterBottom>
Web Portal
</Typography>
</CardContent>
<CardActions>
<Button fullWidth href="/register" color="secondary" variant="raised">Create an account</Button>
</CardActions>
</Card>
</Grid>
<Grid
item
sm={6}
xs={12}
>
<Card className={scss.card}>
<CardContent>
<TextField
ref={(input) => { emailInput = input }}
label="Email Address"
fullWidth
/>
<TextField
ref={(input) => { passwordInput = input }}
label="Password"
fullWidth
margin="normal"
type="password"
/>
</CardContent>
<CardActions className={scss['login-actions']}>
<Button href="/login" color="primary" variant="raised">Login</Button>
<Button href="/forgot-password">Forgot Password</Button>
</CardActions>
</Card>
</Grid>
</Grid>
</form>
</Grid>
</Grid>
);
};
As you can see, I am using ref to retrieve the values of email and password input fields. But, when I run, it is still giving me this error.
Warning: Stateless function components cannot be given refs. Attempts to access this ref will fail.
So, how can I fix my code? How can I use Ref correctly in the stateless function component?
Obviously, I followed this, How can I attach to a stateless component's ref in React?
I tried using the class as well. It is giving me the same error. This is the class version of my component.
class Login extends React.Component {
submitForm = e => {
e.preventDefault();
}
constructor(props)
{
super(props);
this.emailInput = React.createRef();
this.passwordInput = React.createRef();
}
render () {
const { classes, width } = this.props;
// Flip container to column on mobile screens.
const panelDirection = width === 'xs' ? 'column' : 'row';
return (
<Grid
container
direction="row"
spacing={0}
justify="center"
alignItems="center"
className={classes.background}
>
<Grid item sm={10} xs={12} className={scss.panel}>
<form className="full-height" action="post" onSubmit={this.submitForm}>
<Grid direction={panelDirection} container spacing={0}>
<Grid
item
sm={6}
xs={12}
>
<Card className={classNames(scss.card, classes['primary-card'])}>
<CardContent className={scss['signup-content']}>
<img src={logoImage} className={scss['signup-logo']} alt="logo" />
<Typography variant="headline" component="h2" gutterBottom>
Web Portal
</Typography>
</CardContent>
<CardActions>
<Button fullWidth href="/register" color="secondary" variant="raised">Create an account</Button>
</CardActions>
</Card>
</Grid>
<Grid
item
sm={6}
xs={12}
>
<Card className={scss.card}>
<CardContent>
<TextField
ref={this.emailInput}
label="Email Address"
fullWidth
/>
<TextField
ref={this.passwordInput}
label="Password"
fullWidth
margin="normal"
type="password"
/>
</CardContent>
<CardActions className={scss['login-actions']}>
<Button type="submit" color="primary" variant="raised">Login</Button>
<Button href="/forgot-password">Forgot Password</Button>
</CardActions>
</Card>
</Grid>
</Grid>
</form>
</Grid>
</Grid>
)
}
}
Login.propTypes = {
classes: PropTypes.shape({}).isRequired,
width: PropTypes.string.isRequired
};
export default compose(withWidth(), withStyles(themeStyles, { withTheme: true }))(Login);
If you insist in using stateless component (which to me they are great) you should use a callback to retrieve the value of your input:
// Login.js
const Login = (props) => {
const {
classes,
width,
onChange, // <- get the callback here
} = props;
...
return (
...
<TextField
name="email"
onChange={onChange}
label="Email Address"
fullWidth
/>
<TextField
name="password"
onChange={onChange}
label="Password"
fullWidth
margin="normal"
type="password"
/>
...
);
// Somewhere to include Login
class LoginPage extends Component {
...
handleInputChange({ target }) {
...
console.log(target.name, target.value);
}
render (
<Login onChange={this.handleInputChange} ... />
)
}
// Or connect it to Redux
const mapDispatchToProps = dispatch => {
const updateLoginInputValues = ({ target }) => dispatch(updateLoginInputValues(target.name, target.value)));
return {
onChange: updateLoginInputValues,
}
};
const connectedLogin = connect(null, mapDispatchToProps)(Login
The only part that you can improve is basically either handling the values by a state management or directly with React. Other than this you need to address the state at some point and you can't keep all of you components stateless.
State less component means it does not contains state, component only updates through props. So you can use class container for that. here is the solution...
import React, { Component } from "react";
class Login extends Component {
constructor(props) {
super(props);
this.emailInput = React.createRef();
this.passwordInput = React.createRef();
}
render() {
const { classes, width } = this.props;
// Flip container to column on mobile screens.
const panelDirection = width === "xs" ? "column" : "row";
return (
<Grid container direction="row" spacing={0} justify="center" alignItems="center" className={classes.background}>
<Grid item sm={10} xs={12} className={scss.panel}>
<form className="full-height" action="post">
<Grid direction={panelDirection} container spacing={0}>
<Grid item sm={6} xs={12}>
<Card className={classNames(scss.card, classes["primary-card"])}>
<CardContent className={scss["signup-content"]}>
<img src={logoImage} className={scss["signup-logo"]} alt="logo" />
<Typography variant="headline" component="h2" gutterBottom>
Web Portal
</Typography>
</CardContent>
<CardActions>
<Button fullWidth href="/register" color="secondary" variant="raised">
Create an account
</Button>
</CardActions>
</Card>
</Grid>
<Grid item sm={6} xs={12}>
<Card className={scss.card}>
<CardContent>
<TextField ref={this.emailInput} label="Email Address" fullWidth />
<TextField ref={this.passwordInput} label="Password" fullWidth margin="normal" type="password" />
</CardContent>
<CardActions className={scss["login-actions"]}>
<Button href="/login" color="primary" variant="raised">
Login
</Button>
<Button href="/forgot-password">Forgot Password</Button>
</CardActions>
</Card>
</Grid>
</Grid>
</form>
</Grid>
</Grid>
)
}
}
export default Login;
Now you can get value of the textfields like this
this.emailInput.current.value and this.passwordInput.current.value

Resources