diff options
author | Dessalines <tyhou13@gmx.com> | 2019-03-26 11:00:18 -0700 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2019-03-26 11:00:18 -0700 |
commit | 25dcb8f4f4f80e401d1d3154923e2dcd05664c76 (patch) | |
tree | 85e9644b64e0eb3fa139db18075dbfd73f854a38 /ui | |
parent | e1cb805cfc719d6266ec50e5f1ef3ac1edf74656 (diff) |
Adding a few endpoints.
- Adding CreatePost, CreateComment, CreateCommunity
Diffstat (limited to 'ui')
-rw-r--r-- | ui/src/components/community.tsx | 72 | ||||
-rw-r--r-- | ui/src/components/create-community.tsx | 19 | ||||
-rw-r--r-- | ui/src/components/create-post.tsx | 121 | ||||
-rw-r--r-- | ui/src/components/login.tsx | 5 | ||||
-rw-r--r-- | ui/src/components/navbar.tsx | 1 | ||||
-rw-r--r-- | ui/src/components/post.tsx | 126 | ||||
-rw-r--r-- | ui/src/index.tsx | 10 | ||||
-rw-r--r-- | ui/src/interfaces.ts | 81 | ||||
-rw-r--r-- | ui/src/services/UserService.ts | 8 | ||||
-rw-r--r-- | ui/src/services/WebSocketService.ts | 52 |
10 files changed, 440 insertions, 55 deletions
diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx new file mode 100644 index 00000000..b0322635 --- /dev/null +++ b/ui/src/components/community.tsx @@ -0,0 +1,72 @@ +import { Component, linkEvent } from 'inferno'; +import { Subscription } from "rxjs"; +import { retryWhen, delay, take } from 'rxjs/operators'; +import { UserOperation, Community as CommunityI, CommunityResponse, Post } from '../interfaces'; +import { WebSocketService, UserService } from '../services'; +import { msgOp } from '../utils'; + +interface State { + community: CommunityI; + posts: Array<Post>; +} + +export class Community extends Component<any, State> { + + private subscription: Subscription; + private emptyState: State = { + community: { + id: null, + name: null, + published: null + }, + posts: [] + } + + constructor(props, context) { + super(props, context); + + this.state = this.emptyState; + + console.log(this.props.match.params.id); + + 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 communityId = Number(this.props.match.params.id); + WebSocketService.Instance.getCommunity(communityId); + } + + componentWillUnmount() { + this.subscription.unsubscribe(); + } + + render() { + return ( + <div class="container"> + <div class="row"> + <div class="col-12 col-lg-6 mb-4"> + {this.state.community.name} + </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.GetCommunity) { + let res: CommunityResponse = msg; + this.state.community = res.community; + this.setState(this.state); + } + } +} diff --git a/ui/src/components/create-community.tsx b/ui/src/components/create-community.tsx index 159147b6..0a0edae6 100644 --- a/ui/src/components/create-community.tsx +++ b/ui/src/components/create-community.tsx @@ -11,20 +11,20 @@ interface State { communityForm: CommunityForm; } -let emptyState: State = { - communityForm: { - name: null, - } -} - export class CreateCommunity extends Component<any, State> { private subscription: Subscription; + private emptyState: State = { + communityForm: { + name: null, + } + } + constructor(props, context) { super(props, context); - this.state = emptyState; - + this.state = this.emptyState; + this.subscription = WebSocketService.Instance.subject .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) .subscribe( @@ -89,7 +89,8 @@ export class CreateCommunity extends Component<any, State> { return; } else { if (op == UserOperation.CreateCommunity) { - let community: Community = msg.data; + let community: Community = msg.community; + this.props.history.push(`/community/${community.id}`); } } } diff --git a/ui/src/components/create-post.tsx b/ui/src/components/create-post.tsx index bb6e60e2..9ddf8c97 100644 --- a/ui/src/components/create-post.tsx +++ b/ui/src/components/create-post.tsx @@ -1,56 +1,141 @@ import { Component, linkEvent } from 'inferno'; - -import { LoginForm, PostForm, UserOperation } from '../interfaces'; +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'; interface State { postForm: PostForm; + communities: Array<Community>; } -let emptyState: State = { - postForm: { - name: null, - url: null, - attributed_to: null - } -} export class CreatePost extends Component<any, State> { + private subscription: Subscription; + private emptyState: State = { + postForm: { + name: null, + auth: null, + community_id: null + }, + communities: [] + } + constructor(props, context) { super(props, context); - this.state = emptyState; + this.state = this.emptyState; - WebSocketService.Instance.subject.subscribe( - (msg) => this.parseMessage(msg), - (err) => console.error(err), - () => console.log('complete') - ); + 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 class="container"> <div class="row"> <div class="col-12 col-lg-6 mb-4"> - create post - {/* {this.postForm()} */} + {this.postForm()} </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; + i.setState(i.state); + } + + handlePostNameChange(i: CreatePost, event) { + i.state.postForm.name = event.target.value; + i.setState(i.state); + } + + handlePostBodyChange(i: CreatePost, event) { + i.state.postForm.body = event.target.value; + i.setState(i.state); + } + + handlePostCommunityChange(i: CreatePost, 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 { + } else if (op == UserOperation.ListCommunities) { + let res: ListCommunitiesResponse = msg; + this.state.communities = res.communities; + 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/login.tsx b/ui/src/components/login.tsx index 60ee9e01..cad4593e 100644 --- a/ui/src/components/login.tsx +++ b/ui/src/components/login.tsx @@ -1,7 +1,7 @@ import { Component, linkEvent } from 'inferno'; import { Subscription } from "rxjs"; import { retryWhen, delay, take } from 'rxjs/operators'; -import { LoginForm, RegisterForm, UserOperation } from '../interfaces'; +import { LoginForm, RegisterForm, LoginResponse, UserOperation } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { msgOp } from '../utils'; @@ -169,7 +169,8 @@ export class Login extends Component<any, State> { return; } else { if (op == UserOperation.Register || op == UserOperation.Login) { - UserService.Instance.login(msg.jwt); + let res: LoginResponse = msg; + UserService.Instance.login(msg); this.props.history.push('/'); } } diff --git a/ui/src/components/navbar.tsx b/ui/src/components/navbar.tsx index 4cf6d6d2..ae2d90b3 100644 --- a/ui/src/components/navbar.tsx +++ b/ui/src/components/navbar.tsx @@ -58,5 +58,6 @@ export class Navbar extends Component<any, any> { handleLogoutClick(i: Navbar, event) { UserService.Instance.logout(); + // i.props.history.push('/'); } } diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx new file mode 100644 index 00000000..8d84f27a --- /dev/null +++ b/ui/src/components/post.tsx @@ -0,0 +1,126 @@ +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 } from '../interfaces'; +import { WebSocketService, UserService } from '../services'; +import { msgOp } from '../utils'; + +interface State { + post: PostI; + commentForm: CommentForm; + comments: Array<Comment>; +} + +export class Post extends Component<any, State> { + + private subscription: Subscription; + private emptyState: State = { + post: { + name: null, + attributed_to: null, + community_id: null, + id: null, + published: null, + }, + commentForm: { + auth: null, + content: null, + post_id: null + }, + comments: [] + } + + constructor(props, context) { + super(props, context); + + let postId = Number(this.props.match.params.id); + + this.state = this.emptyState; + this.state.commentForm.post_id = postId; + + 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.getPost(postId); + } + + componentWillUnmount() { + this.subscription.unsubscribe(); + } + + render() { + return ( + <div class="container"> + <div class="row"> + <div class="col-12 col-lg-6 mb-4"> + {this.state.post.name} + {this.commentForm()} + {this.comments()} + </div> + </div> + </div> + ) + } + + comments() { + return ( + <div> + <h3>Comments</h3> + {this.state.comments.map(comment => + <div>{comment.content}</div> + )} + </div> + ) + } + + + commentForm() { + return ( + <div> + <form onSubmit={linkEvent(this, this.handleCreateCommentSubmit)}> + <h3>Create Comment</h3> + <div class="form-group row"> + <label class="col-sm-2 col-form-label">Name</label> + <div class="col-sm-10"> + <textarea class="form-control" value={this.state.commentForm.content} onInput={linkEvent(this, this.handleCommentContentChange)} required minLength={3} /> + </div> + </div> + <div class="form-group row"> + <div class="col-sm-10"> + <button type="submit" class="btn btn-secondary">Create</button> + </div> + </div> + </form> + </div> + ); + } + + handleCreateCommentSubmit(i: Post, event) { + event.preventDefault(); + WebSocketService.Instance.createComment(i.state.commentForm); + } + + handleCommentContentChange(i: Post, event) { + i.state.commentForm.content = 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.GetPost) { + let res: PostResponse = msg; + this.state.post = res.post; + this.state.comments = res.comments; + this.setState(this.state); + } + } +} diff --git a/ui/src/index.tsx b/ui/src/index.tsx index 1eb3a7d5..e68fc92a 100644 --- a/ui/src/index.tsx +++ b/ui/src/index.tsx @@ -6,6 +6,8 @@ import { Home } from './components/home'; import { Login } from './components/login'; import { CreatePost } from './components/create-post'; import { CreateCommunity } from './components/create-community'; +import { Post } from './components/post'; +import { Community } from './components/community'; import './main.css'; @@ -31,12 +33,8 @@ 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={`/search/:type_/:q/:page`} component={Search} /> - <Route path={`/submit`} component={Submit} /> - <Route path={`/user/:id`} component={Login} /> - <Route path={`/community/:id`} component={Login} /> - */} + <Route path={`/post/:id`} component={Post} /> + <Route path={`/community/:id`} component={Community} /> </Switch> </div> </HashRouter> diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index e620aa4e..14c28438 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -1,5 +1,5 @@ export enum UserOperation { - Login, Register, CreateCommunity + Login, Register, CreateCommunity, CreatePost, ListCommunities, GetPost, GetCommunity, CreateComment } export interface User { @@ -10,8 +10,71 @@ export interface User { export interface Community { id: number; name: string; - published: Date; - updated?: Date; + published: string; + updated?: string; +} + +export interface CommunityForm { + name: string; + auth?: string; +} + +export interface CommunityResponse { + op: string; + community: Community; +} + +export interface ListCommunitiesResponse { + op: string; + communities: Array<Community>; +} + +export interface Post { + id: number; + name: string; + url?: string; + body?: string; + attributed_to: string; + community_id: number; + published: string; + updated?: string; +} + +export interface PostForm { + name: string; + url?: string; + body?: string; + community_id: number; + updated?: number; + auth: string; +} + +export interface PostResponse { + op: string; + post: Post; + comments: Array<Comment>; +} + +export interface Comment { + id: number; + content: string; + attributed_to: string; + post_id: number, + parent_id?: number; + published: string; + updated?: string; +} + +export interface CommentForm { + content: string; + post_id: number; + parent_id?: number; + auth: string; +} + +export interface CommentResponse { + op: string; + comment: Comment; } export interface LoginForm { @@ -26,13 +89,9 @@ export interface RegisterForm { password_verify: string; } -export interface CommunityForm { - name: string; +export interface LoginResponse { + op: string; + jwt: string; } -export interface PostForm { - name: string; - url: string; - attributed_to: string; - updated?: number -} + diff --git a/ui/src/services/UserService.ts b/ui/src/services/UserService.ts index d90fbde5..42411f88 100644 --- a/ui/src/services/UserService.ts +++ b/ui/src/services/UserService.ts @@ -1,5 +1,5 @@ import * as Cookies from 'js-cookie'; -import { User } from '../interfaces'; +import { User, LoginResponse } from '../interfaces'; import * as jwt_decode from 'jwt-decode'; import { Subject } from 'rxjs'; @@ -18,9 +18,9 @@ export class UserService { } - public login(jwt: string) { - this.setUser(jwt); - Cookies.set("jwt", jwt); + public login(res: LoginResponse) { + this.setUser(res.jwt); + Cookies.set("jwt", res.jwt); console.log("jwt cookie set"); } diff --git a/ui/src/services/WebSocketService.ts b/ui/src/services/WebSocketService.ts index 1882b125..cd67e2f9 100644 --- a/ui/src/services/WebSocketService.ts +++ b/ui/src/services/WebSocketService.ts @@ -1,15 +1,22 @@ import { wsUri } from '../env'; -import { LoginForm, RegisterForm, UserOperation, CommunityForm } from '../interfaces'; +import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, CommentForm } from '../interfaces'; import { webSocket } from 'rxjs/webSocket'; import { Subject } from 'rxjs'; +import { retryWhen, delay, take } from 'rxjs/operators'; import { UserService } from './'; export class WebSocketService { private static _instance: WebSocketService; - public subject: Subject<{}>; + public subject: Subject<any>; private constructor() { this.subject = webSocket(wsUri); + + // Even tho this isn't used, its necessary to not keep reconnecting + this.subject + .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) + .subscribe(); + console.log(`Connected to ${wsUri}`); } @@ -26,12 +33,47 @@ export class WebSocketService { } public createCommunity(communityForm: CommunityForm) { - this.subject.next(this.wsSendWrapper(UserOperation.CreateCommunity, communityForm, UserService.Instance.auth)); + this.setAuth(communityForm); + this.subject.next(this.wsSendWrapper(UserOperation.CreateCommunity, communityForm)); + } + + public listCommunities() { + this.subject.next(this.wsSendWrapper(UserOperation.ListCommunities, undefined)); + } + + public createPost(postForm: PostForm) { + this.setAuth(postForm); + this.subject.next(this.wsSendWrapper(UserOperation.CreatePost, postForm)); + } + + public getPost(postId: number) { + this.subject.next(this.wsSendWrapper(UserOperation.GetPost, {id: postId})); } - private wsSendWrapper(op: UserOperation, data: any, auth?: string) { - let send = { op: UserOperation[op], data: data, auth: auth }; + public getCommunity(communityId: number) { + this.subject.next(this.wsSendWrapper(UserOperation.GetCommunity, {id: communityId})); + } + + public createComment(commentForm: CommentForm) { + this.setAuth(commentForm); + this.subject.next(this.wsSendWrapper(UserOperation.CreateComment, commentForm)); + } + + public getComments(postId: number) { + this.subject.next(this.wsSendWrapper(UserOperation.GetComments, {post_id: postId})); + } + + private wsSendWrapper(op: UserOperation, data: any) { + let send = { op: UserOperation[op], data: data }; console.log(send); return send; } + + private setAuth(obj: any) { + obj.auth = UserService.Instance.auth; + if (obj.auth == null) { + alert("Not logged in."); + throw "Not logged in"; + } + } } |