1 import { Component, linkEvent } from 'inferno';
2 import { Subscription } from "rxjs";
3 import { retryWhen, delay, take } from 'rxjs/operators';
4 import { UserOperation, Community as CommunityI, GetCommunityResponse, CommunityResponse, CommunityUser, UserView, SortType, Post, GetPostsForm, ListingType, GetPostsResponse, CreatePostLikeResponse } from '../interfaces';
5 import { WebSocketService } from '../services';
6 import { PostListings } from './post-listings';
7 import { Sidebar } from './sidebar';
8 import { msgOp, routeSortTypeToEnum, fetchLimit, postRefetchSeconds } from '../utils';
9 import { T, i18n } from 'inferno-i18next';
12 community: CommunityI;
14 communityName: string;
15 moderators: Array<CommunityUser>;
16 admins: Array<UserView>;
23 export class Community extends Component<any, State> {
25 private subscription: Subscription;
26 private postFetcher: any;
27 private emptyState: State = {
36 number_of_subscribers: null,
37 number_of_posts: null,
38 number_of_comments: null,
46 communityId: Number(this.props.match.params.id),
47 communityName: this.props.match.params.name,
50 sort: this.getSortTypeFromProps(this.props),
51 page: this.getPageFromProps(this.props),
54 getSortTypeFromProps(props: any): SortType {
55 return (props.match.params.sort) ?
56 routeSortTypeToEnum(props.match.params.sort) :
60 getPageFromProps(props: any): number {
61 return (props.match.params.page) ? Number(props.match.params.page) : 1;
64 constructor(props: any, context: any) {
65 super(props, context);
67 this.state = this.emptyState;
69 this.subscription = WebSocketService.Instance.subject
70 .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
72 (msg) => this.parseMessage(msg),
73 (err) => console.error(err),
74 () => console.log('complete')
77 if (this.state.communityId) {
78 WebSocketService.Instance.getCommunity(this.state.communityId);
79 } else if (this.state.communityName) {
80 WebSocketService.Instance.getCommunityByName(this.state.communityName);
83 this.keepFetchingPosts();
86 componentWillUnmount() {
87 this.subscription.unsubscribe();
88 clearInterval(this.postFetcher);
91 // Necessary for back button for some reason
92 componentWillReceiveProps(nextProps: any) {
93 if (nextProps.history.action == 'POP') {
94 this.state = this.emptyState;
95 this.state.sort = this.getSortTypeFromProps(nextProps);
96 this.state.page = this.getPageFromProps(nextProps);
103 <div class="container">
104 {this.state.loading ?
105 <h5><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h5> :
107 <div class="col-12 col-md-8">
108 <h5>{this.state.community.title}
109 {this.state.community.removed &&
110 <small className="ml-2 text-muted font-italic"><T i18nKey="removed">#</T></small>
112 {this.state.community.nsfw &&
113 <small className="ml-2 text-muted font-italic"><T i18nKey="nsfw">#</T></small>
117 <PostListings posts={this.state.posts} />
120 <div class="col-12 col-md-4">
122 community={this.state.community}
123 moderators={this.state.moderators}
124 admins={this.state.admins}
135 <div className="mb-2">
136 <select value={this.state.sort} onChange={linkEvent(this, this.handleSortChange)} class="custom-select custom-select-sm w-auto">
137 <option disabled><T i18nKey="sort_type">#</T></option>
138 <option value={SortType.Hot}><T i18nKey="hot">#</T></option>
139 <option value={SortType.New}><T i18nKey="new">#</T></option>
140 <option disabled>──────</option>
141 <option value={SortType.TopDay}><T i18nKey="top_day">#</T></option>
142 <option value={SortType.TopWeek}><T i18nKey="week">#</T></option>
143 <option value={SortType.TopMonth}><T i18nKey="month">#</T></option>
144 <option value={SortType.TopYear}><T i18nKey="year">#</T></option>
145 <option value={SortType.TopAll}><T i18nKey="all">#</T></option>
154 {this.state.page > 1 &&
155 <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}><T i18nKey="prev">#</T></button>
157 <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}><T i18nKey="next">#</T></button>
162 nextPage(i: Community) {
167 window.scrollTo(0,0);
170 prevPage(i: Community) {
175 window.scrollTo(0,0);
178 handleSortChange(i: Community, event: any) {
179 i.state.sort = Number(event.target.value);
184 window.scrollTo(0,0);
188 let sortStr = SortType[this.state.sort].toLowerCase();
189 this.props.history.push(`/c/${this.state.community.name}/sort/${sortStr}/page/${this.state.page}`);
192 keepFetchingPosts() {
194 this.postFetcher = setInterval(() => this.fetchPosts(), postRefetchSeconds);
198 let getPostsForm: GetPostsForm = {
199 page: this.state.page,
201 sort: SortType[this.state.sort],
202 type_: ListingType[ListingType.Community],
203 community_id: this.state.community.id,
205 WebSocketService.Instance.getPosts(getPostsForm);
208 parseMessage(msg: any) {
210 let op: UserOperation = msgOp(msg);
212 alert(i18n.t(msg.error));
214 } else if (op == UserOperation.GetCommunity) {
215 let res: GetCommunityResponse = msg;
216 this.state.community = res.community;
217 this.state.moderators = res.moderators;
218 this.state.admins = res.admins;
219 document.title = `/c/${this.state.community.name} - ${WebSocketService.Instance.site.name}`;
220 this.setState(this.state);
222 } else if (op == UserOperation.EditCommunity) {
223 let res: CommunityResponse = msg;
224 this.state.community = res.community;
225 this.setState(this.state);
226 } else if (op == UserOperation.FollowCommunity) {
227 let res: CommunityResponse = msg;
228 this.state.community.subscribed = res.community.subscribed;
229 this.state.community.number_of_subscribers = res.community.number_of_subscribers;
230 this.setState(this.state);
231 } else if (op == UserOperation.GetPosts) {
232 let res: GetPostsResponse = msg;
233 this.state.posts = res.posts;
234 this.state.loading = false;
235 this.setState(this.state);
236 } else if (op == UserOperation.CreatePostLike) {
237 let res: CreatePostLikeResponse = msg;
238 let found = this.state.posts.find(c => c.id == res.post.id);
239 found.my_vote = res.post.my_vote;
240 found.score = res.post.score;
241 found.upvotes = res.post.upvotes;
242 found.downvotes = res.post.downvotes;
243 this.setState(this.state);