From 2c2a0e0c82e299bb2c31cb7d53ee967b082cfb4d Mon Sep 17 00:00:00 2001 From: riccardo Date: Wed, 2 Oct 2019 16:43:13 +0200 Subject: [PATCH] Add button to toggle comment is post update --- app/controllers/comments_controller.rb | 24 +++++++++- app/javascript/actions/updateComment.ts | 45 +++++++++++++++++++ .../components/Comments/Comment.tsx | 15 ++++++- .../components/Comments/CommentList.tsx | 4 ++ .../components/Comments/CommentsP.tsx | 16 +++++++ app/javascript/containers/Comments.tsx | 10 +++++ app/javascript/reducers/commentsReducer.ts | 20 ++++++++- app/javascript/reducers/currentPostReducer.ts | 9 +++- .../stylesheets/components/Comments.scss | 9 +++- config/locales/en.yml | 3 +- config/routes.rb | 2 +- spec/routing/comments_routing_spec.rb | 4 +- 12 files changed, 152 insertions(+), 9 deletions(-) create mode 100644 app/javascript/actions/updateComment.ts diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 39423c75..107862e3 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -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 @@ class CommentsController < ApplicationController 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] diff --git a/app/javascript/actions/updateComment.ts b/app/javascript/actions/updateComment.ts new file mode 100644 index 00000000..361a14ed --- /dev/null +++ b/app/javascript/actions/updateComment.ts @@ -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> => 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); + } +} \ No newline at end of file diff --git a/app/javascript/components/Comments/Comment.tsx b/app/javascript/components/Comments/Comment.tsx index fbe74762..b2db5be6 100644 --- a/app/javascript/components/Comments/Comment.tsx +++ b/app/javascript/components/Comments/Comment.tsx @@ -12,6 +12,7 @@ import friendlyDate from '../../helpers/friendlyDate'; interface Props { id: number; body: string; + isPostUpdate: boolean; userFullName: string; userEmail: string; updatedAt: string; @@ -19,6 +20,7 @@ interface Props { replyForm: ReplyFormState; handleToggleCommentReply(): void; handleCommentReplyBodyChange(e: React.FormEvent): void; + handleToggleIsCommentUpdate(commentId: number, currentIsPostUpdate: boolean): void; handleSubmitComment(body: string, parentId: number): void; isLoggedIn: boolean; @@ -29,6 +31,7 @@ interface Props { const Comment = ({ id, body, + isPostUpdate, userFullName, userEmail, updatedAt, @@ -36,6 +39,7 @@ const Comment = ({ replyForm, handleToggleCommentReply, handleCommentReplyBodyChange, + handleToggleIsCommentUpdate, handleSubmitComment, isLoggedIn, @@ -46,17 +50,26 @@ const Comment = ({
{userFullName} + { isPostUpdate ? Post update : null }

{body}

- + { replyForm.isOpen ? 'Cancel' : 'Reply' } { isPowerUser ? + + handleToggleIsCommentUpdate(id, isPostUpdate)} + className="commentLink" + > + { isPostUpdate ? 'No post update' : 'Post update' } + Edit + : null diff --git a/app/javascript/components/Comments/CommentList.tsx b/app/javascript/components/Comments/CommentList.tsx index 443a67ee..79662f82 100644 --- a/app/javascript/components/Comments/CommentList.tsx +++ b/app/javascript/components/Comments/CommentList.tsx @@ -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} diff --git a/app/javascript/components/Comments/CommentsP.tsx b/app/javascript/components/Comments/CommentsP.tsx index e778c1c9..2c12cef4 100644 --- a/app/javascript/components/Comments/CommentsP.tsx +++ b/app/javascript/components/Comments/CommentsP.tsx @@ -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 { 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 { replyForms={replyForms} toggleCommentReply={toggleCommentReply} setCommentReplyBody={setCommentReplyBody} + handleToggleIsCommentUpdate={this._handleToggleIsCommentUpdate} handleSubmitComment={this._handleSubmitComment} parentId={null} level={1} diff --git a/app/javascript/containers/Comments.tsx b/app/javascript/containers/Comments.tsx index 0d352dd0..337324d5 100644 --- a/app/javascript/containers/Comments.tsx +++ b/app/javascript/containers/Comments.tsx @@ -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, diff --git a/app/javascript/reducers/commentsReducer.ts b/app/javascript/reducers/commentsReducer.ts index 8950dd9e..7207341b 100644 --- a/app/javascript/reducers/commentsReducer.ts +++ b/app/javascript/reducers/commentsReducer.ts @@ -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; } diff --git a/app/javascript/reducers/currentPostReducer.ts b/app/javascript/reducers/currentPostReducer.ts index b1d48547..dad84fce 100644 --- a/app/javascript/reducers/currentPostReducer.ts +++ b/app/javascript/reducers/currentPostReducer.ts @@ -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), diff --git a/app/javascript/stylesheets/components/Comments.scss b/app/javascript/stylesheets/components/Comments.scss index 21bed4cf..bafc52d6 100644 --- a/app/javascript/stylesheets/components/Comments.scss +++ b/app/javascript/stylesheets/components/Comments.scss @@ -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 { diff --git a/config/locales/en.yml b/config/locales/en.yml index 19d63e90..f3d5f06e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -7,4 +7,5 @@ en: like: create: 'Like create error: %{message}' comment: - create: 'Comment create error: %{message}' \ No newline at end of file + create: 'Comment create error: %{message}' + update: 'Comment update error: %{message}' \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index b5d991bd..41b60696 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -17,7 +17,7 @@ Rails.application.routes.draw do 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] diff --git a/spec/routing/comments_routing_spec.rb b/spec/routing/comments_routing_spec.rb index 1f89d302..5ca261fc 100644 --- a/spec/routing/comments_routing_spec.rb +++ b/spec/routing/comments_routing_spec.rb @@ -8,11 +8,13 @@ RSpec.describe 'comments routing', :aggregate_failures, type: :routing do 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 \ No newline at end of file