Skip to content

Commit

Permalink
Feature/add comments (#13)
Browse files Browse the repository at this point in the history
* refactor: Move Postform to folder structure

* feat: Basic scaffold and linking to comment form

* feat: add basic structure, header etc

* feat: Move form to post page

* feat: Conditional render for comments

* chore: add escaped word to remove warning

* feat: Add button component

* style: escape html

* feat: Add basic form (no functionality, ltd styling)

* styles: minor updates

* feat: WIP - first version of the fetch method

* feat: actions and reducers to add  comments

* feat: Add comments via form

* feat: validate form submissions to add comment

* fix: Resolve error btw optional and mandatory 'body' inputs

* fix: Resolve proptypes warning

* chore: Upgrade Styled Components to latest

* feat: Add Sidebar to NoPosts view

also tidy up where "Comments:" appears
  • Loading branch information
Sam Atkins committed Dec 15, 2017
1 parent 9d05539 commit 63ce871
Show file tree
Hide file tree
Showing 22 changed files with 601 additions and 183 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
@@ -1,5 +1,6 @@
{
"cSpell.words": [
"doesn",
"pagewrapper"
]
}
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -17,7 +17,7 @@
"redux-logger": "^3.0.6",
"redux-thunk": "^2.2.0",
"slugify": "^1.2.5",
"styled-components": "^2.2.3"
"styled-components": "^2.3.0"
},
"scripts": {
"start": "react-scripts start",
Expand Down
19 changes: 18 additions & 1 deletion src/actions/commentActions.js
@@ -1,4 +1,4 @@
import { fetchCommentsForSinglePost } from '../utils/api';
import { fetchCommentsForSinglePost, persistComment } from '../utils/api';

export const RECEIVE_COMMENTS_SUCCESS = 'RECEIVE_COMMENTS_SUCCESS';
export const receiveCommentsSuccess = payload => ({
Expand All @@ -15,3 +15,20 @@ export const fetchComments = payload => dispatch =>
fetchCommentsForSinglePost(payload)
.then(comments => dispatch(receiveCommentsSuccess(comments)))
.catch(error => dispatch(receiveCommentsFail(error)));

export const ADD_NEW_COMMENT_SUCCESS = 'ADD_NEW_COMMENT_SUCCESS';
export const addCommentSuccess = payload => ({
type: ADD_NEW_COMMENT_SUCCESS,
payload,
});

export const ADD_NEW_COMMENT_FAILURE = 'ADD_NEW_COMMENT_FAILURE';
export const addCommentError = () => ({
type: ADD_NEW_COMMENT_FAILURE,
});

export const addCommentPost = payload => (dispatch) => {
persistComment(payload)
.then(data => dispatch(addCommentSuccess(data)))
.catch(error => dispatch(addCommentError(error)));
};
4 changes: 2 additions & 2 deletions src/components/CommentView/CommentView.js
Expand Up @@ -16,8 +16,8 @@ const CommentView = ({ comment }) => (
{comment.author}
</StyledCommentMetaBold>
<StyledCommentMetaBold>Votes: {comment.voteScore}</StyledCommentMetaBold>
<StyledPostMetaBoldLink>edit</StyledPostMetaBoldLink>
<StyledPostMetaBoldLink>delete</StyledPostMetaBoldLink>
<StyledPostMetaBoldLink to="/">edit</StyledPostMetaBoldLink>
<StyledPostMetaBoldLink to="/">delete</StyledPostMetaBoldLink>
</CommentDiv>
);

Expand Down
4 changes: 2 additions & 2 deletions src/components/CommentView/CommentView.styles.js
@@ -1,4 +1,5 @@
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import {
LINK_HOVER,
POST_BACKGROUND,
Expand All @@ -24,7 +25,7 @@ export const StyledCommentMetaBold = styled.span`
padding-right: 1rem;
`;

export const StyledPostMetaBoldLink = styled.div`
export const StyledPostMetaBoldLink = styled(Link)`
color: ${POST_META};
font-size: x-small;
font-weight: bold;
Expand All @@ -33,6 +34,5 @@ export const StyledPostMetaBoldLink = styled.div`
:hover {
color: ${LINK_HOVER};
cursor: pointer;
}
`;
20 changes: 17 additions & 3 deletions src/components/FormErrorMessage/FormErrorMessage.js
Expand Up @@ -4,6 +4,7 @@ import { ErrorMessageWrapper, ErrorText } from './FormErrorMessage.styles';

const FormErrorMessage = ({
bodyErrorMessage,
commentBodyErrorMessage,
titleErrorMessage,
authorErrorMessage,
min,
Expand All @@ -20,6 +21,11 @@ const FormErrorMessage = ({
Oops, the text cannot be longer than {max} characters.
</ErrorText>
)}
{commentBodyErrorMessage && (
<ErrorText>
Oops, your comment needs to be between {min} and {max} characters.
</ErrorText>
)}
{authorErrorMessage && (
<ErrorText>
Oops, your username needs to be between {min} and {max} characters.
Expand All @@ -29,11 +35,19 @@ const FormErrorMessage = ({
);

FormErrorMessage.propTypes = {
bodyErrorMessage: PropTypes.bool.isRequired,
titleErrorMessage: PropTypes.bool.isRequired,
authorErrorMessage: PropTypes.bool.isRequired,
bodyErrorMessage: PropTypes.bool,
commentBodyErrorMessage: PropTypes.bool,
titleErrorMessage: PropTypes.bool,
authorErrorMessage: PropTypes.bool,
min: PropTypes.number.isRequired,
max: PropTypes.number.isRequired,
};

FormErrorMessage.defaultProps = {
bodyErrorMessage: false,
commentBodyErrorMessage: false,
titleErrorMessage: false,
authorErrorMessage: false,
};

export default FormErrorMessage;
2 changes: 2 additions & 0 deletions src/components/NoPosts/NoPosts.js
Expand Up @@ -3,11 +3,13 @@ import NavBarContainer from '../../containers/NavBarContainer';
import Header from '../Header';
import Footer from '../Footer';
import { StyledWrapper, NoPostsText, NoPostsWrapper } from './NoPosts.styles';
import SideBar from '../SideBar';

const NoPosts = () => (
<StyledWrapper>
<Header />
<NavBarContainer />
<SideBar />
<NoPostsWrapper>
<NoPostsText>Nothing to see here.</NoPostsText>
</NoPostsWrapper>
Expand Down
180 changes: 100 additions & 80 deletions src/components/PostView/PostView.js
@@ -1,4 +1,4 @@
import React from 'react';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import FaArrowUp from 'react-icons/lib/fa/arrow-up';
Expand All @@ -8,6 +8,7 @@ import Loading from '../Loading';
import Error from '../Error';
import NoMatchText from '../NoMatchText';
import CommentView from '../CommentView';
import CommentForm from '../../containers/CommentForm';
import {
getPostErrorStatus,
getPostLoadingStatus,
Expand All @@ -34,89 +35,108 @@ import {
PostTitleLink,
} from './PostView.styles';

const PostView = ({
post,
comments,
error,
loading,
commentsFlag,
homeFlag,
postPage,
requestDeletePostStatus,
confirmedDeletePostRequest,
submitPostToEdit,
userCancelDeleteRequest,
userRequestDeletePost,
}) => {
if (loading) {
return <Loading />;
}
class PostView extends Component {
renderComments = () => {
const { commentsFlag, comments } = this.props;
if (commentsFlag && comments.length === 0) {
return <div>there doesn&apos;t seem to be anything here</div>;
} else if (commentsFlag) {
return comments.map(comment => (
<CommentView key={comment.id} comment={comment} />
));
}
return null;
};

if (error) {
return <Error />;
}
render() {
const {
post,
error,
loading,
commentsFlag,
homeFlag,
postPage,
requestDeletePostStatus,
confirmedDeletePostRequest,
submitPostToEdit,
userCancelDeleteRequest,
userRequestDeletePost,
} = this.props;

if (postPage && post.deleted === true) {
return <NoMatchText />;
}
if (loading) {
return <Loading />;
}

if (error) {
return <Error />;
}

return (
<PostWrapper>
<StyledVoteCount>
<FaArrowUp />
<br />
{post.voteScore}
<br />
<FaArrowDown />
</StyledVoteCount>
<StyledPostMetaWrapper>
<PostTitleLink
to={`/${post.category}/${post.id}/${slugifyPostTitle(post.title)}`}
>
{post.title}
</PostTitleLink>
<StyledPostMeta>
Submitted {distanceInWordsToNow(post.timestamp)} ago by {post.author}
</StyledPostMeta>
</StyledPostMetaWrapper>
{!homeFlag && <StyledPostBody>{post.body}</StyledPostBody>}
<StyledCommentWrapper>
<StyledPostMetaBoldLink
to={`/${post.category}/${post.id}/${slugifyPostTitle(post.title)}`}
>
{post.commentCount} comments
</StyledPostMetaBoldLink>
<StyledPostMetaBoldLink
to="/newpost"
onClick={() => submitPostToEdit(post.id)}
>
edit
</StyledPostMetaBoldLink>
{!requestDeletePostStatus && (
<StyledPostMetaBold onClick={() => userRequestDeletePost(post.id)}>
delete
</StyledPostMetaBold>
)}
{requestDeletePostStatus && (
<div>
<StyledPostMetaBoldWarning
onClick={() => confirmedDeletePostRequest(post.id)}
>
confirm delete?
</StyledPostMetaBoldWarning>
<StyledPostMetaBold onClick={() => userCancelDeleteRequest()}>
cancel
if (postPage && post.deleted === true) {
return <NoMatchText />;
}

return (
<PostWrapper>
<StyledVoteCount>
<FaArrowUp />
<br />
{post.voteScore}
<br />
<FaArrowDown />
</StyledVoteCount>
<StyledPostMetaWrapper>
<PostTitleLink
to={`/${post.category}/${post.id}/${slugifyPostTitle(post.title)}`}
>
{post.title}
</PostTitleLink>
<StyledPostMeta>
Submitted {distanceInWordsToNow(post.timestamp)} ago by{' '}
{post.author}
</StyledPostMeta>
</StyledPostMetaWrapper>
{!homeFlag && <StyledPostBody>{post.body}</StyledPostBody>}
<StyledCommentWrapper>
<StyledPostMetaBoldLink
to={`/${post.category}/${post.id}/${slugifyPostTitle(post.title)}`}
>
{post.commentCount} comments
</StyledPostMetaBoldLink>
<StyledPostMetaBoldLink
to="/newpost"
onClick={() => submitPostToEdit(post.id)}
>
edit
</StyledPostMetaBoldLink>
{!requestDeletePostStatus && (
<StyledPostMetaBold onClick={() => userRequestDeletePost(post.id)}>
delete
</StyledPostMetaBold>
</div>
)}
{commentsFlag &&
comments.map(comment => (
<CommentView key={comment.id} comment={comment} />
))}
</StyledCommentWrapper>
</PostWrapper>
);
};
)}
{requestDeletePostStatus && (
<div>
<StyledPostMetaBoldWarning
onClick={() => confirmedDeletePostRequest(post.id)}
>
confirm delete?
</StyledPostMetaBoldWarning>
<StyledPostMetaBold onClick={() => userCancelDeleteRequest()}>
cancel
</StyledPostMetaBold>
</div>
)}
{commentsFlag && (
<div>
<CommentForm />
Comments:
</div>
)}
{this.renderComments()}
</StyledCommentWrapper>
</PostWrapper>
);
}
}

PostView.propTypes = {
post: PropTypes.object.isRequired,
Expand Down
4 changes: 2 additions & 2 deletions src/containers/App.js
Expand Up @@ -6,7 +6,7 @@ import { fetchCategories } from '../actions/categoryActions';
import { fetchPosts } from '../actions/postActions';
import HomePageWrapper from '../components/HomePageWrapper';
import CategoryRoutingContainer from './CategoryRoutingContainer';
import NewPostForm from './NewPostForm';
import PostForm from './PostForm';

class App extends Component {
componentWillMount() {
Expand All @@ -19,7 +19,7 @@ class App extends Component {
<BrowserRouter>
<Switch>
<Route exact path="/" component={HomePageWrapper} />
<Route exact path="/newpost" component={NewPostForm} />
<Route exact path="/newpost" component={PostForm} />
<Route path="/:categoryUrl" component={CategoryRoutingContainer} />
</Switch>
</BrowserRouter>
Expand Down

0 comments on commit 63ce871

Please sign in to comment.