diff options
author | Dessalines <tyhou13@gmx.com> | 2019-04-04 15:29:14 -0700 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2019-04-04 15:29:14 -0700 |
commit | ed688f9292f079e04fa5ad22b2505d8a45cb3d46 (patch) | |
tree | f0e99679eab81f0e67d51f5cb43fefc0bb1f3e9f /ui/src/components | |
parent | f3cbe9e6cee4a03d8677414ae29b81a59d31b71c (diff) |
Community editing
- Community editing mostly working. Fixes #26
Diffstat (limited to 'ui/src/components')
-rw-r--r-- | ui/src/components/community-form.tsx | 155 | ||||
-rw-r--r-- | ui/src/components/community.tsx | 8 | ||||
-rw-r--r-- | ui/src/components/create-community.tsx | 131 | ||||
-rw-r--r-- | ui/src/components/post-form.tsx | 1 | ||||
-rw-r--r-- | ui/src/components/post-listing.tsx | 21 | ||||
-rw-r--r-- | ui/src/components/post.tsx | 8 | ||||
-rw-r--r-- | ui/src/components/sidebar.tsx | 58 |
7 files changed, 244 insertions, 138 deletions
diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx new file mode 100644 index 00000000..a8ea7b11 --- /dev/null +++ b/ui/src/components/community-form.tsx @@ -0,0 +1,155 @@ +import { Component, linkEvent } from 'inferno'; +import { Subscription } from "rxjs"; +import { retryWhen, delay, take } from 'rxjs/operators'; +import { CommunityForm as CommunityFormI, UserOperation, Category, ListCategoriesResponse, CommunityResponse } from '../interfaces'; +import { WebSocketService, UserService } from '../services'; +import { msgOp } from '../utils'; + +import { Community } from '../interfaces'; + +interface CommunityFormProps { + community?: Community; // If a community is given, that means this is an edit + onCancel?(); + onCreate?(id: number); + onEdit?(community: Community); +} + +interface CommunityFormState { + communityForm: CommunityFormI; + categories: Array<Category>; +} + +export class CommunityForm extends Component<CommunityFormProps, CommunityFormState> { + private subscription: Subscription; + + private emptyState: CommunityFormState = { + communityForm: { + name: null, + title: null, + category_id: null + }, + categories: [] + } + + constructor(props, context) { + super(props, context); + + this.state = this.emptyState; + + if (this.props.community) { + this.state.communityForm = { + name: this.props.community.name, + title: this.props.community.title, + category_id: this.props.community.category_id, + description: this.props.community.description, + edit_id: this.props.community.id, + auth: null + } + } + + 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.listCategories(); + } + + componentWillUnmount() { + this.subscription.unsubscribe(); + } + + + render() { + return ( + <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}> + <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} pattern="[a-z0-9_]+" title="lowercase, underscores, and no spaces."/> + </div> + </div> + <div class="form-group row"> + <label class="col-sm-2 col-form-label">Title / Headline</label> + <div class="col-sm-10"> + <input type="text" value={this.state.communityForm.title} onInput={linkEvent(this, this.handleCommunityTitleChange)} class="form-control" required minLength={3} /> + </div> + </div> + <div class="form-group row"> + <label class="col-sm-2 col-form-label">Description / Sidebar</label> + <div class="col-sm-10"> + <textarea value={this.state.communityForm.description} onInput={linkEvent(this, this.handleCommunityDescriptionChange)} class="form-control" rows={6} /> + </div> + </div> + <div class="form-group row"> + <label class="col-sm-2 col-form-label">Category</label> + <div class="col-sm-10"> + <select class="form-control" value={this.state.communityForm.category_id} onInput={linkEvent(this, this.handleCommunityCategoryChange)}> + {this.state.categories.map(category => + <option value={category.id}>{category.name}</option> + )} + </select> + </div> + </div> + <div class="form-group row"> + <div class="col-sm-10"> + <button type="submit" class="btn btn-secondary">{this.props.community ? 'Edit' : 'Create'} Community</button> + </div> + </div> + </form> + ); + } + + handleCreateCommunitySubmit(i: CommunityForm, event) { + event.preventDefault(); + if (i.props.community) { + WebSocketService.Instance.editCommunity(i.state.communityForm); + } else { + WebSocketService.Instance.createCommunity(i.state.communityForm); + } + } + + handleCommunityNameChange(i: CommunityForm, event) { + i.state.communityForm.name = event.target.value; + i.setState(i.state); + } + + handleCommunityTitleChange(i: CommunityForm, event) { + i.state.communityForm.title = event.target.value; + i.setState(i.state); + } + + handleCommunityDescriptionChange(i: CommunityForm, event) { + i.state.communityForm.description = event.target.value; + i.setState(i.state); + } + + handleCommunityCategoryChange(i: CommunityForm, event) { + i.state.communityForm.category_id = Number(event.target.value); + i.setState(i.state); + } + + parseMessage(msg: any) { + let op: UserOperation = msgOp(msg); + console.log(msg); + if (msg.error) { + alert(msg.error); + return; + } else if (op == UserOperation.ListCategories){ + let res: ListCategoriesResponse = msg; + this.state.categories = res.categories; + this.state.communityForm.category_id = res.categories[0].id; + this.setState(this.state); + } else if (op == UserOperation.CreateCommunity) { + let res: CommunityResponse = msg; + this.props.onCreate(res.community.id); + } else if (op == UserOperation.EditCommunity) { + let res: CommunityResponse = msg; + this.props.onEdit(res.community); + } + } + +} diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx index 5505e01d..ed2cd98e 100644 --- a/ui/src/components/community.tsx +++ b/ui/src/components/community.tsx @@ -2,7 +2,7 @@ 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, CommunityResponse, Post, GetPostsForm, ListingSortType, ListingType, GetPostsResponse, CreatePostLikeForm, CreatePostLikeResponse, CommunityUser} from '../interfaces'; +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'; @@ -127,7 +127,7 @@ export class Community extends Component<any, State> { alert(msg.error); return; } else if (op == UserOperation.GetCommunity) { - let res: CommunityResponse = msg; + let res: GetCommunityResponse = msg; this.state.community = res.community; this.state.moderators = res.moderators; this.setState(this.state); @@ -143,6 +143,10 @@ export class Community extends Component<any, State> { 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; + this.setState(this.state); } } } diff --git a/ui/src/components/create-community.tsx b/ui/src/components/create-community.tsx index e21db8ac..cd43c8fa 100644 --- a/ui/src/components/create-community.tsx +++ b/ui/src/components/create-community.tsx @@ -1,47 +1,11 @@ import { Component, linkEvent } from 'inferno'; -import { Subscription } from "rxjs"; -import { retryWhen, delay, take } from 'rxjs/operators'; -import { CommunityForm, UserOperation, Category, ListCategoriesResponse } from '../interfaces'; -import { WebSocketService, UserService } from '../services'; -import { msgOp } from '../utils'; +import { CommunityForm } from './community-form'; -import { Community } from '../interfaces'; - -interface State { - communityForm: CommunityForm; - categories: Array<Category>; -} - -export class CreateCommunity extends Component<any, State> { - private subscription: Subscription; - - private emptyState: State = { - communityForm: { - name: null, - title: null, - category_id: null - }, - categories: [] - } +export class CreateCommunity extends Component<any, any> { 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.listCategories(); - } - - componentWillUnmount() { - this.subscription.unsubscribe(); + this.handleCommunityCreate = this.handleCommunityCreate.bind(this); } render() { @@ -49,96 +13,17 @@ export class CreateCommunity extends Component<any, State> { <div class="container"> <div class="row"> <div class="col-12 col-lg-6 mb-4"> - {this.communityForm()} + <h3>Create Forum</h3> + <CommunityForm onCreate={this.handleCommunityCreate}/> </div> </div> </div> ) } - communityForm() { - return ( - <div> - <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}> - <h3>Create Forum</h3> - <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} pattern="[a-z0-9_]+" title="lowercase, underscores, and no spaces."/> - </div> - </div> - <div class="form-group row"> - <label class="col-sm-2 col-form-label">Title / Headline</label> - <div class="col-sm-10"> - <input type="text" value={this.state.communityForm.title} onInput={linkEvent(this, this.handleCommunityTitleChange)} class="form-control" required minLength={3} /> - </div> - </div> - <div class="form-group row"> - <label class="col-sm-2 col-form-label">Description / Sidebar</label> - <div class="col-sm-10"> - <textarea value={this.state.communityForm.description} onInput={linkEvent(this, this.handleCommunityDescriptionChange)} class="form-control" rows={6} /> - </div> - </div> - <div class="form-group row"> - <label class="col-sm-2 col-form-label">Category</label> - <div class="col-sm-10"> - <select class="form-control" value={this.state.communityForm.category_id} onInput={linkEvent(this, this.handleCommunityCategoryChange)}> - {this.state.categories.map(category => - <option value={category.id}>{category.name}</option> - )} - </select> - </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> - ); - } - - handleCreateCommunitySubmit(i: CreateCommunity, event) { - event.preventDefault(); - WebSocketService.Instance.createCommunity(i.state.communityForm); - } - - handleCommunityNameChange(i: CreateCommunity, event) { - i.state.communityForm.name = event.target.value; - i.setState(i.state); - } - - handleCommunityTitleChange(i: CreateCommunity, event) { - i.state.communityForm.title = event.target.value; - i.setState(i.state); - } - - handleCommunityDescriptionChange(i: CreateCommunity, event) { - i.state.communityForm.description = event.target.value; - i.setState(i.state); - } - - handleCommunityCategoryChange(i: CreateCommunity, event) { - i.state.communityForm.category_id = Number(event.target.value); - i.setState(i.state); + handleCommunityCreate(id: number) { + this.props.history.push(`/community/${id}`); } +} - parseMessage(msg: any) { - let op: UserOperation = msgOp(msg); - console.log(msg); - if (msg.error) { - alert(msg.error); - return; - } else if (op == UserOperation.ListCategories){ - let res: ListCategoriesResponse = msg; - this.state.categories = res.categories; - this.state.communityForm.category_id = res.categories[0].id; - this.setState(this.state); - } else if (op == UserOperation.CreateCommunity) { - let community: Community = msg.community; - this.props.history.push(`/community/${community.id}`); - } - } -} diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index b64ad66d..6967bf0d 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -105,7 +105,6 @@ export class PostForm extends Component<PostFormProps, PostFormState> { handlePostSubmit(i: PostForm, event) { event.preventDefault(); - console.log(i.state.postForm); if (i.props.post) { WebSocketService.Instance.editPost(i.state.postForm); } else { diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index c6c07d8b..cdb2fed3 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -34,15 +34,15 @@ export class PostListing extends Component<PostListingProps, PostListingState> { this.handleEditPost = this.handleEditPost.bind(this); } - render() { - return ( - <div> - {!this.state.showEdit - ? this.listing() - : <PostForm post={this.props.post} onEdit={this.handleEditPost} /> - } - </div> - ) + render() { + return ( + <div> + {!this.state.showEdit + ? this.listing() + : <PostForm post={this.props.post} onEdit={this.handleEditPost} /> + } + </div> + ) } listing() { @@ -90,7 +90,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { <Link to={`/post/${post.id}`}>{post.number_of_comments} Comments</Link> </li> </ul> - {this.myPost && + {this.myPost && <ul class="list-inline mb-1 text-muted small font-weight-bold"> <li className="list-inline-item"> <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}>edit</span> @@ -132,6 +132,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { i.setState(i.state); } + // The actual editing is done in the recieve for post handleEditPost(post: Post) { this.state.showEdit = false; this.setState(this.state); diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx index f36ad979..0efa254a 100644 --- a/ui/src/components/post.tsx +++ b/ui/src/components/post.tsx @@ -2,7 +2,7 @@ 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, CommunityUser } from '../interfaces'; +import { UserOperation, Community, Post as PostI, GetPostResponse, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentLikeForm, CommentSortType, CreatePostLikeResponse, CommunityUser, CommunityResponse } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { msgOp, hotRank,mdToHtml } from '../utils'; import { MomentTime } from './moment-time'; @@ -223,6 +223,12 @@ export class Post extends Component<any, PostState> { let res: PostResponse = msg; this.state.post = res.post; this.setState(this.state); + } else if (op == UserOperation.EditCommunity) { + let res: CommunityResponse = msg; + this.state.community = res.community; + this.state.post.community_id = res.community.id; + this.state.post.community_name = res.community.name; + this.setState(this.state); } } diff --git a/ui/src/components/sidebar.tsx b/ui/src/components/sidebar.tsx index e8a2f410..90c35924 100644 --- a/ui/src/components/sidebar.tsx +++ b/ui/src/components/sidebar.tsx @@ -1,7 +1,9 @@ import { Component, linkEvent } from 'inferno'; import { Link } from 'inferno-router'; import { Community, CommunityUser } from '../interfaces'; +import { WebSocketService, UserService } from '../services'; import { mdToHtml } from '../utils'; +import { CommunityForm } from './community-form'; interface SidebarProps { community: Community; @@ -9,20 +11,49 @@ interface SidebarProps { } interface SidebarState { + showEdit: boolean; } export class Sidebar extends Component<SidebarProps, SidebarState> { + private emptyState: SidebarState = { + showEdit: false + } + constructor(props, context) { super(props, context); + this.state = this.emptyState; + this.handleEditCommunity = this.handleEditCommunity.bind(this); } - render() { + return ( + <div> + {!this.state.showEdit + ? this.sidebar() + : <CommunityForm community={this.props.community} onEdit={this.handleEditCommunity} /> + } + </div> + ) + } + + sidebar() { let community = this.props.community; return ( <div> <h4>{community.title}</h4> + {this.amMod && + <ul class="list-inline mb-1 text-muted small font-weight-bold"> + <li className="list-inline-item"> + <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}>edit</span> + </li> + {this.amCreator && + <li className="list-inline-item"> + {/* <span class="pointer" onClick={linkEvent(this, this.handleDeleteClick)}>delete</span> */} + </li> + } + </ul> + } <ul class="list-inline"> <li className="list-inline-item"><Link className="badge badge-light" to="/communities">{community.category_name}</Link></li> <li className="list-inline-item badge badge-light">{community.number_of_subscribers} Subscribers</li> @@ -44,4 +75,29 @@ export class Sidebar extends Component<SidebarProps, SidebarState> { </div> ); } + + handleEditClick(i: Sidebar, event) { + i.state.showEdit = true; + i.setState(i.state); + } + + handleEditCommunity(community: Community) { + this.state.showEdit = false; + this.setState(this.state); + } + + // TODO no deleting communities yet + handleDeleteClick(i: Sidebar, event) { + } + + private get amCreator(): boolean { + return UserService.Instance.loggedIn && this.props.community.creator_id == UserService.Instance.user.id; + } + + private get amMod(): boolean { + console.log(this.props.moderators); + console.log(this.props); + return UserService.Instance.loggedIn && + this.props.moderators.map(m => m.user_id).includes(UserService.Instance.user.id); + } } |