Skip to content
Permalink
Browse files

Add button to toggle comment is post update

  • Loading branch information
riggraz committed Oct 2, 2019
1 parent e8d7fcc commit 2c2a0e0c82e299bb2c31cb7d53ee967b082cfb4d
@@ -1,5 +1,5 @@
class CommentsController < ApplicationController
before_action :authenticate_user!, only: [:create]
before_action :authenticate_user!, only: [:create, :update]

def index
comments = Comment
@@ -33,12 +33,32 @@ def create
end
end

def update
comment = Comment.find_by(post_id: params[:post_id])
comment.assign_attributes(comment_params)

if !current_user.power_user? && current_user.id != post.user_id
render json: I18n.t('errors.unauthorized'), status: :unauthorized
return
end

if comment.save
render json: comment.attributes.merge(
{ user_full_name: current_user.full_name, user_email: current_user.email}
)
else
render json: {
error: I18n.t('errors.comment.update', message: comment.errors.full_messages)
}, status: :unprocessable_entity
end
end

private

def comment_params
params
.require(:comment)
.permit(:body, :parent_id)
.permit(:body, :parent_id, :is_post_update)
.merge(
user_id: current_user.id,
post_id: params[:post_id]
@@ -0,0 +1,45 @@
import { ThunkAction } from "redux-thunk";
import { State } from "../reducers/rootReducer";
import { Action } from "redux";

export const TOGGLE_COMMENT_IS_UPDATE_SUCCESS = 'TOGGLE_COMMENT_IS_UPDATE_SUCCESS';
export interface ToggleIsUpdateSuccessAction {
type: typeof TOGGLE_COMMENT_IS_UPDATE_SUCCESS;
commentId: number;
}

const toggleIsUpdateSuccess = (
commentId: number,
): ToggleIsUpdateSuccessAction => ({
type: TOGGLE_COMMENT_IS_UPDATE_SUCCESS,
commentId,
});

export const toggleCommentIsUpdate = (
postId: number,
commentId: number,
currentIsPostUpdate: boolean,
authenticityToken: string,
): ThunkAction<void, State, null, Action<string>> => async (dispatch) => {
try {
const response = await fetch(`/posts/${postId}/comments/${commentId}`, {
method: 'PATCH',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'X-CSRF-Token': authenticityToken,
},
body: JSON.stringify({
comment: {
is_post_update: !currentIsPostUpdate,
},
})
});

if (response.status === 200) {
dispatch(toggleIsUpdateSuccess(commentId));
}
} catch (e) {
console.log(e);
}
}
@@ -12,13 +12,15 @@ import friendlyDate from '../../helpers/friendlyDate';
interface Props {
id: number;
body: string;
isPostUpdate: boolean;
userFullName: string;
userEmail: string;
updatedAt: string;

replyForm: ReplyFormState;
handleToggleCommentReply(): void;
handleCommentReplyBodyChange(e: React.FormEvent): void;
handleToggleIsCommentUpdate(commentId: number, currentIsPostUpdate: boolean): void;
handleSubmitComment(body: string, parentId: number): void;

isLoggedIn: boolean;
@@ -29,13 +31,15 @@ interface Props {
const Comment = ({
id,
body,
isPostUpdate,
userFullName,
userEmail,
updatedAt,

replyForm,
handleToggleCommentReply,
handleCommentReplyBodyChange,
handleToggleIsCommentUpdate,
handleSubmitComment,

isLoggedIn,
@@ -46,17 +50,26 @@ const Comment = ({
<div className="commentHeader">
<Gravatar email={userEmail} size={24} className="gravatar" />
<span className="commentAuthor">{userFullName}</span>
{ isPostUpdate ? <span className="postUpdateBadge">Post update</span> : null }
</div>
<p className="commentBody">{body}</p>
<div className="commentFooter">
<a className="commentReplyButton" onClick={handleToggleCommentReply}>
<a className="commentReplyButton commentLink" onClick={handleToggleCommentReply}>
{ replyForm.isOpen ? 'Cancel' : 'Reply' }
</a>
{
isPowerUser ?
<React.Fragment>
<Separator />
<a
onClick={() => handleToggleIsCommentUpdate(id, isPostUpdate)}
className="commentLink"
>
{ isPostUpdate ? 'No post update' : 'Post update' }
</a>
<Separator />
<a href={`/admin/comments/${id}`} data-turbolinks="false">Edit</a>

</React.Fragment>
:
null
@@ -13,6 +13,7 @@ interface Props {

toggleCommentReply(commentId: number): void;
setCommentReplyBody(commentId: number, body: string): void;
handleToggleIsCommentUpdate(commentId: number, currentIsPostUpdate: boolean): void;
handleSubmitComment(body: string, parentId: number): void;

isLoggedIn: boolean;
@@ -28,6 +29,7 @@ const CommentList = ({

toggleCommentReply,
setCommentReplyBody,
handleToggleIsCommentUpdate,
handleSubmitComment,

isLoggedIn,
@@ -47,6 +49,7 @@ const CommentList = ({
setCommentReplyBody(comment.id, (e.target as HTMLTextAreaElement).value)
)
}
handleToggleIsCommentUpdate={handleToggleIsCommentUpdate}
handleSubmitComment={handleSubmitComment}
{...comment}

@@ -63,6 +66,7 @@ const CommentList = ({

toggleCommentReply={toggleCommentReply}
setCommentReplyBody={setCommentReplyBody}
handleToggleIsCommentUpdate={handleToggleIsCommentUpdate}
handleSubmitComment={handleSubmitComment}

isLoggedIn={isLoggedIn}
@@ -23,6 +23,12 @@ interface Props {
requestComments(postId: number, page?: number): void;
toggleCommentReply(commentId: number): void;
setCommentReplyBody(commentId: number, body: string): void;
toggleCommentIsPostUpdate(
postId: number,
commentId: number,
currentIsPostUpdate: boolean,
authenticityToken: string,
): void;
submitComment(
postId: number,
body: string,
@@ -36,6 +42,15 @@ class CommentsP extends React.Component<Props> {
this.props.requestComments(this.props.postId);
}

_handleToggleIsCommentUpdate = (commentId: number, currentIsPostUpdate: boolean) => {
this.props.toggleCommentIsPostUpdate(
this.props.postId,
commentId,
currentIsPostUpdate,
this.props.authenticityToken,
);
}

_handleSubmitComment = (body: string, parentId: number) => {
this.props.submitComment(
this.props.postId,
@@ -92,6 +107,7 @@ class CommentsP extends React.Component<Props> {
replyForms={replyForms}
toggleCommentReply={toggleCommentReply}
setCommentReplyBody={setCommentReplyBody}
handleToggleIsCommentUpdate={this._handleToggleIsCommentUpdate}
handleSubmitComment={this._handleSubmitComment}
parentId={null}
level={1}
@@ -5,6 +5,7 @@ import {
toggleCommentReply,
setCommentReplyBody,
} from '../actions/handleCommentReplies';
import { toggleCommentIsUpdate } from '../actions/updateComment';
import { submitComment } from '../actions/submitComment';

import { State } from '../reducers/rootReducer';
@@ -31,6 +32,15 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(setCommentReplyBody(commentId, body));
},

toggleCommentIsPostUpdate(
postId: number,
commentId: number,
currentIsPostUpdate: boolean,
authenticityToken: string,
) {
dispatch(toggleCommentIsUpdate(postId, commentId, currentIsPostUpdate, authenticityToken));
},

submitComment(
postId: number,
body: string,
@@ -20,6 +20,11 @@ import {
COMMENT_SUBMIT_FAILURE,
} from '../actions/submitComment';

import {
ToggleIsUpdateSuccessAction,
TOGGLE_COMMENT_IS_UPDATE_SUCCESS,
} from '../actions/updateComment';

import commentReducer from './commentReducer';
import replyFormsReducer from './replyFormsReducer';

@@ -47,7 +52,8 @@ const commentsReducer = (
action:
CommentsRequestActionTypes |
HandleCommentRepliesType |
CommentSubmitActionTypes
CommentSubmitActionTypes |
ToggleIsUpdateSuccessAction
): CommentsState => {
switch (action.type) {
case COMMENTS_REQUEST_START:
@@ -95,6 +101,18 @@ const commentsReducer = (
replyForms: replyFormsReducer(state.replyForms, action),
};

case TOGGLE_COMMENT_IS_UPDATE_SUCCESS:
return {
...state,
items:
state.items.map(comment => {
if (comment.id === action.commentId) {
comment.isPostUpdate = !comment.isPostUpdate;
return comment;
} else return comment;
})
}

default:
return state;
}
@@ -47,6 +47,11 @@ import {
COMMENT_SUBMIT_FAILURE,
} from '../actions/submitComment';

import {
ToggleIsUpdateSuccessAction,
TOGGLE_COMMENT_IS_UPDATE_SUCCESS,
} from '../actions/updateComment';

import postReducer from './postReducer';
import likesReducer from './likesReducer';
import commentsReducer from './commentsReducer';
@@ -82,7 +87,8 @@ const currentPostReducer = (
LikeActionTypes |
CommentsRequestActionTypes |
HandleCommentRepliesType |
CommentSubmitActionTypes
CommentSubmitActionTypes |
ToggleIsUpdateSuccessAction
): CurrentPostState => {
switch (action.type) {
case POST_REQUEST_START:
@@ -130,6 +136,7 @@ const currentPostReducer = (
case COMMENT_SUBMIT_START:
case COMMENT_SUBMIT_SUCCESS:
case COMMENT_SUBMIT_FAILURE:
case TOGGLE_COMMENT_IS_UPDATE_SUCCESS:
return {
...state,
comments: commentsReducer(state.comments, action),
@@ -58,6 +58,13 @@

vertical-align: middle;
}

.postUpdateBadge {
@extend
.badge,
.badgeLight,
.ml-2;
}
}

.commentBody {
@@ -67,7 +74,7 @@
.commentFooter {
font-size: 14px;

.commentReplyButton {
.commentLink {
color: $astuto-black;

&:hover {
@@ -7,4 +7,5 @@ en:
like:
create: 'Like create error: %{message}'
comment:
create: 'Comment create error: %{message}'
create: 'Comment create error: %{message}'
update: 'Comment update error: %{message}'
@@ -17,7 +17,7 @@
resources :posts, only: [:index, :create, :show, :update] do
resource :likes, only: [:create, :destroy]
resources :likes, only: [:index]
resources :comments, only: [:index, :create]
resources :comments, only: [:index, :create, :update]
end
resources :boards, only: [:show]
resources :post_statuses, only: [:index]
@@ -8,11 +8,13 @@
expect(post: '/posts/1/comments').to route_to(
controller: 'comments', action: 'create', post_id: "1"
)
expect(patch: '/posts/1/comments/1').to route_to(
controller: 'comments', action: 'update', post_id: "1", id: "1"
)

expect(get: '/posts/1/comments/1').not_to be_routable
expect(get: '/posts/1/comments/new').not_to be_routable
expect(get: '/posts/1/comments/1/edit').not_to be_routable
expect(patch: '/posts/1/comments/1').not_to be_routable
expect(delete: '/posts/1/comments/1').not_to be_routable
end
end

0 comments on commit 2c2a0e0

Please sign in to comment.
You can’t perform that action at this time.