diff options
author | Dessalines <tyhou13@gmx.com> | 2019-04-05 12:14:54 -0700 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2019-04-05 12:14:54 -0700 |
commit | 38fa7969f95f49f20074ad8b982d8d92923071ad (patch) | |
tree | 2de5f93884ff6b315dcdab48a43662b85f1a0d85 /ui/src | |
parent | 2c66d86e2686c09e56d7b65ab679ce929d499478 (diff) |
Adding a front page / fetching subscribed forums.
- Adding subscribed to post view. Fixes #25
Diffstat (limited to 'ui/src')
-rw-r--r-- | ui/src/components/communities.tsx | 4 | ||||
-rw-r--r-- | ui/src/components/community.tsx | 70 | ||||
-rw-r--r-- | ui/src/components/home.tsx | 5 | ||||
-rw-r--r-- | ui/src/components/main.tsx | 85 | ||||
-rw-r--r-- | ui/src/components/post-listing.tsx | 8 | ||||
-rw-r--r-- | ui/src/components/post-listings.tsx | 167 | ||||
-rw-r--r-- | ui/src/index.html | 2 | ||||
-rw-r--r-- | ui/src/interfaces.ts | 7 | ||||
-rw-r--r-- | ui/src/services/WebSocketService.ts | 5 |
9 files changed, 277 insertions, 76 deletions
diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx index e8158a36..c3cde177 100644 --- a/ui/src/components/communities.tsx +++ b/ui/src/components/communities.tsx @@ -42,8 +42,8 @@ export class Communities extends Component<any, CommunitiesState> { <div class="container-fluid"> <h4>Communities</h4> <div class="table-responsive"> - <table id="community_table" class="table table-sm table-hover" data-sortable> - <thead> + <table id="community_table" class="table table-sm table-hover"> + <thead class="pointer"> <tr> <th>Name</th> <th>Title</th> diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx index 726055ba..0d6d353d 100644 --- a/ui/src/components/community.tsx +++ b/ui/src/components/community.tsx @@ -5,15 +5,14 @@ import { retryWhen, delay, take } from 'rxjs/operators'; import { UserOperation, Community as CommunityI, GetCommunityResponse, CommunityResponse, Post, GetPostsForm, ListingSortType, ListingType, GetPostsResponse, CreatePostLikeForm, CreatePostLikeResponse, CommunityUser} from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { MomentTime } from './moment-time'; -import { PostListing } from './post-listing'; +import { PostListings } from './post-listings'; import { Sidebar } from './sidebar'; import { msgOp, mdToHtml } from '../utils'; interface State { community: CommunityI; + communityId: number; moderators: Array<CommunityUser>; - posts: Array<Post>; - sortType: ListingSortType; } export class Community extends Component<any, State> { @@ -34,8 +33,7 @@ export class Community extends Component<any, State> { published: null }, moderators: [], - posts: [], - sortType: ListingSortType.Hot, + communityId: Number(this.props.match.params.id) } constructor(props, context) { @@ -51,16 +49,7 @@ export class Community extends Component<any, State> { () => console.log('complete') ); - let communityId = Number(this.props.match.params.id); - WebSocketService.Instance.getCommunity(communityId); - - let getPostsForm: GetPostsForm = { - community_id: communityId, - limit: 10, - sort: ListingSortType[ListingSortType.Hot], - type_: ListingType[ListingType.Community] - } - WebSocketService.Instance.getPosts(getPostsForm); + WebSocketService.Instance.getCommunity(this.state.communityId); } componentWillUnmount() { @@ -73,12 +62,7 @@ export class Community extends Component<any, State> { <div class="row"> <div class="col-12 col-lg-9"> <h4>/f/{this.state.community.name}</h4> - <div>{this.selects()}</div> - {this.state.posts.length > 0 - ? this.state.posts.map(post => - <PostListing post={post} />) - : <div>no listings</div> - } + <PostListings communityId={this.state.communityId} /> </div> <div class="col-12 col-lg-3"> <Sidebar community={this.state.community} moderators={this.state.moderators} /> @@ -88,37 +72,6 @@ export class Community extends Component<any, State> { ) } - selects() { - return ( - <div className="mb-2"> - <select value={this.state.sortType} onChange={linkEvent(this, this.handleSortChange)} class="custom-select w-auto"> - <option disabled>Sort Type</option> - <option value={ListingSortType.Hot}>Hot</option> - <option value={ListingSortType.New}>New</option> - <option disabled>──────────</option> - <option value={ListingSortType.TopDay}>Top Day</option> - <option value={ListingSortType.TopWeek}>Week</option> - <option value={ListingSortType.TopMonth}>Month</option> - <option value={ListingSortType.TopYear}>Year</option> - <option value={ListingSortType.TopAll}>All</option> - </select> - </div> - ) - - } - - handleSortChange(i: Community, event) { - i.state.sortType = Number(event.target.value); - i.setState(i.state); - - let getPostsForm: GetPostsForm = { - community_id: i.state.community.id, - limit: 10, - sort: ListingSortType[i.state.sortType], - type_: ListingType[ListingType.Community] - } - WebSocketService.Instance.getPosts(getPostsForm); - } parseMessage(msg: any) { console.log(msg); @@ -131,18 +84,6 @@ export class Community extends Component<any, State> { this.state.community = res.community; this.state.moderators = res.moderators; this.setState(this.state); - } else if (op == UserOperation.GetPosts) { - let res: GetPostsResponse = msg; - this.state.posts = res.posts; - this.setState(this.state); - } else if (op == UserOperation.CreatePostLike) { - let res: CreatePostLikeResponse = msg; - let found = this.state.posts.find(c => c.id == res.post.id); - found.my_vote = res.post.my_vote; - found.score = res.post.score; - found.upvotes = res.post.upvotes; - found.downvotes = res.post.downvotes; - this.setState(this.state); } else if (op == UserOperation.EditCommunity) { let res: CommunityResponse = msg; this.state.community = res.community; @@ -156,4 +97,3 @@ export class Community extends Component<any, State> { } } - diff --git a/ui/src/components/home.tsx b/ui/src/components/home.tsx index 07cb94f5..356534f7 100644 --- a/ui/src/components/home.tsx +++ b/ui/src/components/home.tsx @@ -1,13 +1,12 @@ import { Component } from 'inferno'; import { repoUrl } from '../utils'; +import { Main } from './main'; export class Home extends Component<any, any> { render() { return ( - <div class="container"> - hola this is me. - </div> + <Main /> ) } diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx new file mode 100644 index 00000000..b7b0a562 --- /dev/null +++ b/ui/src/components/main.tsx @@ -0,0 +1,85 @@ +import { Component, linkEvent } from 'inferno'; +import { Link } from 'inferno-router'; +import { Subscription } from "rxjs"; +import { retryWhen, delay, take } from 'rxjs/operators'; +import { UserOperation, Community as CommunityI, GetCommunityResponse, CommunityResponse, Post, GetPostsForm, ListingSortType, ListingType, GetPostsResponse, CreatePostLikeForm, CreatePostLikeResponse, CommunityUser, GetFollowedCommunitiesResponse } from '../interfaces'; +import { WebSocketService, UserService } from '../services'; +import { MomentTime } from './moment-time'; +import { PostListings } from './post-listings'; +import { Sidebar } from './sidebar'; +import { msgOp, mdToHtml } from '../utils'; + +interface State { + subscribedCommunities: Array<CommunityUser>; +} + +export class Main extends Component<any, State> { + + private subscription: Subscription; + private emptyState: State = { + subscribedCommunities: [] + } + + 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') + ); + + if (UserService.Instance.loggedIn) { + WebSocketService.Instance.getFollowedCommunities(); + } + } + + componentWillUnmount() { + this.subscription.unsubscribe(); + } + + render() { + return ( + <div class="container"> + <div class="row"> + <div class="col-12 col-lg-9"> + <PostListings /> + </div> + <div class="col-12 col-lg-3"> + <h4>A Landing message</h4> + {UserService.Instance.loggedIn && + <div> + <hr /> + <h4>Subscribed forums</h4> + <ul class="list-unstyled"> + {this.state.subscribedCommunities.map(community => + <li><Link to={`/community/${community.community_id}`}>{community.community_name}</Link></li> + )} + </ul> + </div> + } + </div> + </div> + </div> + ) + } + + + parseMessage(msg: any) { + console.log(msg); + let op: UserOperation = msgOp(msg); + if (msg.error) { + alert(msg.error); + return; + } else if (op == UserOperation.GetFollowedCommunities) { + let res: GetFollowedCommunitiesResponse = msg; + this.state.subscribedCommunities = res.communities; + this.setState(this.state); + } + } +} + diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index 516baad3..c5052efb 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -59,8 +59,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> { </div> <div className="ml-4"> {post.url - ? <h4 className="mb-0"> - <a className="text-white" href={post.url}>{post.name}</a> + ? <div className="mb-0"> + <h4 className="d-inline"><a className="text-white" href={post.url}>{post.name}</a></h4> <small><a className="ml-2 text-muted font-italic" href={post.url}>{(new URL(post.url)).hostname}</a></small> { !this.state.iframeExpanded ? <span class="pointer ml-2 text-muted small" title="Expand here" onClick={linkEvent(this, this.handleIframeExpandClick)}>+</span> @@ -72,7 +72,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { </div> </span> } - </h4> + </div> : <h4 className="mb-0"><Link className="text-white" to={`/post/${post.id}`}>{post.name}</Link></h4> } </div> @@ -80,7 +80,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { <ul class="list-inline mb-0 text-muted small"> <li className="list-inline-item"> <span>by </span> - <a href={post.creator_id.toString()}>{post.creator_name}</a> + <Link to={`/user/${post.creator_id}`}>{post.creator_name}</Link> {this.props.showCommunity && <span> <span> to </span> diff --git a/ui/src/components/post-listings.tsx b/ui/src/components/post-listings.tsx new file mode 100644 index 00000000..fcc41cf5 --- /dev/null +++ b/ui/src/components/post-listings.tsx @@ -0,0 +1,167 @@ +import { Component, linkEvent } from 'inferno'; +import { Link } from 'inferno-router'; +import { Subscription } from "rxjs"; +import { retryWhen, delay, take } from 'rxjs/operators'; +import { UserOperation, Community as CommunityI, GetCommunityResponse, CommunityResponse, Post, GetPostsForm, ListingSortType, ListingType, GetPostsResponse, CreatePostLikeForm, CreatePostLikeResponse, CommunityUser} from '../interfaces'; +import { WebSocketService, UserService } from '../services'; +import { MomentTime } from './moment-time'; +import { PostListing } from './post-listing'; +import { Sidebar } from './sidebar'; +import { msgOp, mdToHtml } from '../utils'; + + +interface PostListingsProps { + communityId?: number; +} + +interface PostListingsState { + community: CommunityI; + moderators: Array<CommunityUser>; + posts: Array<Post>; + sortType: ListingSortType; + type_: ListingType; +} + +export class PostListings extends Component<PostListingsProps, PostListingsState> { + + private subscription: Subscription; + private emptyState: PostListingsState = { + community: { + id: null, + name: null, + title: null, + category_id: null, + category_name: null, + creator_id: null, + creator_name: null, + number_of_subscribers: null, + number_of_posts: null, + number_of_comments: null, + published: null + }, + moderators: [], + posts: [], + sortType: ListingSortType.Hot, + type_: this.props.communityId + ? ListingType.Community + : UserService.Instance.loggedIn + ? ListingType.Subscribed + : ListingType.All + } + + 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') + ); + + let getPostsForm: GetPostsForm = { + type_: ListingType[this.state.type_], + community_id: this.props.communityId, + limit: 10, + sort: ListingSortType[ListingSortType.Hot], + } + WebSocketService.Instance.getPosts(getPostsForm); + } + + componentWillUnmount() { + this.subscription.unsubscribe(); + } + + render() { + return ( + <div> + <div>{this.selects()}</div> + {this.state.posts.length > 0 + ? this.state.posts.map(post => + <PostListing post={post} showCommunity={!this.props.communityId}/>) + : <div>No Listings</div> + } + </div> + ) + } + + selects() { + return ( + <div className="mb-2"> + <select value={this.state.sortType} onChange={linkEvent(this, this.handleSortChange)} class="custom-select w-auto"> + <option disabled>Sort Type</option> + <option value={ListingSortType.Hot}>Hot</option> + <option value={ListingSortType.New}>New</option> + <option disabled>──────────</option> + <option value={ListingSortType.TopDay}>Top Day</option> + <option value={ListingSortType.TopWeek}>Week</option> + <option value={ListingSortType.TopMonth}>Month</option> + <option value={ListingSortType.TopYear}>Year</option> + <option value={ListingSortType.TopAll}>All</option> + </select> + {!this.props.communityId && + UserService.Instance.loggedIn && + <select value={this.state.type_} onChange={linkEvent(this, this.handleTypeChange)} class="ml-2 custom-select w-auto"> + <option disabled>Type</option> + <option value={ListingType.All}>All</option> + <option value={ListingType.Subscribed}>Subscribed</option> + </select> + + } + </div> + ) + + } + + handleSortChange(i: PostListings, event) { + i.state.sortType = Number(event.target.value); + i.setState(i.state); + + let getPostsForm: GetPostsForm = { + community_id: i.state.community.id, + limit: 10, + sort: ListingSortType[i.state.sortType], + type_: ListingType[ListingType.Community] + } + WebSocketService.Instance.getPosts(getPostsForm); + } + + handleTypeChange(i: PostListings, event) { + i.state.type_ = Number(event.target.value); + i.setState(i.state); + + let getPostsForm: GetPostsForm = { + limit: 10, + sort: ListingSortType[i.state.sortType], + type_: ListingType[i.state.type_] + } + WebSocketService.Instance.getPosts(getPostsForm); + } + + parseMessage(msg: any) { + console.log(msg); + let op: UserOperation = msgOp(msg); + if (msg.error) { + alert(msg.error); + return; + } else if (op == UserOperation.GetPosts) { + let res: GetPostsResponse = msg; + this.state.posts = res.posts; + this.setState(this.state); + } else if (op == UserOperation.CreatePostLike) { + let res: CreatePostLikeResponse = msg; + let found = this.state.posts.find(c => c.id == res.post.id); + found.my_vote = res.post.my_vote; + found.score = res.post.score; + found.upvotes = res.post.upvotes; + found.downvotes = res.post.downvotes; + this.setState(this.state); + } + } +} + + diff --git a/ui/src/index.html b/ui/src/index.html index 8b6fccf2..2b79ac1c 100644 --- a/ui/src/index.html +++ b/ui/src/index.html @@ -10,7 +10,7 @@ <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" /> + <!-- <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> diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index f8007cba..6d314c62 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -1,5 +1,5 @@ export enum UserOperation { - Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, EditCommunity, FollowCommunity + Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, EditCommunity, FollowCommunity, GetFollowedCommunities } export interface User { @@ -179,6 +179,11 @@ export interface FollowCommunityForm { auth?: string; } +export interface GetFollowedCommunitiesResponse { + op: string; + communities: Array<CommunityUser>; +} + export interface LoginForm { username_or_email: string; password: string; diff --git a/ui/src/services/WebSocketService.ts b/ui/src/services/WebSocketService.ts index c8cc9557..79f6750a 100644 --- a/ui/src/services/WebSocketService.ts +++ b/ui/src/services/WebSocketService.ts @@ -52,6 +52,11 @@ export class WebSocketService { this.subject.next(this.wsSendWrapper(UserOperation.ListCommunities, data)); } + public getFollowedCommunities() { + let data = {auth: UserService.Instance.auth }; + this.subject.next(this.wsSendWrapper(UserOperation.GetFollowedCommunities, data)); + } + public listCategories() { this.subject.next(this.wsSendWrapper(UserOperation.ListCategories, undefined)); } |