diff options
author | Dessalines <tyhou13@gmx.com> | 2019-04-03 13:59:37 -0700 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2019-04-03 13:59:37 -0700 |
commit | e690d6c470c6330b31e39448fe9e566a30860b14 (patch) | |
tree | 37f7bf5629f1a5fd01442df2bd3a35c705b40f54 /ui/src/components | |
parent | c7864643812645ecfb560154bcb1e758555126de (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.tsx | 127 | ||||
-rw-r--r-- | ui/src/components/post-form.tsx | 162 | ||||
-rw-r--r-- | ui/src/components/post-listing.tsx | 58 | ||||
-rw-r--r-- | ui/src/components/post.tsx | 15 |
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) { |