how to clear state in a ReactJS component? - javascript

I am developing a chat app using react js and firebase database everything works fine but when i open a new person to chat the previous chat messages with other person renders..
there is link to deployed app: https://basic-chat-42.web.app
Q:how to clear the state every time i call chat function so there is no message from the previous chat
code:
import React from 'react'
import { connect } from 'react-redux';
import { adding_Dummy, get_user } from '../store/action'
import firebase from '../config/firebase'
class Chat extends React.Component {
constructor() {
super()
this.state = {
chat_user: {},
chat: [],
message: []
}
}
chat = (user) => {
this.setState({
chat_user: user
})
let cu_user= this.props.current_user
let chat_user = this.state.chat_user
let merged_uid = this.uid_merge(cu_user.uid,user.uid);
console.log('hammad',user.uid)
console.log('osama',cu_user.uid)
console.log('uid___WARS',cu_user.uid)
console.log('merged_uid>>>',merged_uid)
this.get_messages(merged_uid)
}
uid_merge =(id1,id2)=>{
if (id1<id2) {
return id1+id2
}
else
return id2+id1
}
send_message=()=>{
let user= this.props.current_user
let chat_user = this.state.chat_user
let merged_uid = this.uid_merge(user.uid,chat_user.uid);
firebase.database().ref('/').child(`chat/${merged_uid}`).push({
message :this.state.message,
name :user.name,
uid:user.uid
})
// this.state.chat.push({
// message : this.state.message
// })
// this.setState({
// chats: this.state.chats,
// message : ''
// })
}
get_messages=(uid)=>{
firebase.database().ref('/').child(`chat/${uid}`).on('child_added',(message)=>{
this.state.chat.push(message.val())
this.setState({
chat:this.state.chat,
message : ''
})
})
}
componentDidMount() {
this.props.get_user()
this.props.get_user()
}
render() {
console.log('stateChat=>', this.state)
let user = this.props.current_user
console.log('thistaet==>s', this.state)
console.log('asdCU',this.props.current_user)
return (
<div>
<h1>WELCOME ! {user.name}</h1>
<img src={user.profile} alt='img' />
<h2>Email: {user.email}</h2>
<button onClick={() => this.props.dum_data()}>adding dummy</button>
<button onClick={() => console.log(this.props)}>PRops</button>
<button onClick={() => this.props.get_user()}>get user</button>
{/* <button onClick={(e)=>console.log(e.target.value)}>button</button> */}
<div style={{ display: "flex" }}>
<div style={{ backgroundColor: "red" }}>
<h4>Chat users</h4>
<ul>
{this.props.users.map((v, i) => {
return v.uid !== user.uid && <li key={i}>{v.name} <button onClick={() => this.chat(v)} >CHAT</button></li>
})}
</ul>
</div>
<div style={{ width: 400, backgroundColor: "yellow" }}>
<h4>CHAT</h4>
{Object.keys(this.state.chat_user).length ?
<div>
<h4>{this.state.chat_user.name}</h4>
<ul>
{this.state.chat.map((v,i)=>{
return <li style={{color : v.uid === user.uid ? 'red' :'green'}}key={i}>{v.message}</li>
})}
<input value={this.state.message} onChange={(e)=>{this.setState({message:e.target.value})}} type="text" placeholder="Enter here" />
<button onClick={()=>this.send_message()}>Send </button>
</ul>
</div>
:
<div>
NO USER
</div>}
</div>
</div>
</div>
)
}
}
const mapStateToProps = (state) => ({
current_user: state.current_user,
users: state.users
})
const mapDispatchToProps = (dispatch) => ({
dum_data: () => dispatch(adding_Dummy()),
get_user: () => dispatch(get_user()),
})
export default connect(mapStateToProps, mapDispatchToProps)(Chat);

You need to clear the message when user clicked on chat button for the name
<button onClick={() => this.chat(v)} >CHAT
In the chat() method, update to reset the messages in state
this.setState({
chat_user: user,
chat: [],
message: []
})

Related

Action being callled but not hitting

I am using MERN stack and redux, i have created a findOneAndUpdate api and tested it on Postman. All works as it should but i can't get it working on my website. It never actually hits the updateSubject action. Am i passing in the data incorrectly? Anyone any idea what i am missing?
action
export const updateSubject = (id, rate, noOfVotes, rating) => (dispatch) => {
console.log("updateSubject hitting");
fetch(`/api/subjects/Subject/${id}/${rate}/${noOfVotes}/${rating}`)
.then((res) => res.json())
.then((subject) =>
dispatch({
type: UPDATE_SUBJECT,
subjects: subject,
})
);
};
api
// update subject
subjectRouter.put("/subject/:_id/:rate/:noOfVotes/:rating", (req, res) => {
Subject.findOneAndUpdate(
{ _id: req.params._id },
{
rating: Number(req.params.rating) + Number(req.params.rate),
noOfVotes: Number(req.params.noOfVotes) + 1,
},
{
new: true,
useFindAndModify: false,
}
)
.then((subjects) => res.json(subjects))
.catch((err) => console.log(err));
});
component
import React, { Component } from "react";
import PropTypes from "prop-types";
import GoogleSearch from "./GoogleSearch";
import { connect } from "react-redux";
import { fetchSubjects } from "../../actions/subject";
import { fetchComments } from "../../actions/comment";
import { updateSubject } from "../../actions/subject";
class Subject extends Component {
// on loading the subjects and comments
// are fetched from the database
componentDidMount() {
this.props.fetchSubjects();
this.props.fetchComments();
}
constructor(props) {
super(props);
this.state = {
// set inital state for subjects description
// and summary to invisible
viewDesription: -1,
viewSummary: -1,
comments: [],
};
}
componentWillReceiveProps(nextProps) {
// new subject and comments are added to the top
if (nextProps.newPost) {
this.props.subjects.unshift(nextProps.newPost);
}
if (nextProps.newPost) {
this.props.comments.unshift(nextProps.newPost);
}
}
clickHandler = (id) => {
// when a subject title is clicked pass in its id
// and make the desciption visible
const { viewDescription } = this.state;
this.setState({ viewDescription: viewDescription === id ? -1 : id });
// add relevant comments to the state
var i;
var temp = [];
for (i = 0; i < this.props.comments.length; i++) {
if (this.props.comments[i].subject === id) {
temp.unshift(this.props.comments[i]);
}
}
this.setState({
comments: temp,
});
// save the subject id to local storage
// this is done incase a new comment is added
// then the subject associated with it can be retrieved
// and added as a property of that comment
localStorage.setItem("passedSubject", id);
};
// hovering on and off subjects toggles the visibility of the summary
hoverHandler = (id) => {
this.setState({ viewSummary: id });
};
hoverOffHandler = () => {
this.setState({ viewSummary: -1 });
};
rateHandler = (id, rate) => {
var currRate;
var currVotes;
var i;
for (i = 0; i < this.props.subjects.length; i++) {
if (this.props.subjects[i]._id === id) {
currRate = this.props.subjects[i].rating;
currVotes = this.props.subjects[i].noOfVotes;
}
}
updateSubject(id, rate, currVotes, currRate);
console.log(id, rate, currVotes, currRate);
};
findAuthor(id) {
// search users for id return name
}
render() {
const subjectItems = this.props.subjects.map((subject) => {
// if the state equals the id set to visible if not set to invisible
var view = this.state.viewDescription === subject._id ? "" : "none";
var hover = this.state.viewSummary === subject._id ? "" : "none";
var comments = this.state.comments;
return (
<div key={subject._id}>
<div
className="subjectTitle"
onClick={() => this.clickHandler(subject._id)}
onMouseEnter={() => this.hoverHandler(subject._id)}
onMouseLeave={() => this.hoverOffHandler()}
>
<p className="title">{subject.title}</p>
<p className="rate">
Rate this subject:
<button onClick={() => this.rateHandler(subject._id, 1)}>
1
</button>
<button onClick={() => this.rateHandler(subject._id, 2)}>
2
</button>
<button onClick={() => this.rateHandler(subject._id, 3)}>
3
</button>
<button onClick={() => this.rateHandler(subject._id, 4)}>
4
</button>
<button onClick={() => this.rateHandler(subject._id, 5)}>
5
</button>
</p>
<p className="rating">
Rating: {(subject.rating / subject.noOfVotes).toFixed(1)}/5
</p>
<p className="summary" style={{ display: hover }}>
{subject.summary}
</p>
</div>
<div className="subjectBody " style={{ display: view }}>
<div className="subjectAuthor">
<p className="author" style={{ fontWeight: "bold" }}>
Subject created by: {subject.author} on {subject.date}
</p>
</div>
<div className="subjectDescription">
<p className="description">{subject.description}</p>
</div>
<div className="subjectLinks">Links:</div>
<div className="subjectComments">
<p style={{ fontWeight: "bold" }}>Comments:</p>
{comments.map((comment, i) => {
return (
<div key={i} className="singleComment">
<p>
{comment.title}
<br />
{comment.comment}
<br />
Comment by : {comment.author}
</p>
</div>
);
})}
<a href="/addcomment">
<div className="buttonAddComment">ADD COMMENT</div>
</a>
</div>
</div>
</div>
);
});
return (
<div id="Subject">
<GoogleSearch />
{subjectItems}
</div>
);
}
}
Subject.propTypes = {
fetchSubjects: PropTypes.func.isRequired,
fetchComments: PropTypes.func.isRequired,
subjects: PropTypes.array.isRequired,
comments: PropTypes.array.isRequired,
newPost: PropTypes.object,
};
const mapStateToProps = (state) => ({
subjects: state.subjects.items,
newSubject: state.subjects.item,
comments: state.comments.items,
newComment: state.comments.item,
});
// export default Subject;
export default connect(mapStateToProps, { fetchSubjects, fetchComments })(
Subject,
Comment
);
You are not attaching the updateSubject to the component itself, currently you only have fetchSubjects and fetchComments instead.
So, you would need to change your connect function like so:
export default connect(mapStateToProps, { fetchSubjects, fetchComments, updateSubject })(
Subject,
Comment
);
and then your calling function could be changed like so:
rateHandler = (id, rate) => {
const subject = this.props.subjects.find( subject => subject._id === id);
// when no subject was found, the updateSubject won't be called
subject && this.props.updateSubject( id, rate, subject.noOfVotes, subject.rating );
};
This would also mean that you should update your proptypes like:
Subject.propTypes = {
fetchSubjects: PropTypes.func.isRequired,
fetchComments: PropTypes.func.isRequired,
updateSubject: PropTypes.func.isRequired,
subjects: PropTypes.array.isRequired,
comments: PropTypes.array.isRequired,
newPost: PropTypes.object,
};
As you mentioned in the comments, you are using a put endpoint, so you should probably update your updateSubject method to the following
export const updateSubject = (id, rate, noOfVotes, rating) => (dispatch) => {
console.log("updateSubject hitting");
fetch(`/api/subjects/Subject/${id}/${rate}/${noOfVotes}/${rating}`, { method: 'PUT' })
.then((res) => res.json())
.then((subject) =>
dispatch({
type: UPDATE_SUBJECT,
subjects: subject,
})
);
};

Why isn't this button showing when the state is false?

I have created a component to function as a "Like/Unlike" button. When the state is true, the "Unlike" button successfully displays, but when I click "Unlike", and it DOES unlike successfully, the state should be set to false as (liked: false). However, I don't see the button.
One thing I noticed is, when I click "Unlike", the "Unlike" button disappears and the "Like" button does appear, for a millisecond, and then it vanishes in thin air. I cannot figure it out why.
Here are all the codes for my like button component:
import React from "react";
import { API, graphqlOperation } from "aws-amplify";
import { Button } from "element-react";
import { createLike, deleteLike } from "../graphql/mutations";
import { UserContext } from "../App";
class Like extends React.Component {
state = {
liked: "",
};
componentDidMount() {
this.setLiked();
}
setLiked() {
console.log(this.props);
const { user } = this.props;
const { post } = this.props;
if (post.likes.items.find((items) => items.liker === user.username)) {
this.setState({ liked: true });
console.log("liked: true");
} else {
this.setState({ liked: false });
console.log("liked: false");
}
}
handleLike = async (user) => {
try {
const input = {
liker: user.username,
likePostId: this.props.postId,
};
await API.graphql(graphqlOperation(createLike, { input }));
this.setState({
liked: true,
});
console.log("Liked!");
} catch (err) {
console.log("Failed to like", err);
}
};
handleUnlike = async (likeId) => {
try {
const input = {
id: likeId,
};
await API.graphql(graphqlOperation(deleteLike, { input }));
this.setState({
liked: false,
});
console.log("Unliked!");
} catch (err) {
console.log("Failed to unlike", err);
}
};
render() {
const { like } = this.props;
const { liked } = this.state;
return (
<UserContext.Consumer>
{({ user }) => (
<React.Fragment>
{liked ? (
<Button type="primary" onClick={() => this.handleUnlike(like.id)}>
Unlike
</Button>
) : (
<Button
type="primary"
onClick={() => this.handleLike(user, like.id)}
>
Like
</Button>
)}
</React.Fragment>
)}
</UserContext.Consumer>
);
}
}
export default Like;
The code of the parent component:
import React from "react";
import { API, graphqlOperation } from "aws-amplify";
import {
onCreateComment,
onCreateLike,
onDeleteLike,
} from "../graphql/subscriptions";
import { getPost } from "../graphql/queries";
import Comment from "../components/Comment";
import Like from "../components/Like";
import LikeButton from "../components/LikeButton";
import { Loading, Tabs, Icon } from "element-react";
import { Link } from "react-router-dom";
import { S3Image } from "aws-amplify-react";
import NewComment from "../components/NewComment";
class PostDetailPage extends React.Component {
state = {
post: null,
isLoading: true,
isAuthor: false,
};
componentDidMount() {
this.handleGetPost();
this.createCommentListener = API.graphql(
graphqlOperation(onCreateComment)
).subscribe({
next: (commentData) => {
const createdComment = commentData.value.data.onCreateComment;
const prevComments = this.state.post.comments.items.filter(
(item) => item.id !== createdComment.id
);
const updatedComments = [createdComment, ...prevComments];
const post = { ...this.state.post };
post.comments.items = updatedComments;
this.setState({ post });
},
});
this.createLikeListener = API.graphql(
graphqlOperation(onCreateLike)
).subscribe({
next: (likeData) => {
const createdLike = likeData.value.data.onCreateLike;
const prevLikes = this.state.post.likes.items.filter(
(item) => item.id !== createdLike.id
);
const updatedLikes = [createdLike, ...prevLikes];
const post = { ...this.state.post };
post.likes.items = updatedLikes;
this.setState({ post });
},
});
this.deleteLikeListener = API.graphql(
graphqlOperation(onDeleteLike)
).subscribe({
next: (likeData) => {
const deletedLike = likeData.value.data.onDeleteLike;
const updatedLikes = this.state.post.likes.items.filter(
(item) => item.id !== deletedLike.id
);
const post = { ...this.state.post };
post.likes.items = updatedLikes;
this.setState({ post });
},
});
}
componentWillUnmount() {
this.createCommentListener.unsubscribe();
}
handleGetPost = async () => {
const input = {
id: this.props.postId,
};
const result = await API.graphql(graphqlOperation(getPost, input));
console.log({ result });
this.setState({ post: result.data.getPost, isLoading: false }, () => {});
};
checkPostAuthor = () => {
const { user } = this.props;
const { post } = this.state;
if (user) {
this.setState({ isAuthor: user.username === post.author });
}
};
render() {
const { post, isLoading } = this.state;
return isLoading ? (
<Loading fullscreen={true} />
) : (
<React.Fragment>
{/*Back Button */}
<Link className="link" to="/">
Back to Home Page
</Link>
{/*Post MetaData*/}
<span className="items-center pt-2">
<h2 className="mb-mr">{post.title}</h2>
</span>
<span className="items-center pt-2">{post.content}</span>
<S3Image imgKey={post.file.key} />
<div className="items-center pt-2">
<span style={{ color: "var(--lightSquidInk)", paddingBottom: "1em" }}>
<Icon name="date" className="icon" />
{post.createdAt}
</span>
</div>
<div className="items-center pt-2">
{post.likes.items.map((like) => (
<Like
user={this.props.user}
like={like}
post={post}
postId={this.props.postId}
/>
))}
</div>
<div className="items-center pt-2">
{post.likes.items.length}people liked this.
</div>
<div>
Add Comment
<NewComment postId={this.props.postId} />
</div>
{/* Comments */}
Comments: ({post.comments.items.length})
<div className="comment-list">
{post.comments.items.map((comment) => (
<Comment comment={comment} />
))}
</div>
</React.Fragment>
);
}
}
export default PostDetailPage;
I think I know why it doesn't show up. It's because at first when the user hasn't liked it, there is no "like" object, so there is nothing to be shown, as it is only shown when there is a "like" mapped to it. I don't know how to fix it though.

How to modify a specific component of a list of component rendered using map in react?

I have a PostList component with an array of posts objects. I am rendering this list of post using another pure functional component Post using Array.map() method. Post component has another component - LikeButton to like or unlike a post. Now I want to show a spinner during like or unlike on top of that LikeButton component. LikeButton Component looks something like this:
const LikeButton = (props) => {
const likeBtnClasses = [classes.LikeBtn];
const loggedInUserId = useSelector((state) => state.auth.user.id);
const isLoading = useSelector((state) => state.post.loading);
const isPostLiked = props.post.likes.find(
(like) => like.user === loggedInUserId
);
const [isLiked, setLike] = useState(isPostLiked ? true : false);
const token = useSelector((state) => state.auth.token);
const dispatch = useDispatch();
if (isLiked) {
likeBtnClasses.push(classes.Highlight);
}
const postLikeHandler = () => {
if (!isLiked) {
setLike(true);
dispatch(actions.likePost(props.post._id, token));
} else {
setLike(false);
dispatch(actions.unlikePost(props.post._id, token));
}
};
return isLoading ? (
<Spinner />
) : (
<button
className={likeBtnClasses.join(" ")}
onClick={() => postLikeHandler()}
>
<i class="far fa-thumbs-up"></i>
<small>{props.post.likes.length}</small>
</button>
);
};
Instead of showing the spinner to that single post, I am seeing it on all the posts.
My Post component looks like this:
const Post = (props) => {
return (
<div className={classes.Post}>
<div className={classes.Author}>
<img src={props.postData.avatar} alt="avatar" />
<div className={classes.AuthorDetails}>
<h3>{props.postData.name}</h3>
</div>
</div>
<div className={classes.PostText}>
<p>{props.postData.text}</p>
</div>
<hr />
<div className={classes.PostTools}>
<LikeButton post={props.postData} />
<div className={classes.PostBtn}>
<i class="far fa-comments"></i>
<small>3</small>
</div>
<div className={classes.PostBtn}>
<i class="fas fa-share"></i>
<small>2</small>
</div>
</div>
</div>
);
};
PostList component:
class PostList extends React.Component {
state = {
posts: [
{
text: "POST1",
user: "XYZ",
name: "XYZ",
id: "post1",
likes: [],
},
{
text: "POST2",
user: "johndoe#test.com",
name: "John Doe",
id: "post2",
likes: [],
},
],
};
componentDidMount() {
if (this.props.token) {
this.props.onFetchPosts(this.props.token);
this.props.onFetchUserAuthData(this.props.token);
}
}
render() {
let posts = null;
if (this.props.posts.length === 0) {
posts = this.state.posts.map((post) => {
return <Post key={post.id} postData={post} />;
});
} else {
posts = this.props.posts.map((post) => {
return <Post key={post._id} postData={post} />;
});
}
return (
<div>
<CreatePost />
{posts}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
token: state.auth.token,
posts: state.post.posts,
loading: state.post.loading,
error: state.post.err,
};
};
const mapDispatchToProps = (dispatch) => {
return {
onFetchPosts: (token) => dispatch(actions.fetchPosts(token)),
onFetchUserAuthData: (token) => dispatch(actions.fetchUser(token)),
};
};
Please do some change in your to checking like/unlike is loading or not for the LikeButton.
const LikeButton = (props) => {
....
const [isButtonLoading, setButtonLoading] = useState(false);
...
return isButtonLoading ? (
<Spinner />
) : (
<button
className={likeBtnClasses.join(" ")}
onClick={() => postLikeHandler();setButtonLoading(true)}
>
<i class="far fa-thumbs-up"></i>
<small>{props.post.likes.length}</small>
</button>
);
};
Then on your dispatch callback need to set the isButtonLoading value to false.
const buttonCallback() {
// here we need to reset our flag
setButtonLoading(false);
}
const postLikeHandler = () => {
if (!isLiked) {
setLike(true);
// for this action you need to create third parameter called as callback so after response our buttonCallback will call
dispatch(actions.likePost(props.post._id, token, buttonCallback));
} else {
setLike(false);
// for this action you need to create third parameter called as callback so after response our buttonCallback will call
dispatch(actions.unlikePost(props.post._id, token, buttonCallback);
}
};
fore more details please check here.
Hope this will help you.

AutoComplete ReactJS / Redux NOT changing the search value

im trying to make the title of the movie clicked to be the in search input value.
exapmle: searched for "batman", clicked on result "batman ninja", search input becomes "batman ninja"
Search Component:
handleSelect is the function im passing to each search result
class MoviesSearch extends Component {
state = {
display: false,
title: ''
};
handleChange = e => {
this.props.movieSearch(e.target.value);
this.setState({
display: false
});
};
handleSubmit = e => {
e.preventDefault();
const { searchInput } = this.props;
this.props.fetchMovie(searchInput);
this.setState({
display: true
});
};
handleSelect = e => {
// this.setState({title: e.target.value})
// this.setState({title: e.target.value})
// this.setState({display: false, title: this.props.movies.Title})
// this.props.movieSearch(this.state.title)
}
render() {
//////////////////////////////////////////
////STATE:
const { movies } = this.props;
//////////////////////////////////////////
//// BUTTONS:
const btnDisabled = (
<button type="submit" disabled>
Search
</button>
);
const btnEnabled = <button type="submit">Search</button>;
///////////////////////////////////////////
//// DISPLAY CONTENT:
const display = (
<div className="dropdown-content">
<MovieList select={this.handleSelect}/>
</div>
);
///////////////////////////////////////////
console.log(this.state.title)
return (
<div className="movieSearch">
<form className="searchForm" onSubmit={this.handleSubmit}>
<div
className={movies.length === 0 ? "dropdown" : "dropdown is-active"}
>
<input
type="text"
placeholder="Enter Movie Name"
onChange={this.handleChange}
value={this.props.movies.Title}
/>
<div className="dropdown-menu">
{this.state.display ? display : null}
</div>
{this.props.searchInput.length <= 0 ? btnDisabled : btnEnabled}
</div>
</form>
</div>
);
}
}
const mapStateToProps = state => ({
searchInput: state.movies.searchInput,
movies: state.movies.movies
});
export default connect(mapStateToProps, { movieSearch, fetchMovie })(
MoviesSearch
);
MovieItem Component:
selectedItem is the function that was passed (handleSelect)
const MovieItem = ({ movie, selectedItem }) => {
return (
<NavLink className="dropdown-item" to="#" onClick={(e)=>selectedItem(e.movie.Title)}>
<img
className="poster"
src={movie.Poster === "N/A" ? "" : movie.Poster}
alt=""
/>
<span className="title">{movie.Title}</span>
</NavLink>
);
};
export default MovieItem;
In MovieItem component, use onClick={(e)=>selectedItem(movie.Title)}
In your parent component, use
handleSelect = value => {
this.setState({title: value})
}

Getting error TypeError: Cannot read property 'id' of undefined using React/Redux action

I am using react/redux and the error is happening after a deleteRequest is called using an action. The reducer removes the item from the array and I think that is why this is happening, but I should be changing the location so it should not be rendering this page anymore.
The direct error is coming from the Post component down below from the this.props.deleteRecord in the catch block.
I am also using turbo which is how I make the deleteRequest and store the data. If you need a reference here is the docs. https://www.turbo360.co/docs
Reducer:
import constants from '../constants';
const initialState = {
all: null
};
export default (state = initialState, action) => {
switch (action.type) {
case constants.POST_CREATED:
return {
...state,
all: state.all.concat(action.data),
[action.data.id]: action.data
};
case constants.RECORD_UPDATED:
return {
...state,
[action.data.id]: action.data,
all: all.map(item => (item.id === action.data.id ? action.data : item))
};
case constants.RECORD_DELETED:
const newState = {
...state,
all: state.all.filter(item => item.id !== action.data.id)
};
delete newState[action.payload.id];
return newState;
case constants.FETCH_POSTS:
const sortedData = action.data.sort((a, b) => {
return new Date(b.timestamp) - new Date(a.timestamp);
});
return { ...state, all: sortedData };
case constants.FETCH_POST:
return { ...state, [action.data.id]: action.data };
default:
return state;
}
};
Component:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import swal from 'sweetalert2/dist/sweetalert2.all.min.js';
import actions from '../../actions';
import { DateUtils } from '../../utils';
import { Reply } from '../containers';
import { UpdateRecord } from '../view';
class Post extends Component {
constructor() {
super();
this.state = {
editShow: false
};
}
componentDidMount() {
const { id } = this.props.match.params;
if (this.props.posts[id] != null) {
return;
}
this.props
.getRecord(id)
.then(() => {})
.catch(err => {
console.log(err);
});
}
updateRecord(params) {
const { id } = this.props.match.params;
const post = this.props.posts[id];
const { currentUser } = this.props.user;
if (post.profile.id !== currentUser.id) {
swal({
title: 'Oops...',
text: 'Must be owner of post',
type: 'error'
});
return;
}
this.props
.updateRecord(post, params)
.then(response => {
swal({
title: 'Success',
text: `${currentUser.username} Your post has been updated!`,
type: 'success'
});
})
.catch(err => {
console.log(err);
});
}
deleteRecord() {
const { id } = this.props.match.params;
const post = this.props.posts[id];
const { currentUser } = this.props.user;
if (currentUser.id !== post.profile.id) {
swal({
title: 'Oops...',
text: 'Must be owner of post',
type: 'error'
});
return;
}
this.props
.deleteRecord(post)
.then(() => {
this.props.history.push('/');
swal({
title: 'Post Delete',
text: 'Please create a new post',
type: 'success'
});
})
.catch(err => {
console.log(err);
});
}
render() {
const { id } = this.props.match.params;
const post = this.props.posts[id];
const { currentUser } = this.props.user;
if (post == null) {
return <div />;
}
return (
<div>
<div className="jumbotron">
<h1 className="display-3">{post.title}</h1>
<div className="row" style={{ marginBottom: '25px' }}>
<img className="img-fluid mx-auto" src={`${post.image}`} style={{ maxHeight: '400px' }} />
</div>
<p className="lead">{post.text}</p>
<hr className="my-4" />
{post.video == undefined ? null : (
<div className="row justify-content-center">
<div className="col-8">
<div className="lead" style={{ marginBottom: '25px' }}>
<div className="embed-responsive embed-responsive-16by9">
<video style={{ background: 'black' }} width="800" controls loop tabIndex="0">
<source src={post.video} type={post.videoType} />
Your browser does not support HTML5 video.
</video>
</div>
</div>
</div>
</div>
)}
<div className="lead">
<Link to={`/profile/${post.profile.id}`}>
<button className="btn btn-secondary btn-lg">{post.profile.username}</button>
</Link>
<p style={{ marginTop: '10px' }}>{DateUtils.relativeTime(post.timestamp)}</p>
</div>
{currentUser.id !== post.profile.id ? null : (
<div className="row justify-content-end">
<div className="col-md-2">
<button
onClick={() => {
this.setState({ editShow: !this.state.editShow });
}}
className="btn btn-success"
>
Edit
</button>
</div>
<div className="col-md-2">
<button onClick={this.deleteRecord.bind(this)} className="btn btn-danger">
Delete
</button>
</div>
</div>
)}
</div>
{this.state.editShow === false ? null : (
<div>
<UpdateRecord onCreate={this.updateRecord.bind(this)} currentRecord={post} />
</div>
)}
<div>
<Reply postId={post.id} />
</div>
</div>
);
}
}
const stateToProps = state => {
return {
posts: state.post,
user: state.user
};
};
const dispatchToProps = dispatch => {
return {
getRecord: id => dispatch(actions.getRecord(id)),
updateRecord: (entity, params) => dispatch(actions.updateRecord(entity, params)),
deleteRecord: entity => dispatch(actions.deleteRecord(entity))
};
};
export default connect(stateToProps, dispatchToProps)(Post);
Take a look here
case constants.RECORD_DELETED:
const newState = {
...state,
all: state.all.filter(item => item.id !== action.data.id)
};
delete newState[action.payload.id];
return newState;
You are using action.data when filtering, and action.payload when deleting from object

Categories

Resources