diff options
author | Dessalines <tyhou13@gmx.com> | 2019-03-29 23:08:02 -0700 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2019-03-29 23:08:02 -0700 |
commit | 480b627ff516627c308090b43b4219d8070984a7 (patch) | |
tree | fe64ed6e4fc6be14bd2a414668ae8baf896945c4 /ui | |
parent | 743390113a7f2f95209acabbdc6c9aeb92b08008 (diff) |
Adding comment sorting
- Fixes #15
Diffstat (limited to 'ui')
-rw-r--r-- | ui/src/components/post.tsx | 87 | ||||
-rw-r--r-- | ui/src/interfaces.ts | 4 | ||||
-rw-r--r-- | ui/src/main.css | 10 | ||||
-rw-r--r-- | ui/src/services/WebSocketService.ts | 1 | ||||
-rw-r--r-- | ui/src/utils.ts | 15 |
5 files changed, 96 insertions, 21 deletions
diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx index 1cd61ea3..feb815e5 100644 --- a/ui/src/components/post.tsx +++ b/ui/src/components/post.tsx @@ -1,9 +1,9 @@ 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, CommentLikeForm, CreateCommentLikeResponse } from '../interfaces'; +import { UserOperation, Community, Post as PostI, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentLikeForm, CreateCommentLikeResponse, CommentSortType } from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { msgOp } from '../utils'; +import { msgOp, hotRank } from '../utils'; import { MomentTime } from './moment-time'; interface CommentNodeI { @@ -14,6 +14,7 @@ interface CommentNodeI { interface State { post: PostI; comments: Array<Comment>; + commentSort: CommentSortType; } export class Post extends Component<any, State> { @@ -27,7 +28,8 @@ export class Post extends Component<any, State> { id: null, published: null, }, - comments: [] + comments: [], + commentSort: CommentSortType.Hot } constructor(props, context) { @@ -59,6 +61,7 @@ export class Post extends Component<any, State> { <div class="col-12 col-sm-8 col-lg-7 mb-3"> {this.postHeader()} <CommentForm postId={this.state.post.id} /> + {this.sortRadios()} {this.commentsTree()} </div> <div class="col-12 col-sm-4 col-lg-3 mb-3"> @@ -88,6 +91,28 @@ export class Post extends Component<any, State> { ) } + sortRadios() { + return ( + <div class="btn-group btn-group-toggle mb-3"> + <label className={`btn btn-sm btn-secondary ${this.state.commentSort === CommentSortType.Hot && 'active'}`}>Hot + <input type="radio" value={CommentSortType.Hot} + checked={this.state.commentSort === CommentSortType.Hot} + onChange={linkEvent(this, this.handleCommentSortChange)} /> + </label> + <label className={`btn btn-sm btn-secondary ${this.state.commentSort === CommentSortType.Top && 'active'}`}>Top + <input type="radio" value={CommentSortType.Top} + checked={this.state.commentSort === CommentSortType.Top} + onChange={linkEvent(this, this.handleCommentSortChange)} /> + </label> + <label className={`btn btn-sm btn-secondary ${this.state.commentSort === CommentSortType.New && 'active'}`}>New + <input type="radio" value={CommentSortType.New} + checked={this.state.commentSort === CommentSortType.New} + onChange={linkEvent(this, this.handleCommentSortChange)} /> + </label> + </div> + ) + } + newComments() { return ( <div class="sticky-top"> @@ -107,30 +132,52 @@ export class Post extends Component<any, State> { </div> ); } - - // buildCommentsTree(): Array<CommentNodeI> { - buildCommentsTree(): any { - let tree: Array<CommentNodeI> = this.createCommentsTree(this.state.comments); - console.log(tree); // TODO this is redoing every time and it shouldn't - return tree; + + handleCommentSortChange(i: Post, event) { + i.state.commentSort = Number(event.target.value); + i.setState(i.state); } - private createCommentsTree(comments: Array<Comment>): Array<CommentNodeI> { - let hashTable = {}; - for (let comment of comments) { + private buildCommentsTree(): Array<CommentNodeI> { + let map = new Map<number, CommentNodeI>(); + for (let comment of this.state.comments) { let node: CommentNodeI = { - comment: comment + comment: comment, + children: [] }; - hashTable[comment.id] = { ...node, children : [] }; + map.set(comment.id, { ...node }); } let tree: Array<CommentNodeI> = []; - for (let comment of comments) { - if( comment.parent_id ) hashTable[comment.parent_id].children.push(hashTable[comment.id]); - else tree.push(hashTable[comment.id]); + for (let comment of this.state.comments) { + if( comment.parent_id ) { + map.get(comment.parent_id).children.push(map.get(comment.id)); + } + else { + tree.push(map.get(comment.id)); + } } + + this.sortTree(tree); + return tree; } + sortTree(tree: Array<CommentNodeI>) { + + if (this.state.commentSort == CommentSortType.Top) { + tree.sort((a, b) => b.comment.score - a.comment.score); + } else if (this.state.commentSort == CommentSortType.New) { + tree.sort((a, b) => b.comment.published.localeCompare(a.comment.published)); + } else if (this.state.commentSort == CommentSortType.Hot) { + tree.sort((a, b) => hotRank(b.comment) - hotRank(a.comment)); + } + + for (let node of tree) { + this.sortTree(node.children); + } + + } + commentsTree() { let nodes = this.buildCommentsTree(); return ( @@ -280,7 +327,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { } </div> {this.state.showReply && <CommentForm node={node} onReplyCancel={this.handleReplyCancel} />} - {this.props.node.children && <CommentNodes nodes={this.props.node.children}/>} + {this.props.node.children && <CommentNodes nodes={this.props.node.children} />} </div> ) } @@ -389,8 +436,8 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { </div> <div class="row"> <div class="col-sm-12"> - <button type="submit" class="btn btn-secondary mr-2">{this.state.buttonTitle}</button> - {this.props.node && <button type="button" class="btn btn-secondary" onClick={linkEvent(this, this.handleReplyCancel)}>Cancel</button>} + <button type="submit" class="btn btn-sm btn-secondary mr-2">{this.state.buttonTitle}</button> + {this.props.node && <button type="button" class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.handleReplyCancel)}>Cancel</button>} </div> </div> </form> diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index c89a254e..95ea5e09 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -112,4 +112,8 @@ export interface LoginResponse { jwt: string; } +export enum CommentSortType { + Hot, Top, New +} + diff --git a/ui/src/main.css b/ui/src/main.css index d0cb8baf..089a53b8 100644 --- a/ui/src/main.css +++ b/ui/src/main.css @@ -13,3 +13,13 @@ body { .downvote:hover { color: var(--danger); } + +.form-control, .form-control:focus { + background-color: var(--secondary); + color: #fff; +} + +.custom-select { + color: #fff; + background-color: var(--secondary); +} diff --git a/ui/src/services/WebSocketService.ts b/ui/src/services/WebSocketService.ts index b35d97a1..1ea207f4 100644 --- a/ui/src/services/WebSocketService.ts +++ b/ui/src/services/WebSocketService.ts @@ -88,5 +88,6 @@ export class WebSocketService { window.onbeforeunload = (e => { WebSocketService.Instance.subject.unsubscribe(); + WebSocketService.Instance.subject = null; }); diff --git a/ui/src/utils.ts b/ui/src/utils.ts index 02c1afbf..1d490a30 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -1,4 +1,4 @@ -import { UserOperation } from './interfaces'; +import { UserOperation, Comment } from './interfaces'; export let repoUrl = 'https://github.com/dessalines/rust-reddit-fediverse'; export let wsUri = (window.location.protocol=='https:'&&'wss://'||'ws://')+window.location.host + '/service/ws/'; @@ -8,3 +8,16 @@ export function msgOp(msg: any): UserOperation { return UserOperation[opStr]; } +export function hotRank(comment: Comment): number { + // Rank = ScaleFactor * sign(Score) * log(1 + abs(Score)) / (Time + 2)^Gravity + + let date: Date = new Date(comment.published + 'Z'); // Add Z to convert from UTC date + let now: Date = new Date(); + let hoursElapsed: number = (now.getTime() - date.getTime()) / 36e5; + + let rank = (10000 * Math.sign(comment.score) * Math.log10(1 + Math.abs(comment.score))) / Math.pow(hoursElapsed + 2, 1.8); + + // console.log(`Comment: ${comment.content}\nRank: ${rank}\nScore: ${comment.score}\nHours: ${hoursElapsed}`); + + return rank; +} |