mirror of
https://github.com/astuto/astuto.git
synced 2025-12-16 03:37:56 +01:00
Post follow and updates notifications V1 (#111)
* It is now possible to follow a post in order to receive updates about it * Notifications are now sent when updates are published * Post status changes are now tracked * Update sidebar now shows the post status history * Mark a comment as a post update using the comment form * ... more ...
This commit is contained in:
committed by
GitHub
parent
ce7be1b30c
commit
dad382d2b1
33
app/javascript/components/Post/ActionBox.tsx
Normal file
33
app/javascript/components/Post/ActionBox.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import * as React from 'react';
|
||||
import Button from '../shared/Button';
|
||||
|
||||
import { BoxTitleText, SmallMutedText } from '../shared/CustomTexts';
|
||||
|
||||
interface Props {
|
||||
followed: boolean;
|
||||
submitFollow(): void;
|
||||
|
||||
isLoggedIn: boolean;
|
||||
}
|
||||
|
||||
const ActionBox = ({followed, submitFollow, isLoggedIn}: Props) => (
|
||||
<div className="actionBoxContainer">
|
||||
<div className="actionBoxFollow">
|
||||
<BoxTitleText>Actions</BoxTitleText>
|
||||
<br />
|
||||
<Button onClick={isLoggedIn ? submitFollow : () => location.href = '/users/sign_in'} outline>
|
||||
{ followed ? 'Unfollow post' : 'Follow post' }
|
||||
</Button>
|
||||
<br />
|
||||
<SmallMutedText>
|
||||
{ followed ?
|
||||
'you\'re receiving notifications about new updates on this post'
|
||||
:
|
||||
'you won\'t receive notifications about this post'
|
||||
}
|
||||
</SmallMutedText>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default ActionBox;
|
||||
@@ -4,7 +4,9 @@ import IPost from '../../interfaces/IPost';
|
||||
import IPostStatus from '../../interfaces/IPostStatus';
|
||||
import IBoard from '../../interfaces/IBoard';
|
||||
|
||||
import PostUpdateList from './PostUpdateList';
|
||||
import LikeList from './LikeList';
|
||||
import ActionBox from './ActionBox';
|
||||
import LikeButton from '../../containers/LikeButton';
|
||||
import PostBoardSelect from './PostBoardSelect';
|
||||
import PostStatusSelect from './PostStatusSelect';
|
||||
@@ -13,25 +15,31 @@ import PostStatusLabel from '../shared/PostStatusLabel';
|
||||
import Comments from '../../containers/Comments';
|
||||
import { MutedText } from '../shared/CustomTexts';
|
||||
|
||||
import friendlyDate from '../../helpers/friendlyDate';
|
||||
import { LikesState } from '../../reducers/likesReducer';
|
||||
import { CommentsState } from '../../reducers/commentsReducer';
|
||||
import PostUpdateList from './PostUpdateList';
|
||||
import { PostStatusChangesState } from '../../reducers/postStatusChangesReducer';
|
||||
|
||||
import friendlyDate, { fromRailsStringToJavascriptDate } from '../../helpers/datetime';
|
||||
|
||||
interface Props {
|
||||
postId: number;
|
||||
post: IPost;
|
||||
likes: LikesState;
|
||||
followed: boolean;
|
||||
comments: CommentsState;
|
||||
postStatusChanges: PostStatusChangesState;
|
||||
boards: Array<IBoard>;
|
||||
postStatuses: Array<IPostStatus>;
|
||||
isLoggedIn: boolean;
|
||||
isPowerUser: boolean;
|
||||
userFullName: string;
|
||||
userEmail: string;
|
||||
authenticityToken: string;
|
||||
|
||||
requestPost(postId: number): void;
|
||||
requestLikes(postId: number): void;
|
||||
requestFollow(postId: number): void;
|
||||
requestPostStatusChanges(postId: number): void;
|
||||
changePostBoard(
|
||||
postId: number,
|
||||
newBoardId: number,
|
||||
@@ -40,38 +48,62 @@ interface Props {
|
||||
changePostStatus(
|
||||
postId: number,
|
||||
newPostStatusId: number,
|
||||
userFullName: string,
|
||||
userEmail: string,
|
||||
authenticityToken: string,
|
||||
): void;
|
||||
submitFollow(
|
||||
postId: number,
|
||||
isFollow: boolean,
|
||||
authenticityToken: string,
|
||||
): void;
|
||||
}
|
||||
|
||||
class PostP extends React.Component<Props> {
|
||||
componentDidMount() {
|
||||
this.props.requestPost(this.props.postId);
|
||||
this.props.requestLikes(this.props.postId);
|
||||
const {postId} = this.props;
|
||||
|
||||
this.props.requestPost(postId);
|
||||
this.props.requestLikes(postId);
|
||||
this.props.requestFollow(postId);
|
||||
this.props.requestPostStatusChanges(postId);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
post,
|
||||
likes,
|
||||
followed,
|
||||
comments,
|
||||
postStatusChanges,
|
||||
boards,
|
||||
postStatuses,
|
||||
|
||||
isLoggedIn,
|
||||
isPowerUser,
|
||||
userFullName,
|
||||
userEmail,
|
||||
authenticityToken,
|
||||
|
||||
changePostBoard,
|
||||
changePostStatus,
|
||||
submitFollow,
|
||||
} = this.props;
|
||||
|
||||
const postUpdates = [
|
||||
...comments.items.filter(comment => comment.isPostUpdate === true),
|
||||
...postStatusChanges.items,
|
||||
].sort(
|
||||
(a, b) =>
|
||||
fromRailsStringToJavascriptDate(a.updatedAt) < fromRailsStringToJavascriptDate(b.updatedAt) ? 1 : -1
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="pageContainer">
|
||||
<div className="sidebar">
|
||||
<PostUpdateList
|
||||
postUpdates={comments.items.filter(comment => comment.isPostUpdate === true)}
|
||||
postUpdates={postUpdates}
|
||||
postStatuses={postStatuses}
|
||||
areLoading={comments.areLoading}
|
||||
error={comments.error}
|
||||
/>
|
||||
@@ -81,6 +113,13 @@ class PostP extends React.Component<Props> {
|
||||
areLoading={likes.areLoading}
|
||||
error={likes.error}
|
||||
/>
|
||||
|
||||
<ActionBox
|
||||
followed={followed}
|
||||
submitFollow={() => submitFollow(post.id, !followed, authenticityToken)}
|
||||
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="postAndCommentsContainer">
|
||||
@@ -113,7 +152,8 @@ class PostP extends React.Component<Props> {
|
||||
postStatuses={postStatuses}
|
||||
selectedPostStatusId={post.postStatusId}
|
||||
handleChange={
|
||||
newPostStatusId => changePostStatus(post.id, newPostStatusId, authenticityToken)
|
||||
newPostStatusId =>
|
||||
changePostStatus(post.id, newPostStatusId, userFullName, userEmail, authenticityToken)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -5,17 +5,22 @@ import { BoxTitleText, DangerText, CenteredMutedText, MutedText } from '../share
|
||||
import Spinner from '../shared/Spinner';
|
||||
|
||||
import IComment from '../../interfaces/IComment';
|
||||
import IPostStatusChange from '../../interfaces/IPostStatusChange';
|
||||
import IPostStatus from '../../interfaces/IPostStatus';
|
||||
|
||||
import friendlyDate from '../../helpers/friendlyDate';
|
||||
import friendlyDate from '../../helpers/datetime';
|
||||
import PostStatusLabel from '../shared/PostStatusLabel';
|
||||
|
||||
interface Props {
|
||||
postUpdates: Array<IComment>;
|
||||
postUpdates: Array<IComment | IPostStatusChange>;
|
||||
postStatuses: Array<IPostStatus>
|
||||
areLoading: boolean;
|
||||
error: string;
|
||||
}
|
||||
|
||||
const PostUpdateList = ({
|
||||
postUpdates,
|
||||
postStatuses,
|
||||
areLoading,
|
||||
error,
|
||||
}: Props) => (
|
||||
@@ -33,7 +38,18 @@ const PostUpdateList = ({
|
||||
<span>{postUpdate.userFullName}</span>
|
||||
</div>
|
||||
|
||||
<p className="postUpdateListItemBody">{postUpdate.body}</p>
|
||||
<p className="postUpdateListItemBody">
|
||||
{ 'body' in postUpdate ?
|
||||
postUpdate.body
|
||||
:
|
||||
<React.Fragment>
|
||||
<i>changed status to</i>
|
||||
<PostStatusLabel
|
||||
{...postStatuses.find(postStatus => postStatus.id === postUpdate.postStatusId)}
|
||||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
</p>
|
||||
|
||||
<MutedText>{friendlyDate(postUpdate.updatedAt)}</MutedText>
|
||||
</div>
|
||||
|
||||
@@ -17,6 +17,7 @@ interface Props {
|
||||
postStatuses: Array<IPostStatus>;
|
||||
isLoggedIn: boolean;
|
||||
isPowerUser: boolean;
|
||||
userFullName: string;
|
||||
userEmail: string;
|
||||
authenticityToken: string;
|
||||
}
|
||||
@@ -37,6 +38,7 @@ class PostRoot extends React.Component<Props> {
|
||||
postStatuses,
|
||||
isLoggedIn,
|
||||
isPowerUser,
|
||||
userFullName,
|
||||
userEmail,
|
||||
authenticityToken
|
||||
} = this.props;
|
||||
@@ -50,6 +52,7 @@ class PostRoot extends React.Component<Props> {
|
||||
|
||||
isLoggedIn={isLoggedIn}
|
||||
isPowerUser={isPowerUser}
|
||||
userFullName={userFullName}
|
||||
userEmail={userEmail}
|
||||
authenticityToken={authenticityToken}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user