diff options
author | Dessalines <tyhou13@gmx.com> | 2019-03-28 12:32:08 -0700 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2019-03-28 12:32:08 -0700 |
commit | 49c61fc31818e92fea00f8cd9d1c048104d8ecbf (patch) | |
tree | 3d23898c675722809f585ee81ae53ed9763fe87b /ui/src | |
parent | 05f0aee3ea88d3982e2efe6230f8c591540e4c92 (diff) |
Adding comment voting
- Extracting out some components.
- Fixing an issue with window refreshing websockets.
Diffstat (limited to 'ui/src')
-rw-r--r-- | ui/src/components/post.tsx | 176 | ||||
-rw-r--r-- | ui/src/interfaces.ts | 18 | ||||
-rw-r--r-- | ui/src/services/WebSocketService.ts | 16 |
3 files changed, 148 insertions, 62 deletions
diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx index 867e1a4a..2a780cf7 100644 --- a/ui/src/components/post.tsx +++ b/ui/src/components/post.tsx @@ -1,7 +1,7 @@ import { Component, linkEvent } from 'inferno'; import { Subscription } from "rxjs"; import { retryWhen, delay, take } from 'rxjs/operators'; -import { UserOperation, Community, Post as PostI, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse } from '../interfaces'; +import { UserOperation, Community, Post as PostI, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentLikeForm, CreateCommentLikeResponse } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { msgOp } from '../utils'; import { MomentTime } from './moment-time'; @@ -9,7 +9,6 @@ import { MomentTime } from './moment-time'; interface CommentNodeI { comment: Comment; children?: Array<CommentNodeI>; - showReply?: boolean; }; interface State { @@ -78,7 +77,7 @@ export class Post extends Component<any, State> { ? <h5> <a href={this.state.post.url}>{this.state.post.name}</a> <small><a className="ml-2 text-muted font-italic" href={this.state.post.url}>{(new URL(this.state.post.url)).hostname}</a></small> - </h5> + </h5> : <h5>{this.state.post.name}</h5>; return ( <div> @@ -141,7 +140,6 @@ export class Post extends Component<any, State> { ); } - parseMessage(msg: any) { console.log(msg); let op: UserOperation = msgOp(msg); @@ -157,6 +155,16 @@ export class Post extends Component<any, State> { let res: CommentResponse = msg; this.state.comments.unshift(res.comment); this.setState(this.state); + } else if (op == UserOperation.CreateCommentLike) { + let res: CreateCommentLikeResponse = msg; + let found: Comment = this.state.comments.find(c => c.id === res.comment.id); + found.score = res.comment.score; + found.upvotes = res.comment.upvotes; + found.downvotes = res.comment.downvotes; + if (res.comment.my_vote !== null) + found.my_vote = res.comment.my_vote; + console.log(res.comment.my_vote); + this.setState(this.state); } } @@ -174,75 +182,128 @@ export class CommentNodes extends Component<CommentNodesProps, CommentNodesState constructor(props, context) { super(props, context); - this.handleReplyClick = this.handleReplyClick.bind(this); - this.handleReplyCancel = this.handleReplyCancel.bind(this); } render() { return ( <div className="comments"> {this.props.nodes.map(node => - <div className={`comment ${node.comment.parent_id && !this.props.noIndent ? 'ml-4' : ''}`}> - <div className="float-left small text-center"> - <div className="pointer upvote">▲</div> - <div>20</div> - <div className="pointer downvote">▼</div> - </div> - <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> - </li> - <li className="list-inline-item"> - <span>( - <span className="text-info">+1300</span> - <span> | </span> - <span className="text-danger">-29</span> - <span>) </span> - </span> - </li> - <li className="list-inline-item"> - <span><MomentTime data={node.comment} /></span> - </li> - </ul> - <p className="mb-0">{node.comment.content}</p> - <ul class="list-inline mb-1 text-muted small font-weight-bold"> - <li className="list-inline-item"> - <span class="pointer" onClick={linkEvent(node, this.handleReplyClick)}>reply</span> - </li> - <li className="list-inline-item"> - <a className="text-muted" href="test">link</a> - </li> - </ul> - </div> - {node.showReply && <CommentForm node={node} onReplyCancel={this.handleReplyCancel} />} - {node.children && <CommentNodes nodes={node.children}/>} - </div> + <CommentNode node={node} noIndent={this.props.noIndent} /> )} </div> ) } +} - handleReplyClick(i: CommentNodeI, event) { - i.showReply = true; - this.setState(this.state); + +interface CommentNodeState { + showReply: boolean; +} + +interface CommentNodeProps { + node: CommentNodeI; + noIndent?: boolean; +} + +export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { + + private emptyState: CommentNodeState = { + showReply: false + } + + constructor(props, context) { + super(props, context); + + this.state = this.emptyState; + this.handleReplyCancel = this.handleReplyCancel.bind(this); + this.handleCommentLike = this.handleCommentLike.bind(this); + this.handleCommentDisLike = this.handleCommentDisLike.bind(this); + } + + render() { + let node = this.props.node; + return ( + <div className={`comment ${node.comment.parent_id && !this.props.noIndent ? 'ml-4' : ''}`}> + <div className="float-left small text-center"> + <div className={`pointer upvote ${node.comment.my_vote == 1 ? 'text-info' : 'text-muted'}`} onClick={linkEvent(node, this.handleCommentLike)}>▲</div> + <div>{node.comment.score}</div> + <div className={`pointer downvote ${node.comment.my_vote == -1 && 'text-danger'}`} onClick={linkEvent(node, this.handleCommentDisLike)}>▼</div> + </div> + <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> + </li> + <li className="list-inline-item"> + <span>( + <span className="text-info">+{node.comment.upvotes}</span> + <span> | </span> + <span className="text-danger">-{node.comment.downvotes}</span> + <span>) </span> + </span> + </li> + <li className="list-inline-item"> + <span><MomentTime data={node.comment} /></span> + </li> + </ul> + <p className="mb-0">{node.comment.content}</p> + <ul class="list-inline mb-1 text-muted small font-weight-bold"> + <li className="list-inline-item"> + <span class="pointer" onClick={linkEvent(this, this.handleReplyClick)}>reply</span> + </li> + <li className="list-inline-item"> + <a className="text-muted" href="test">link</a> + </li> + </ul> + </div> + {this.state.showReply && <CommentForm node={node} onReplyCancel={this.handleReplyCancel} />} + {this.props.node.children && <CommentNodes nodes={this.props.node.children}/>} + </div> + ) + } + + private getScore(): number { + return (this.props.node.comment.upvotes - this.props.node.comment.downvotes) || 0; + } + + handleReplyClick(i: CommentNode, event) { + i.state.showReply = true; + i.setState(i.state); } - handleReplyCancel(i: CommentNodeI): any { - i.showReply = false; + handleReplyCancel(): any { + this.state.showReply = false; this.setState(this.state); } + + handleCommentLike(i: CommentNodeI, event) { + + let form: CommentLikeForm = { + comment_id: i.comment.id, + post_id: i.comment.post_id, + score: (i.comment.my_vote == 1) ? 0 : 1 + }; + WebSocketService.Instance.likeComment(form); + } + + handleCommentDisLike(i: CommentNodeI, event) { + let form: CommentLikeForm = { + comment_id: i.comment.id, + post_id: i.comment.post_id, + score: (i.comment.my_vote == -1) ? 0 : -1 + }; + WebSocketService.Instance.likeComment(form); + } } interface CommentFormProps { postId?: number; node?: CommentNodeI; - onReplyCancel?(node: CommentNodeI); + onReplyCancel?(); } interface CommentFormState { commentForm: CommentFormI; - topReply: boolean; } export class CommentForm extends Component<CommentFormProps, CommentFormState> { @@ -253,8 +314,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { content: null, post_id: null, parent_id: null - }, - topReply: true + } } constructor(props, context) { @@ -262,16 +322,11 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { this.state = this.emptyState; if (this.props.node) { - this.state.topReply = false; this.state.commentForm.post_id = this.props.node.comment.post_id; this.state.commentForm.parent_id = this.props.node.comment.id; } else { this.state.commentForm.post_id = this.props.postId; } - - console.log(this.state); - - this.handleReplyCancel = this.handleReplyCancel.bind(this); } render() { @@ -286,7 +341,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { <div class="row"> <div class="col-sm-12"> <button type="submit" class="btn btn-secondary mr-2">Post</button> - {!this.state.topReply && <button type="button" class="btn btn-secondary" onClick={this.handleReplyCancel}>Cancel</button>} + {this.props.node && <button type="button" class="btn btn-secondary" onClick={linkEvent(this, this.handleReplyCancel)}>Cancel</button>} </div> </div> </form> @@ -299,6 +354,9 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { i.state.commentForm.content = undefined; i.setState(i.state); event.target.reset(); + if (i.props.node) { + i.props.onReplyCancel(); + } } handleCommentContentChange(i: CommentForm, event) { @@ -306,7 +364,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { i.state.commentForm.content = event.target.value; } - handleReplyCancel(event) { - this.props.onReplyCancel(this.props.node); + handleReplyCancel(i: CommentForm, event) { + i.props.onReplyCancel(); } } diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index 14c28438..d499eb0a 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -1,5 +1,5 @@ export enum UserOperation { - Login, Register, CreateCommunity, CreatePost, ListCommunities, GetPost, GetCommunity, CreateComment + Login, Register, CreateCommunity, CreatePost, ListCommunities, GetPost, GetCommunity, CreateComment, CreateCommentLike } export interface User { @@ -63,6 +63,10 @@ export interface Comment { parent_id?: number; published: string; updated?: string; + score: number; + upvotes: number; + downvotes: number; + my_vote?: number; } export interface CommentForm { @@ -77,6 +81,18 @@ export interface CommentResponse { comment: Comment; } +export interface CommentLikeForm { + comment_id: number; + post_id: number; + score: number; + auth?: string; +} + +export interface CreateCommentLikeResponse { + op: string; + comment: Comment; +} + export interface LoginForm { username_or_email: string; password: string; diff --git a/ui/src/services/WebSocketService.ts b/ui/src/services/WebSocketService.ts index beefac85..ed08fa1e 100644 --- a/ui/src/services/WebSocketService.ts +++ b/ui/src/services/WebSocketService.ts @@ -1,5 +1,5 @@ import { wsUri } from '../env'; -import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, CommentForm } from '../interfaces'; +import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, CommentForm, CommentLikeForm } from '../interfaces'; import { webSocket } from 'rxjs/webSocket'; import { Subject } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; @@ -47,7 +47,8 @@ export class WebSocketService { } public getPost(postId: number) { - this.subject.next(this.wsSendWrapper(UserOperation.GetPost, {id: postId})); + let data = {id: postId, auth: UserService.Instance.auth }; + this.subject.next(this.wsSendWrapper(UserOperation.GetPost, data)); } public getCommunity(communityId: number) { @@ -59,6 +60,11 @@ export class WebSocketService { this.subject.next(this.wsSendWrapper(UserOperation.CreateComment, commentForm)); } + public likeComment(form: CommentLikeForm) { + this.setAuth(form); + this.subject.next(this.wsSendWrapper(UserOperation.CreateCommentLike, form)); + } + private wsSendWrapper(op: UserOperation, data: any) { let send = { op: UserOperation[op], data: data }; console.log(send); @@ -72,4 +78,10 @@ export class WebSocketService { throw "Not logged in"; } } + } + +window.onbeforeunload = (e => { + WebSocketService.Instance.subject.unsubscribe(); +}); + |