summaryrefslogtreecommitdiffstats
path: root/ui/src/components
diff options
context:
space:
mode:
authorDessalines <tyhou13@gmx.com>2019-04-03 13:59:37 -0700
committerDessalines <tyhou13@gmx.com>2019-04-03 13:59:37 -0700
commite690d6c470c6330b31e39448fe9e566a30860b14 (patch)
tree37f7bf5629f1a5fd01442df2bd3a35c705b40f54 /ui/src/components
parentc7864643812645ecfb560154bcb1e758555126de (diff)
Adding post editing.
- Adding post editing. Fixes #23 - Making SQL versions of comment and post fetching. Fixes #21 - Starting to add forum categories. #17
Diffstat (limited to 'ui/src/components')
-rw-r--r--ui/src/components/create-post.tsx127
-rw-r--r--ui/src/components/post-form.tsx162
-rw-r--r--ui/src/components/post-listing.tsx58
-rw-r--r--ui/src/components/post.tsx15
4 files changed, 233 insertions, 129 deletions
diff --git a/ui/src/components/create-post.tsx b/ui/src/components/create-post.tsx
index 6715e9d8..51e99211 100644
--- a/ui/src/components/create-post.tsx
+++ b/ui/src/components/create-post.tsx
@@ -1,47 +1,11 @@
import { Component, linkEvent } from 'inferno';
-import { Subscription } from "rxjs";
-import { retryWhen, delay, take } from 'rxjs/operators';
-import { PostForm, Post, PostResponse, UserOperation, Community, ListCommunitiesResponse } from '../interfaces';
-import { WebSocketService, UserService } from '../services';
-import { msgOp } from '../utils';
-import { MomentTime } from './moment-time';
+import { PostForm } from './post-form';
-interface State {
- postForm: PostForm;
- communities: Array<Community>;
-}
-
-
-export class CreatePost extends Component<any, State> {
-
- private subscription: Subscription;
- private emptyState: State = {
- postForm: {
- name: null,
- auth: null,
- community_id: null
- },
- communities: []
- }
+export class CreatePost extends Component<any, any> {
constructor(props, context) {
super(props, context);
-
- this.state = this.emptyState;
-
- this.subscription = WebSocketService.Instance.subject
- .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
- .subscribe(
- (msg) => this.parseMessage(msg),
- (err) => console.error(err),
- () => console.log('complete')
- );
-
- WebSocketService.Instance.listCommunities();
- }
-
- componentWillUnmount() {
- this.subscription.unsubscribe();
+ this.handlePostCreate = this.handlePostCreate.bind(this);
}
render() {
@@ -49,92 +13,17 @@ export class CreatePost extends Component<any, State> {
<div class="container">
<div class="row">
<div class="col-12 col-lg-6 mb-4">
- {this.postForm()}
+ <h3>Create a Post</h3>
+ <PostForm onCreate={this.handlePostCreate}/>
</div>
</div>
</div>
)
}
- postForm() {
- return (
- <div>
- <form onSubmit={linkEvent(this, this.handlePostSubmit)}>
- <h3>Create a Post</h3>
- <div class="form-group row">
- <label class="col-sm-2 col-form-label">URL</label>
- <div class="col-sm-10">
- <input type="url" class="form-control" value={this.state.postForm.url} onInput={linkEvent(this, this.handlePostUrlChange)} />
- </div>
- </div>
- <div class="form-group row">
- <label class="col-sm-2 col-form-label">Title</label>
- <div class="col-sm-10">
- <textarea value={this.state.postForm.name} onInput={linkEvent(this, this.handlePostNameChange)} class="form-control" required rows={3} />
- </div>
- </div>
- <div class="form-group row">
- <label class="col-sm-2 col-form-label">Body</label>
- <div class="col-sm-10">
- <textarea value={this.state.postForm.body} onInput={linkEvent(this, this.handlePostBodyChange)} class="form-control" rows={6} />
- </div>
- </div>
- <div class="form-group row">
- <label class="col-sm-2 col-form-label">Forum</label>
- <div class="col-sm-10">
- <select class="form-control" value={this.state.postForm.community_id} onInput={linkEvent(this, this.handlePostCommunityChange)}>
- {this.state.communities.map(community =>
- <option value={community.id}>{community.name}</option>
- )}
- </select>
- </div>
- </div>
- <div class="form-group row">
- <div class="col-sm-10">
- <button type="submit" class="btn btn-secondary">Create Post</button>
- </div>
- </div>
- </form>
- </div>
- );
- }
-
- handlePostSubmit(i: CreatePost, event) {
- event.preventDefault();
- WebSocketService.Instance.createPost(i.state.postForm);
- }
-
- handlePostUrlChange(i: CreatePost, event) {
- i.state.postForm.url = event.target.value;
- }
-
- handlePostNameChange(i: CreatePost, event) {
- i.state.postForm.name = event.target.value;
- }
-
- handlePostBodyChange(i: CreatePost, event) {
- i.state.postForm.body = event.target.value;
- }
-
- handlePostCommunityChange(i: CreatePost, event) {
- i.state.postForm.community_id = Number(event.target.value);
+ handlePostCreate(id: number) {
+ this.props.history.push(`/post/${id}`);
}
+}
- parseMessage(msg: any) {
- console.log(msg);
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
- alert(msg.error);
- return;
- } else if (op == UserOperation.ListCommunities) {
- let res: ListCommunitiesResponse = msg;
- this.state.communities = res.communities;
- this.state.postForm.community_id = res.communities[0].id; // TODO set it to the default community
- this.setState(this.state);
- } else if (op == UserOperation.CreatePost) {
- let res: PostResponse = msg;
- this.props.history.push(`/post/${res.post.id}`);
- }
- }
-}
diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx
new file mode 100644
index 00000000..b64ad66d
--- /dev/null
+++ b/ui/src/components/post-form.tsx
@@ -0,0 +1,162 @@
+import { Component, linkEvent } from 'inferno';
+import { Subscription } from "rxjs";
+import { retryWhen, delay, take } from 'rxjs/operators';
+import { PostForm as PostFormI, Post, PostResponse, UserOperation, Community, ListCommunitiesResponse } from '../interfaces';
+import { WebSocketService, UserService } from '../services';
+import { msgOp } from '../utils';
+import { MomentTime } from './moment-time';
+
+interface PostFormProps {
+ post?: Post; // If a post is given, that means this is an edit
+ onCancel?();
+ onCreate?(id: number);
+ onEdit?(post: Post);
+}
+
+interface PostFormState {
+ postForm: PostFormI;
+ communities: Array<Community>;
+}
+
+export class PostForm extends Component<PostFormProps, PostFormState> {
+
+ private subscription: Subscription;
+ private emptyState: PostFormState = {
+ postForm: {
+ name: null,
+ auth: null,
+ community_id: null
+ },
+ communities: []
+ }
+
+ constructor(props, context) {
+ super(props, context);
+
+ this.state = this.emptyState;
+
+ if (this.props.post) {
+ this.state.postForm = {
+ body: this.props.post.body,
+ name: this.props.post.name,
+ community_id: this.props.post.community_id,
+ edit_id: this.props.post.id,
+ url: this.props.post.url,
+ auth: null
+ }
+ }
+
+ this.subscription = WebSocketService.Instance.subject
+ .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
+ .subscribe(
+ (msg) => this.parseMessage(msg),
+ (err) => console.error(err),
+ () => console.log('complete')
+ );
+
+ WebSocketService.Instance.listCommunities();
+ }
+
+ componentWillUnmount() {
+ this.subscription.unsubscribe();
+ }
+
+ render() {
+ return (
+ <div>
+ <form onSubmit={linkEvent(this, this.handlePostSubmit)}>
+ <div class="form-group row">
+ <label class="col-sm-2 col-form-label">URL</label>
+ <div class="col-sm-10">
+ <input type="url" class="form-control" value={this.state.postForm.url} onInput={linkEvent(this, this.handlePostUrlChange)} />
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-sm-2 col-form-label">Title</label>
+ <div class="col-sm-10">
+ <textarea value={this.state.postForm.name} onInput={linkEvent(this, this.handlePostNameChange)} class="form-control" required rows={3} />
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-sm-2 col-form-label">Body</label>
+ <div class="col-sm-10">
+ <textarea value={this.state.postForm.body} onInput={linkEvent(this, this.handlePostBodyChange)} class="form-control" rows={6} />
+ </div>
+ </div>
+ <div class="form-group row">
+ <label class="col-sm-2 col-form-label">Forum</label>
+ <div class="col-sm-10">
+ <select class="form-control" value={this.state.postForm.community_id} onInput={linkEvent(this, this.handlePostCommunityChange)}>
+ {this.state.communities.map(community =>
+ <option value={community.id}>{community.name}</option>
+ )}
+ </select>
+ </div>
+ </div>
+ <div class="form-group row">
+ <div class="col-sm-10">
+ <button type="submit" class="btn btn-secondary">{this.props.post ? 'Edit' : 'Create'} Post</button>
+ </div>
+ </div>
+ </form>
+ </div>
+ );
+ }
+
+ handlePostSubmit(i: PostForm, event) {
+ event.preventDefault();
+ console.log(i.state.postForm);
+ if (i.props.post) {
+ WebSocketService.Instance.editPost(i.state.postForm);
+ } else {
+ WebSocketService.Instance.createPost(i.state.postForm);
+ }
+ }
+
+ handlePostUrlChange(i: PostForm, event) {
+ i.state.postForm.url = event.target.value;
+ i.setState(i.state);
+ }
+
+ handlePostNameChange(i: PostForm, event) {
+ i.state.postForm.name = event.target.value;
+ i.setState(i.state);
+ }
+
+ handlePostBodyChange(i: PostForm, event) {
+ i.state.postForm.body = event.target.value;
+ i.setState(i.state);
+ }
+
+ handlePostCommunityChange(i: PostForm, event) {
+ i.state.postForm.community_id = Number(event.target.value);
+ i.setState(i.state);
+ }
+
+ parseMessage(msg: any) {
+ console.log(msg);
+ let op: UserOperation = msgOp(msg);
+ if (msg.error) {
+ alert(msg.error);
+ return;
+ } else if (op == UserOperation.ListCommunities) {
+ let res: ListCommunitiesResponse = msg;
+ this.state.communities = res.communities;
+ if (this.props.post) {
+ this.state.postForm.community_id = this.props.post.community_id;
+ } else {
+ this.state.postForm.community_id = res.communities[0].id;
+ }
+ this.setState(this.state);
+ } else if (op == UserOperation.CreatePost) {
+ let res: PostResponse = msg;
+ this.props.onCreate(res.post.id);
+ } else if (op == UserOperation.EditPost) {
+ let res: PostResponse = msg;
+ this.props.onEdit(res.post);
+ }
+ }
+
+}
+
+
diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx
index 861f0f15..c6c07d8b 100644
--- a/ui/src/components/post-listing.tsx
+++ b/ui/src/components/post-listing.tsx
@@ -3,15 +3,18 @@ import { Link } from 'inferno-router';
import { Subscription } from "rxjs";
import { retryWhen, delay, take } from 'rxjs/operators';
import { WebSocketService, UserService } from '../services';
-import { Post, CreatePostLikeResponse, CreatePostLikeForm } from '../interfaces';
+import { Post, CreatePostLikeResponse, CreatePostLikeForm, PostForm as PostFormI } from '../interfaces';
import { MomentTime } from './moment-time';
+import { PostForm } from './post-form';
import { mdToHtml } from '../utils';
interface PostListingState {
+ showEdit: boolean;
}
interface PostListingProps {
post: Post;
+ editable?: boolean;
showCommunity?: boolean;
showBody?: boolean;
}
@@ -19,6 +22,7 @@ interface PostListingProps {
export class PostListing extends Component<PostListingProps, PostListingState> {
private emptyState: PostListingState = {
+ showEdit: false
}
constructor(props, context) {
@@ -27,9 +31,21 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this.state = this.emptyState;
this.handlePostLike = this.handlePostLike.bind(this);
this.handlePostDisLike = this.handlePostDisLike.bind(this);
+ this.handleEditPost = this.handleEditPost.bind(this);
}
- render() {
+ render() {
+ return (
+ <div>
+ {!this.state.showEdit
+ ? this.listing()
+ : <PostForm post={this.props.post} onEdit={this.handleEditPost} />
+ }
+ </div>
+ )
+ }
+
+ listing() {
let post = this.props.post;
return (
<div class="listing">
@@ -74,15 +90,25 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<Link to={`/post/${post.id}`}>{post.number_of_comments} Comments</Link>
</li>
</ul>
+ {this.myPost &&
+ <ul class="list-inline mb-1 text-muted small font-weight-bold">
+ <li className="list-inline-item">
+ <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}>edit</span>
+ </li>
+ <li className="list-inline-item">
+ <span class="pointer" onClick={linkEvent(this, this.handleDeleteClick)}>delete</span>
+ </li>
+ </ul>
+ }
{this.props.showBody && this.props.post.body && <div className="md-div" dangerouslySetInnerHTML={mdToHtml(post.body)} />}
</div>
</div>
)
}
- // private get myPost(): boolean {
- // return this.props.node.comment.attributed_to == UserService.Instance.fediUserId;
- // }
+ private get myPost(): boolean {
+ return this.props.editable && UserService.Instance.loggedIn && this.props.post.creator_id == UserService.Instance.user.id;
+ }
handlePostLike(i: PostListing, event) {
@@ -100,5 +126,27 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
};
WebSocketService.Instance.likePost(form);
}
+
+ handleEditClick(i: PostListing, event) {
+ i.state.showEdit = true;
+ i.setState(i.state);
+ }
+
+ handleEditPost(post: Post) {
+ this.state.showEdit = false;
+ this.setState(this.state);
+ }
+
+ handleDeleteClick(i: PostListing, event) {
+ let deleteForm: PostFormI = {
+ body: '',
+ community_id: i.props.post.community_id,
+ name: "deleted",
+ url: '',
+ edit_id: i.props.post.id,
+ auth: null
+ };
+ WebSocketService.Instance.editPost(deleteForm);
+ }
}
diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx
index 914eebb5..68ba9634 100644
--- a/ui/src/components/post.tsx
+++ b/ui/src/components/post.tsx
@@ -1,7 +1,8 @@
import { Component, linkEvent } from 'inferno';
+import { Link } from 'inferno-router';
import { Subscription } from "rxjs";
import { retryWhen, delay, take } from 'rxjs/operators';
-import { UserOperation, Community, Post as PostI, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentLikeForm, CreateCommentLikeResponse, CommentSortType, CreatePostLikeResponse } from '../interfaces';
+import { UserOperation, Community, Post as PostI, GetPostResponse, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentLikeForm, CreateCommentLikeResponse, CommentSortType, CreatePostLikeResponse } from '../interfaces';
import { WebSocketService, UserService } from '../services';
import { msgOp, hotRank,mdToHtml } from '../utils';
import { MomentTime } from './moment-time';
@@ -60,7 +61,7 @@ export class Post extends Component<any, State> {
{this.state.post &&
<div class="row">
<div class="col-12 col-sm-8 col-lg-7 mb-3">
- <PostListing post={this.state.post} showBody showCommunity />
+ <PostListing post={this.state.post} showBody showCommunity editable />
<div className="mb-2" />
<CommentForm postId={this.state.post.id} />
{this.sortRadios()}
@@ -181,7 +182,7 @@ export class Post extends Component<any, State> {
alert(msg.error);
return;
} else if (op == UserOperation.GetPost) {
- let res: PostResponse = msg;
+ let res: GetPostResponse = msg;
this.state.post = res.post;
this.state.comments = res.comments;
this.setState(this.state);
@@ -212,6 +213,10 @@ export class Post extends Component<any, State> {
this.state.post.upvotes = res.post.upvotes;
this.state.post.downvotes = res.post.downvotes;
this.setState(this.state);
+ } else if (op == UserOperation.EditPost) {
+ let res: PostResponse = msg;
+ this.state.post = res.post;
+ this.setState(this.state);
}
}
@@ -281,7 +286,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<div className="details ml-4">
<ul class="list-inline mb-0 text-muted small">
<li className="list-inline-item">
- <a href={node.comment.attributed_to}>{node.comment.attributed_to}</a>
+ <Link to={`/user/${node.comment.creator_id}`}>{node.comment.creator_name}</Link>
</li>
<li className="list-inline-item">
<span>(
@@ -327,7 +332,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
}
private get myComment(): boolean {
- return this.props.node.comment.attributed_to == UserService.Instance.fediUserId;
+ return UserService.Instance.loggedIn && this.props.node.comment.creator_id == UserService.Instance.user.id;
}
handleReplyClick(i: CommentNode, event) {