diff options
-rw-r--r-- | server/migrations/2019-04-03-155205_create_community_view/up.sql | 3 | ||||
-rw-r--r-- | server/src/actions/community_view.rs | 4 | ||||
-rw-r--r-- | ui/src/components/communities.tsx | 80 | ||||
-rw-r--r-- | ui/src/components/create-community.tsx | 2 | ||||
-rw-r--r-- | ui/src/components/navbar.tsx | 2 | ||||
-rw-r--r-- | ui/src/components/sidebar.tsx | 9 | ||||
-rw-r--r-- | ui/src/index.html | 2 | ||||
-rw-r--r-- | ui/src/index.tsx | 2 | ||||
-rw-r--r-- | ui/src/interfaces.ts | 1 |
9 files changed, 98 insertions, 7 deletions
diff --git a/server/migrations/2019-04-03-155205_create_community_view/up.sql b/server/migrations/2019-04-03-155205_create_community_view/up.sql index 74972507..d26a313e 100644 --- a/server/migrations/2019-04-03-155205_create_community_view/up.sql +++ b/server/migrations/2019-04-03-155205_create_community_view/up.sql @@ -3,7 +3,8 @@ select *, (select name from user_ u where c.creator_id = u.id) as creator_name, (select name from category ct where c.category_id = ct.id) as category_name, (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers, -(select count(*) from post p where p.community_id = c.id) as number_of_posts +(select count(*) from post p where p.community_id = c.id) as number_of_posts, +(select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments from community c; create view community_moderator_view as diff --git a/server/src/actions/community_view.rs b/server/src/actions/community_view.rs index 9da6215d..03d822ab 100644 --- a/server/src/actions/community_view.rs +++ b/server/src/actions/community_view.rs @@ -17,6 +17,7 @@ table! { category_name -> Varchar, number_of_subscribers -> BigInt, number_of_posts -> BigInt, + number_of_comments -> BigInt, } } @@ -34,7 +35,8 @@ pub struct CommunityView { pub creator_name: String, pub category_name: String, pub number_of_subscribers: i64, - pub number_of_posts: i64 + pub number_of_posts: i64, + pub number_of_comments: i64 } impl CommunityView { diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx new file mode 100644 index 00000000..411aebe1 --- /dev/null +++ b/ui/src/components/communities.tsx @@ -0,0 +1,80 @@ +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, GetPostResponse, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentLikeForm, CommentSortType, CreatePostLikeResponse, ListCommunitiesResponse } from '../interfaces'; +import { WebSocketService, UserService } from '../services'; +import { msgOp, hotRank,mdToHtml } from '../utils'; + +interface CommunitiesState { + communities: Array<Community>; +} + +export class Communities extends Component<any, CommunitiesState> { + private subscription: Subscription; + private emptyState: CommunitiesState = { + communities: [] + } + + 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(); + } + + render() { + return ( + <div class="container-fluid"> + <div class="table-responsive"> + <table class="table table-sm table-hover" data-sortable> + <thead> + <tr> + <th>Name</th> + <th>Title</th> + <th>Category</th> + <th class="text-right">Subscribers</th> + <th class="text-right">Posts</th> + <th class="text-right">Comments</th> + </tr> + </thead> + <tbody> + {this.state.communities.map(community => + <tr> + <td><Link to={`/community/${community.id}`}>{community.name}</Link></td> + <td>{community.title}</td> + <td>{community.category_name}</td> + <td class="text-right">{community.number_of_subscribers}</td> + <td class="text-right">{community.number_of_posts}</td> + <td class="text-right">{community.number_of_comments}</td> + </tr> + )} + </tbody> + </table> + </div> + </div> + ); + } + + + + 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.communities.sort((a, b) => b.number_of_subscribers - a.number_of_subscribers); + this.setState(this.state); + } + } +} diff --git a/ui/src/components/create-community.tsx b/ui/src/components/create-community.tsx index c5149f0a..e21db8ac 100644 --- a/ui/src/components/create-community.tsx +++ b/ui/src/components/create-community.tsx @@ -64,7 +64,7 @@ export class CreateCommunity extends Component<any, State> { <div class="form-group row"> <label class="col-sm-2 col-form-label">Name</label> <div class="col-sm-10"> - <input type="text" class="form-control" value={this.state.communityForm.name} onInput={linkEvent(this, this.handleCommunityNameChange)} required minLength={3} /> + <input type="text" class="form-control" value={this.state.communityForm.name} onInput={linkEvent(this, this.handleCommunityNameChange)} required minLength={3} pattern="[a-z0-9_]+" title="lowercase, underscores, and no spaces."/> </div> </div> <div class="form-group row"> diff --git a/ui/src/components/navbar.tsx b/ui/src/components/navbar.tsx index 1af592b4..44424994 100644 --- a/ui/src/components/navbar.tsx +++ b/ui/src/components/navbar.tsx @@ -37,7 +37,7 @@ export class Navbar extends Component<any, any> { <a class="nav-link" href={repoUrl}>About</a> </li> <li class="nav-item"> - <a class="nav-link" href={repoUrl}>Forums</a> + <Link class="nav-link" to="/communities">Forums</Link> </li> <li class="nav-item"> <Link class="nav-link" to="/create_post">Create Post</Link> diff --git a/ui/src/components/sidebar.tsx b/ui/src/components/sidebar.tsx index 8a88b870..c8e80de6 100644 --- a/ui/src/components/sidebar.tsx +++ b/ui/src/components/sidebar.tsx @@ -21,10 +21,13 @@ export class Sidebar extends Component<SidebarProps, SidebarState> { return ( <div> <h4>{community.title}</h4> + <ul class="list-inline"> + <li className="list-inline-item badge badge-light">{community.category_name}</li> + <li className="list-inline-item badge badge-light">{community.number_of_subscribers} Subscribers</li> + <li className="list-inline-item badge badge-light">{community.number_of_posts} Posts</li> + <li className="list-inline-item badge badge-light">{community.number_of_comments} Comments</li> + </ul> <div><button type="button" class="btn btn-secondary mb-2">Subscribe</button></div> - <div className="badge badge-light">{community.category_name}</div> - <div>{community.number_of_subscribers} Subscribers</div> - <div>{community.number_of_posts} Posts</div> <hr /> {community.description && <div className="md-div" dangerouslySetInnerHTML={mdToHtml(community.description)} />} </div> diff --git a/ui/src/index.html b/ui/src/index.html index e02660cf..8b6fccf2 100644 --- a/ui/src/index.html +++ b/ui/src/index.html @@ -10,6 +10,8 @@ <link rel="stylesheet" href="https://bootswatch.com/4/darkly/bootstrap.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/balloon-css/0.5.0/balloon.min.css"> <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,400i,700,800" rel="stylesheet"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/sortable/0.8.0/css/sortable-theme-minimal.min.css" /> + <script src="https://cdnjs.cloudflare.com/ajax/libs/sortable/0.8.0/js/sortable.min.js"></script> </head> <body> diff --git a/ui/src/index.tsx b/ui/src/index.tsx index e68fc92a..5e454c4d 100644 --- a/ui/src/index.tsx +++ b/ui/src/index.tsx @@ -8,6 +8,7 @@ import { CreatePost } from './components/create-post'; import { CreateCommunity } from './components/create-community'; import { Post } from './components/post'; import { Community } from './components/community'; +import { Communities } from './components/communities'; import './main.css'; @@ -33,6 +34,7 @@ class Index extends Component<any, any> { <Route path={`/login`} component={Login} /> <Route path={`/create_post`} component={CreatePost} /> <Route path={`/create_community`} component={CreateCommunity} /> + <Route path={`/communities`} component={Communities} /> <Route path={`/post/:id`} component={Post} /> <Route path={`/community/:id`} component={Community} /> </Switch> diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index 5d5ea12a..7edcbd8e 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -19,6 +19,7 @@ export interface Community { category_name: string; number_of_subscribers: number; number_of_posts: number; + number_of_comments: number; published: string; updated?: string; } |