Add edit and delete actions to posts and comments (#125)

This commit is contained in:
Riccardo Graziosi
2022-06-22 10:17:42 +02:00
committed by GitHub
parent 07ca2a304a
commit bc15140512
52 changed files with 1495 additions and 481 deletions

View File

@@ -4,12 +4,11 @@ import Gravatar from 'react-gravatar';
import I18n from 'i18n-js';
import NewComment from './NewComment';
import Separator from '../common/Separator';
import { MutedText } from '../common/CustomTexts';
import { ReplyFormState } from '../../reducers/replyFormReducer';
import friendlyDate from '../../helpers/datetime';
import CommentEditForm from './CommentEditForm';
import CommentFooter from './CommentFooter';
interface Props {
id: number;
@@ -17,119 +16,147 @@ interface Props {
isPostUpdate: boolean;
userFullName: string;
userEmail: string;
createdAt: string;
updatedAt: string;
replyForm: ReplyFormState;
handleToggleCommentReply(): void;
handleCommentReplyBodyChange(e: React.FormEvent): void;
handleToggleIsCommentUpdate(commentId: number, currentIsPostUpdate: boolean): void;
handleSubmitComment(body: string, parentId: number, isPostUpdate: boolean): void;
handleUpdateComment(commentId: number, body: string, isPostUpdate: boolean, onSuccess: Function): void;
handleDeleteComment(id: number): void;
isLoggedIn: boolean;
isPowerUser: boolean;
currentUserEmail: string;
}
const Comment = ({
id,
body,
isPostUpdate,
userFullName,
userEmail,
updatedAt,
interface State {
editMode: boolean;
}
replyForm,
handleToggleCommentReply,
handleCommentReplyBodyChange,
handleToggleIsCommentUpdate,
handleSubmitComment,
class Comment extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
isLoggedIn,
isPowerUser,
currentUserEmail,
}: Props) => (
<div className="comment">
<div className="commentHeader">
<Gravatar email={userEmail} size={28} className="gravatar" />
<span className="commentAuthor">{userFullName}</span>
{
isPostUpdate ?
<span className="postUpdateBadge">
{I18n.t('post.comments.post_update_badge')}
</span>
:
null
}
</div>
this.state = {
editMode: false,
};
<ReactMarkdown
className="commentBody"
disallowedTypes={['heading', 'image', 'html']}
unwrapDisallowed
>
{body}
</ReactMarkdown>
this.toggleEditMode = this.toggleEditMode.bind(this);
this._handleUpdateComment = this._handleUpdateComment.bind(this);
}
<div className="commentFooter">
<a className="commentReplyButton commentLink" onClick={handleToggleCommentReply}>
toggleEditMode() {
this.setState({editMode: !this.state.editMode});
}
_handleUpdateComment(body: string, isPostUpdate: boolean) {
this.props.handleUpdateComment(
this.props.id,
body,
isPostUpdate,
this.toggleEditMode,
);
}
render() {
const {
id,
body,
isPostUpdate,
userFullName,
userEmail,
createdAt,
updatedAt,
replyForm,
handleToggleCommentReply,
handleCommentReplyBodyChange,
handleSubmitComment,
handleDeleteComment,
isLoggedIn,
isPowerUser,
currentUserEmail,
} = this.props;
return (
<div className="comment">
<div className="commentHeader">
<Gravatar email={userEmail} size={28} className="gravatar" />
<span className="commentAuthor">{userFullName}</span>
{
isPostUpdate ?
<span className="postUpdateBadge">
{I18n.t('post.comments.post_update_badge')}
</span>
:
null
}
</div>
{
this.state.editMode ?
<CommentEditForm
id={id}
initialBody={body}
initialIsPostUpdate={isPostUpdate}
isPowerUser={isPowerUser}
handleUpdateComment={this._handleUpdateComment}
toggleEditMode={this.toggleEditMode}
/>
:
<>
<ReactMarkdown
className="commentBody"
disallowedTypes={['heading', 'image', 'html']}
unwrapDisallowed
>
{body}
</ReactMarkdown>
<CommentFooter
id={id}
createdAt={createdAt}
updatedAt={updatedAt}
replyForm={replyForm}
isPowerUser={isPowerUser}
currentUserEmail={currentUserEmail}
commentAuthorEmail={userEmail}
handleDeleteComment={handleDeleteComment}
handleToggleCommentReply={handleToggleCommentReply}
toggleEditMode={this.toggleEditMode}
/>
</>
}
{
replyForm.isOpen ?
I18n.t('common.buttons.cancel')
:
I18n.t('post.comments.reply_button')
<NewComment
body={replyForm.body}
parentId={id}
postUpdateFlagValue={replyForm.isPostUpdate}
isSubmitting={replyForm.isSubmitting}
error={replyForm.error}
handleChange={handleCommentReplyBodyChange}
handlePostUpdateFlag={() => null}
handleSubmit={handleSubmitComment}
isLoggedIn={isLoggedIn}
isPowerUser={isPowerUser}
userEmail={currentUserEmail}
/>
:
null
}
</a>
{
isPowerUser ?
<>
<Separator />
<a
onClick={() => handleToggleIsCommentUpdate(id, isPostUpdate)}
className="commentLink"
>
{ 'Post update: ' + (isPostUpdate ? 'yes' : 'no') }
</a>
<Separator />
<a href={`/admin/comments/${id}/edit`} className="commentLink" data-turbolinks="false">
{I18n.t('common.buttons.edit')}
</a>
<Separator />
<a
href={`/admin/comments/${id}`}
className="commentLink"
data-method="delete"
data-confirm="Are you sure?"
data-turbolinks="false">
{I18n.t('common.buttons.delete')}
</a>
</>
:
null
}
<Separator />
<MutedText>{friendlyDate(updatedAt)}</MutedText>
</div>
{
replyForm.isOpen ?
<NewComment
body={replyForm.body}
parentId={id}
postUpdateFlagValue={replyForm.isPostUpdate}
isSubmitting={replyForm.isSubmitting}
error={replyForm.error}
handleChange={handleCommentReplyBodyChange}
handlePostUpdateFlag={() => null}
handleSubmit={handleSubmitComment}
isLoggedIn={isLoggedIn}
isPowerUser={isPowerUser}
userEmail={currentUserEmail}
/>
:
null
}
</div>
);
</div>
);
}
}
export default Comment;

View File

@@ -0,0 +1,100 @@
import * as React from 'react';
import I18n from 'i18n-js';
import Button from '../common/Button';
interface Props {
id: number;
initialBody: string;
initialIsPostUpdate: boolean;
isPowerUser: boolean;
handleUpdateComment(body: string, isPostUpdate: boolean): void;
toggleEditMode(): void;
}
interface State {
body: string;
isPostUpdate: boolean;
}
class CommentEditForm extends React.Component<Props, State> {
constructor(props) {
super(props);
this.state = {
body: '',
isPostUpdate: false,
};
this.handleCommentBodyChange = this.handleCommentBodyChange.bind(this);
this.handleCommentIsPostUpdateChange = this.handleCommentIsPostUpdateChange.bind(this);
}
componentDidMount() {
this.setState({
body: this.props.initialBody,
isPostUpdate: this.props.initialIsPostUpdate,
});
}
handleCommentBodyChange(newCommentBody: string) {
this.setState({ body: newCommentBody });
}
handleCommentIsPostUpdateChange(newIsPostUpdate: boolean) {
this.setState({ isPostUpdate: newIsPostUpdate });
}
render() {
const { id, isPowerUser, handleUpdateComment, toggleEditMode } = this.props;
const { body, isPostUpdate } = this.state;
return (
<div className="editCommentForm">
<textarea
value={body}
onChange={e => this.handleCommentBodyChange(e.target.value)}
className="commentForm"
/>
<div>
<div>
{
isPowerUser ?
<>
<input
id={`isPostUpdateFlagComment${id}`}
type="checkbox"
onChange={e => this.handleCommentIsPostUpdateChange(e.target.checked)}
checked={isPostUpdate || false}
/>
&nbsp;
<label htmlFor={`isPostUpdateFlagComment${id}`}>
{I18n.t('post.new_comment.is_post_update')}
</label>
</>
:
null
}
</div>
<div>
<a className="commentLink" onClick={toggleEditMode}>
{ I18n.t('common.buttons.cancel') }
</a>
&nbsp;
<Button
onClick={() => handleUpdateComment(body, isPostUpdate)}
>
{ I18n.t('common.buttons.update') }
</Button>
</div>
</div>
</div>
);
}
}
export default CommentEditForm;

View File

@@ -0,0 +1,78 @@
import * as React from 'react';
import I18n from 'i18n-js';
import Separator from '../common/Separator';
import { MutedText } from '../common/CustomTexts';
import friendlyDate from '../../helpers/datetime';
import { ReplyFormState } from '../../reducers/replyFormReducer';
interface Props {
id: number;
createdAt: string;
updatedAt: string;
replyForm: ReplyFormState;
isPowerUser: boolean;
currentUserEmail: string;
commentAuthorEmail: string;
handleDeleteComment(id: number): void;
handleToggleCommentReply(): void;
toggleEditMode(): void;
}
const CommentFooter = ({
id,
createdAt,
updatedAt,
replyForm,
isPowerUser,
currentUserEmail,
commentAuthorEmail,
handleDeleteComment,
handleToggleCommentReply,
toggleEditMode,
}: Props) => (
<div className="commentFooter">
<a className="commentReplyButton commentLink" onClick={handleToggleCommentReply}>
{
replyForm.isOpen ?
I18n.t('common.buttons.cancel')
:
I18n.t('post.comments.reply_button')
}
</a>
{
isPowerUser || currentUserEmail === commentAuthorEmail ?
<>
<Separator />
<a onClick={toggleEditMode} className="commentLink">
{I18n.t('common.buttons.edit')}
</a>
<Separator />
<a
onClick={() => confirm(I18n.t('common.confirmation')) && handleDeleteComment(id)}
className="commentLink">
{I18n.t('common.buttons.delete')}
</a>
</>
:
null
}
<Separator />
<MutedText>{friendlyDate(createdAt)}</MutedText>
{
createdAt !== updatedAt ?
<>
<Separator />
<MutedText>{ I18n.t('common.edited').toLowerCase() }</MutedText>
</>
:
null
}
</div>
);
export default CommentFooter;

View File

@@ -13,8 +13,10 @@ interface Props {
toggleCommentReply(commentId: number): void;
setCommentReplyBody(commentId: number, body: string): void;
handleToggleIsCommentUpdate(commentId: number, currentIsPostUpdate: boolean): void;
handleSubmitComment(body: string, parentId: number, isPostUpdate: boolean): void;
handleUpdateComment(commentId: number, body: string, isPostUpdate: boolean, onSuccess: Function): void;
handleDeleteComment(id: number): void;
isLoggedIn: boolean;
isPowerUser: boolean;
@@ -29,8 +31,9 @@ const CommentList = ({
toggleCommentReply,
setCommentReplyBody,
handleToggleIsCommentUpdate,
handleSubmitComment,
handleUpdateComment,
handleDeleteComment,
isLoggedIn,
isPowerUser,
@@ -49,8 +52,11 @@ const CommentList = ({
setCommentReplyBody(comment.id, (e.target as HTMLTextAreaElement).value)
)
}
handleToggleIsCommentUpdate={handleToggleIsCommentUpdate}
handleSubmitComment={handleSubmitComment}
handleUpdateComment={handleUpdateComment}
handleDeleteComment={handleDeleteComment}
{...comment}
isLoggedIn={isLoggedIn}
@@ -66,8 +72,10 @@ const CommentList = ({
toggleCommentReply={toggleCommentReply}
setCommentReplyBody={setCommentReplyBody}
handleToggleIsCommentUpdate={handleToggleIsCommentUpdate}
handleSubmitComment={handleSubmitComment}
handleUpdateComment={handleUpdateComment}
handleDeleteComment={handleDeleteComment}
isLoggedIn={isLoggedIn}
isPowerUser={isPowerUser}

View File

@@ -26,12 +26,7 @@ interface Props {
toggleCommentReply(commentId: number): void;
setCommentReplyBody(commentId: number, body: string): void;
toggleCommentIsPostUpdateFlag(): void;
toggleCommentIsPostUpdate(
postId: number,
commentId: number,
currentIsPostUpdate: boolean,
authenticityToken: string,
): void;
submitComment(
postId: number,
body: string,
@@ -39,6 +34,19 @@ interface Props {
isPostUpdate: boolean,
authenticityToken: string,
): void;
updateComment(
postId: number,
commentId: number,
body: string,
isPostUpdate: boolean,
onSuccess: Function,
authenticityToken: string,
): void;
deleteComment(
postId: number,
commentId: number,
authenticityToken: string,
): void;
}
class CommentsP extends React.Component<Props> {
@@ -46,15 +54,6 @@ 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, isPostUpdate: boolean) => {
this.props.submitComment(
this.props.postId,
@@ -65,6 +64,25 @@ class CommentsP extends React.Component<Props> {
);
}
_handleUpdateComment = (commentId: number, body: string, isPostUpdate: boolean, onSuccess: Function) => {
this.props.updateComment(
this.props.postId,
commentId,
body,
isPostUpdate,
onSuccess,
this.props.authenticityToken,
);
}
_handleDeleteComment = (commentId: number) => {
this.props.deleteComment(
this.props.postId,
commentId,
this.props.authenticityToken,
);
}
render() {
const {
isLoggedIn,
@@ -118,8 +136,9 @@ class CommentsP extends React.Component<Props> {
replyForms={replyForms}
toggleCommentReply={toggleCommentReply}
setCommentReplyBody={setCommentReplyBody}
handleToggleIsCommentUpdate={this._handleToggleIsCommentUpdate}
handleSubmitComment={this._handleSubmitComment}
handleUpdateComment={this._handleUpdateComment}
handleDeleteComment={this._handleDeleteComment}
parentId={null}
level={1}
isLoggedIn={isLoggedIn}

View File

@@ -1,6 +1,6 @@
import * as React from 'react';
import I18n from 'i18n-js';
import Gravatar from 'react-gravatar';
import I18n from 'i18n-js';
import NewCommentUpdateSection from './NewCommentUpdateSection';
@@ -52,7 +52,7 @@ const NewComment = ({
value={body}
onChange={handleChange}
placeholder={I18n.t('post.new_comment.body_placeholder')}
className="newCommentBody"
className="commentForm"
/>
<Button
onClick={() => handleSubmit(body, parentId, postUpdateFlagValue)}

View File

@@ -0,0 +1,107 @@
import * as React from 'react';
import I18n from 'i18n-js';
import PostBoardSelect from './PostBoardSelect';
import PostStatusSelect from './PostStatusSelect';
import IPostStatus from '../../interfaces/IPostStatus';
import IBoard from '../../interfaces/IBoard';
import Button from '../common/Button';
import Spinner from '../common/Spinner';
interface Props {
title: string;
description?: string;
boardId: number;
postStatusId?: number;
isUpdating: boolean;
error: string;
handleChangeTitle(title: string): void;
handleChangeDescription(description: string): void;
handleChangeBoard(boardId: number): void;
handleChangePostStatus(postStatusId: number): void;
isPowerUser: boolean;
boards: Array<IBoard>;
postStatuses: Array<IPostStatus>;
toggleEditMode(): void;
handleUpdatePost(
title: string,
description: string,
boardId: number,
postStatusId: number,
): void;
}
const PostEditForm = ({
title,
description,
boardId,
postStatusId,
isUpdating,
error,
handleChangeTitle,
handleChangeDescription,
handleChangeBoard,
handleChangePostStatus,
isPowerUser,
boards,
postStatuses,
toggleEditMode,
handleUpdatePost,
}: Props) => (
<div className="postEditForm">
<div className="postHeader">
<input
type="text"
value={title}
onChange={e => handleChangeTitle(e.target.value)}
className="form-control"
/>
</div>
{
isPowerUser ?
<div className="postSettings">
<PostBoardSelect
boards={boards}
selectedBoardId={boardId}
handleChange={newBoardId => handleChangeBoard(newBoardId)}
/>
<PostStatusSelect
postStatuses={postStatuses}
selectedPostStatusId={postStatusId}
handleChange={newPostStatusId => handleChangePostStatus(newPostStatusId)}
/>
</div>
:
null
}
<textarea
value={description}
onChange={e => handleChangeDescription(e.target.value)}
rows={5}
className="form-control"
/>
<div className="postEditFormButtons">
<a onClick={toggleEditMode}>
{ I18n.t('common.buttons.cancel') }
</a>
&nbsp;
<Button onClick={() => handleUpdatePost(title, description, boardId, postStatusId)}>
{ isUpdating ? <Spinner /> : I18n.t('common.buttons.update') }
</Button>
</div>
</div>
);
export default PostEditForm;

View File

@@ -0,0 +1,53 @@
import * as React from 'react';
import Gravatar from 'react-gravatar';
import I18n from 'i18n-js';
import { MutedText } from '../common/CustomTexts';
import friendlyDate from '../../helpers/datetime';
import Separator from '../common/Separator';
interface Props {
createdAt: string;
toggleEditMode(): void;
handleDeletePost(): void;
isPowerUser: boolean;
authorEmail: string;
authorFullName: string;
currentUserEmail: string;
}
const PostFooter = ({
createdAt,
toggleEditMode,
handleDeletePost,
isPowerUser,
authorEmail,
authorFullName,
currentUserEmail,
}: Props) => (
<div className="postFooter">
<div className="postAuthor">
<span>{ I18n.t('post.published_by').toLowerCase() } &nbsp;</span>
<Gravatar email={authorEmail} size={24} className="postAuthorAvatar" /> &nbsp;
{authorFullName}
</div>
{
isPowerUser || authorEmail === currentUserEmail ?
<>
<a onClick={toggleEditMode}>
{ I18n.t('common.buttons.edit') }
</a>
<Separator />
<a onClick={() => confirm(I18n.t('common.confirmation')) && handleDeletePost()}>
{ I18n.t('common.buttons.delete') }
</a>
<Separator />
</>
:
null
}
<MutedText>{friendlyDate(createdAt)}</MutedText>
</div>
);
export default PostFooter;

View File

@@ -1,32 +1,34 @@
import * as React from 'react';
import ReactMarkdown from 'react-markdown';
import I18n from 'i18n-js';
import IPost from '../../interfaces/IPost';
import IPostStatus from '../../interfaces/IPostStatus';
import IBoard from '../../interfaces/IBoard';
import PostUpdateList from './PostUpdateList';
import PostEditForm from './PostEditForm';
import PostFooter from './PostFooter';
import LikeList from './LikeList';
import ActionBox from './ActionBox';
import LikeButton from '../../containers/LikeButton';
import PostBoardSelect from './PostBoardSelect';
import PostStatusSelect from './PostStatusSelect';
import PostBoardLabel from '../common/PostBoardLabel';
import PostStatusLabel from '../common/PostStatusLabel';
import Comments from '../../containers/Comments';
import { MutedText } from '../common/CustomTexts';
import Sidebar from '../common/Sidebar';
import { LikesState } from '../../reducers/likesReducer';
import { CommentsState } from '../../reducers/commentsReducer';
import { PostStatusChangesState } from '../../reducers/postStatusChangesReducer';
import { PostEditFormState } from '../../reducers/currentPostReducer';
import friendlyDate, { fromRailsStringToJavascriptDate } from '../../helpers/datetime';
import { fromRailsStringToJavascriptDate } from '../../helpers/datetime';
import HttpStatus from '../../constants/http_status';
interface Props {
postId: number;
post: IPost;
editMode: boolean;
editForm: PostEditFormState;
likes: LikesState;
followed: boolean;
comments: CommentsState;
@@ -35,26 +37,38 @@ interface Props {
postStatuses: Array<IPostStatus>;
isLoggedIn: boolean;
isPowerUser: boolean;
userFullName: string;
userEmail: string;
currentUserFullName: string;
currentUserEmail: string;
authenticityToken: string;
requestPost(postId: number): void;
updatePost(
postId: number,
title: string,
description: string,
boardId: number,
postStatusId: number,
authenticityToken: string,
): Promise<any>;
requestLikes(postId: number): void;
requestFollow(postId: number): void;
requestPostStatusChanges(postId: number): void;
changePostBoard(
postId: number,
newBoardId: number,
authenticityToken: string,
): void;
changePostStatus(
postId: number,
toggleEditMode(): void;
handleChangeEditFormTitle(title: string): void;
handleChangeEditFormDescription(description: string): void;
handleChangeEditFormBoard(boardId: number): void;
handleChangeEditFormPostStatus(postStatusId: number): void;
deletePost(postId: number, authenticityToken: string): Promise<any>;
postStatusChangeSubmitted(
newPostStatusId: number,
userFullName: string,
userEmail: string,
authenticityToken: string,
): void;
submitFollow(
postId: number,
isFollow: boolean,
@@ -63,8 +77,15 @@ interface Props {
}
class PostP extends React.Component<Props> {
constructor(props: Props) {
super(props);
this._handleUpdatePost = this._handleUpdatePost.bind(this);
this._handleDeletePost = this._handleDeletePost.bind(this);
}
componentDidMount() {
const {postId} = this.props;
const { postId } = this.props;
this.props.requestPost(postId);
this.props.requestLikes(postId);
@@ -72,9 +93,51 @@ class PostP extends React.Component<Props> {
this.props.requestPostStatusChanges(postId);
}
_handleUpdatePost(title: string, description: string, boardId: number, postStatusId: number) {
const {
postId,
post,
currentUserFullName,
currentUserEmail,
authenticityToken,
updatePost,
postStatusChangeSubmitted,
} = this.props;
const oldPostStatusId = post.postStatusId;
updatePost(
postId,
title,
description,
boardId,
postStatusId,
authenticityToken,
).then(res => {
if (res?.status !== HttpStatus.OK) return;
if (postStatusId === oldPostStatusId) return;
postStatusChangeSubmitted(
postStatusId,
currentUserFullName,
currentUserEmail,
);
});
}
_handleDeletePost() {
this.props.deletePost(
this.props.postId,
this.props.authenticityToken
).then(() => window.location.href = `/boards/${this.props.post.boardId}`);
}
render() {
const {
post,
editMode,
editForm,
likes,
followed,
comments,
@@ -84,13 +147,15 @@ class PostP extends React.Component<Props> {
isLoggedIn,
isPowerUser,
userFullName,
userEmail,
currentUserEmail,
authenticityToken,
changePostBoard,
changePostStatus,
submitFollow,
toggleEditMode,
handleChangeEditFormTitle,
handleChangeEditFormDescription,
handleChangeEditFormBoard,
handleChangeEditFormPostStatus,
} = this.props;
const postUpdates = [
@@ -98,7 +163,7 @@ class PostP extends React.Component<Props> {
...postStatusChanges.items,
].sort(
(a, b) =>
fromRailsStringToJavascriptDate(a.updatedAt) < fromRailsStringToJavascriptDate(b.updatedAt) ? 1 : -1
fromRailsStringToJavascriptDate(a.createdAt) < fromRailsStringToJavascriptDate(b.createdAt) ? 1 : -1
);
return (
@@ -126,71 +191,72 @@ class PostP extends React.Component<Props> {
</Sidebar>
<div className="postAndCommentsContainer">
<>
<div className="postHeader">
<LikeButton
postId={post.id}
likesCount={likes.items.length}
liked={likes.items.find(like => like.email === userEmail) ? 1 : 0}
isLoggedIn={isLoggedIn}
authenticityToken={authenticityToken}
/>
<h2>{post.title}</h2>
{
isPowerUser && post ?
<a href={`/admin/posts/${post.id}`} data-turbolinks="false">
{I18n.t('post.edit_button')}
</a>
:
null
}
</div>
{
isPowerUser && post ?
<div className="postSettings">
<PostBoardSelect
boards={boards}
selectedBoardId={post.boardId}
handleChange={
newBoardId => changePostBoard(post.id, newBoardId, authenticityToken)
}
/>
<PostStatusSelect
postStatuses={postStatuses}
selectedPostStatusId={post.postStatusId}
handleChange={
newPostStatusId =>
changePostStatus(post.id, newPostStatusId, userFullName, userEmail, authenticityToken)
}
/>
</div>
:
<div className="postInfo">
<PostBoardLabel
{...boards.find(board => board.id === post.boardId)}
/>
<PostStatusLabel
{...postStatuses.find(postStatus => postStatus.id === post.postStatusId)}
/>
</div>
}
<ReactMarkdown
className="postDescription"
disallowedTypes={['heading', 'image', 'html']}
unwrapDisallowed
>
{post.description}
</ReactMarkdown>
<MutedText>{friendlyDate(post.createdAt)}</MutedText>
</>
{
editMode ?
<PostEditForm
{...editForm}
handleChangeTitle={handleChangeEditFormTitle}
handleChangeDescription={handleChangeEditFormDescription}
handleChangeBoard={handleChangeEditFormBoard}
handleChangePostStatus={handleChangeEditFormPostStatus}
isPowerUser={isPowerUser}
boards={boards}
postStatuses={postStatuses}
toggleEditMode={toggleEditMode}
handleUpdatePost={this._handleUpdatePost}
/>
:
<>
<div className="postHeader">
<LikeButton
postId={post.id}
likesCount={likes.items.length}
liked={likes.items.find(like => like.email === currentUserEmail) ? 1 : 0}
isLoggedIn={isLoggedIn}
authenticityToken={authenticityToken}
/>
<h3>{post.title}</h3>
</div>
<div className="postInfo">
<PostBoardLabel
{...boards.find(board => board.id === post.boardId)}
/>
<PostStatusLabel
{...postStatuses.find(postStatus => postStatus.id === post.postStatusId)}
/>
</div>
<ReactMarkdown
className="postDescription"
disallowedTypes={['heading', 'image', 'html']}
unwrapDisallowed
>
{post.description}
</ReactMarkdown>
<PostFooter
createdAt={post.createdAt}
handleDeletePost={this._handleDeletePost}
toggleEditMode={toggleEditMode}
isPowerUser={isPowerUser}
authorEmail={post.userEmail}
authorFullName={post.userFullName}
currentUserEmail={currentUserEmail}
/>
</>
}
<Comments
postId={this.props.postId}
isLoggedIn={isLoggedIn}
isPowerUser={isPowerUser}
userEmail={userEmail}
userEmail={currentUserEmail}
authenticityToken={authenticityToken}
/>
</div>

View File

@@ -65,7 +65,7 @@ const PostUpdateList = ({
}
</div>
<MutedText>{friendlyDate(postUpdate.updatedAt)}</MutedText>
<MutedText>{friendlyDate(postUpdate.createdAt)}</MutedText>
</div>
))
}

View File

@@ -17,8 +17,8 @@ interface Props {
postStatuses: Array<IPostStatus>;
isLoggedIn: boolean;
isPowerUser: boolean;
userFullName: string;
userEmail: string;
currentUserFullName: string;
currentUserEmail: string;
authenticityToken: string;
}
@@ -38,8 +38,8 @@ class PostRoot extends React.Component<Props> {
postStatuses,
isLoggedIn,
isPowerUser,
userFullName,
userEmail,
currentUserFullName,
currentUserEmail,
authenticityToken
} = this.props;
@@ -52,8 +52,8 @@ class PostRoot extends React.Component<Props> {
isLoggedIn={isLoggedIn}
isPowerUser={isPowerUser}
userFullName={userFullName}
userEmail={userEmail}
currentUserFullName={currentUserFullName}
currentUserEmail={currentUserEmail}
authenticityToken={authenticityToken}
/>
</Provider>

View File

@@ -87,10 +87,7 @@ class BoardsEditable extends React.Component<Props, State> {
<Separator />
<a
onClick={() => handleDelete(id)}
data-confirm="Are you sure?"
>
<a onClick={() => confirm(I18n.t('common.confirmation')) && handleDelete(id)}>
{I18n.t('common.buttons.delete')}
</a>
</div>

View File

@@ -78,10 +78,7 @@ class PostStatusEditable extends React.Component<Props, State> {
<Separator />
<a
onClick={() => handleDelete(id)}
data-confirm="Are you sure?"
>
<a onClick={() => confirm(I18n.t('common.confirmation')) && handleDelete(id)}>
{I18n.t('common.buttons.delete')}
</a>
</div>

View File

@@ -6,7 +6,7 @@ interface Props {
}
const Box = ({ customClass, children }: Props) => (
<div className={`box ${customClass}`}>
<div className={`box${customClass ? ' ' + customClass : ''}`}>
{children}
</div>
);

View File

@@ -9,7 +9,7 @@ interface Props {
}
const SidebarBox = ({ title, customClass, children }: Props) => (
<div className={`sidebarBox ${customClass}`}>
<div className={`sidebarBox${customClass ? ' ' + customClass : ''}`}>
<BoxTitleText>{title}</BoxTitleText>
{children}
</div>