]> Untitled Git - lemmy.git/blob - ui/src/components/post-listings.tsx
Saving replies, the actual fixes will be in the merge to dev.
[lemmy.git] / ui / src / components / post-listings.tsx
1 import { Component, linkEvent } from 'inferno';
2 import { Link } from 'inferno-router';
3 import { Subscription } from "rxjs";
4 import { retryWhen, delay, take } from 'rxjs/operators';
5 import { UserOperation, Post, GetPostsForm, SortType, ListingType, GetPostsResponse, CreatePostLikeResponse, CommunityUser} from '../interfaces';
6 import { WebSocketService, UserService } from '../services';
7 import { PostListing } from './post-listing';
8 import { msgOp, fetchLimit } from '../utils';
9
10 interface PostListingsProps {
11   communityId?: number;
12 }
13
14 interface PostListingsState {
15   moderators: Array<CommunityUser>;
16   posts: Array<Post>;
17   sortType: SortType;
18   type_: ListingType;
19   page: number;
20   loading: boolean;
21 }
22
23 export class PostListings extends Component<PostListingsProps, PostListingsState> {
24
25   private subscription: Subscription;
26   private emptyState: PostListingsState = {
27     moderators: [],
28     posts: [],
29     sortType: SortType.Hot,
30     type_: this.props.communityId 
31     ? ListingType.Community 
32     : UserService.Instance.user
33     ? ListingType.Subscribed 
34     : ListingType.All,
35     page: 1,
36     loading: true
37   }
38
39   constructor(props: any, context: any) {
40     super(props, context);
41
42
43     this.state = this.emptyState;
44
45     this.subscription = WebSocketService.Instance.subject
46       .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
47       .subscribe(
48         (msg) => this.parseMessage(msg),
49         (err) => console.error(err),
50         () => console.log('complete')
51       );
52
53       this.refetch();
54   }
55
56   componentWillUnmount() {
57     this.subscription.unsubscribe();
58   }
59
60   render() {
61     return (
62       <div>
63         {this.state.loading ? 
64         <h5><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h5> : 
65         <div>
66           {this.selects()}
67           {this.state.posts.length > 0 
68             ? this.state.posts.map(post => 
69               <PostListing post={post} showCommunity={!this.props.communityId}/>) 
70                 : <div>No Listings. {!this.props.communityId && <span>Subscribe to some <Link to="/communities">forums</Link>.</span>}</div>
71           }
72           {this.paginator()}
73         </div>
74         }
75       </div>
76     )
77   }
78
79   selects() {
80     return (
81       <div className="mb-2">
82         <select value={this.state.sortType} onChange={linkEvent(this, this.handleSortChange)} class="custom-select w-auto">
83           <option disabled>Sort Type</option>
84           <option value={SortType.Hot}>Hot</option>
85           <option value={SortType.New}>New</option>
86           <option disabled>──────────</option>
87           <option value={SortType.TopDay}>Top Day</option>
88           <option value={SortType.TopWeek}>Week</option>
89           <option value={SortType.TopMonth}>Month</option>
90           <option value={SortType.TopYear}>Year</option>
91           <option value={SortType.TopAll}>All</option>
92         </select>
93         {!this.props.communityId && 
94           UserService.Instance.user &&
95             <select value={this.state.type_} onChange={linkEvent(this, this.handleTypeChange)} class="ml-2 custom-select w-auto">
96               <option disabled>Type</option>
97               <option value={ListingType.All}>All</option>
98               <option value={ListingType.Subscribed}>Subscribed</option>
99             </select>
100
101         }
102       </div>
103     )
104   }
105
106   paginator() {
107     return (
108       <div class="mt-2">
109         {this.state.page > 1 && 
110           <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}>Prev</button>
111         }
112         <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}>Next</button>
113       </div>
114     );
115   }
116
117   nextPage(i: PostListings) { 
118     i.state.page++;
119     i.setState(i.state);
120     i.refetch();
121   }
122
123   prevPage(i: PostListings) { 
124     i.state.page--;
125     i.setState(i.state);
126     i.refetch();
127   }
128
129   handleSortChange(i: PostListings, event: any) {
130     i.state.sortType = Number(event.target.value);
131     i.state.page = 1;
132     i.setState(i.state);
133     i.refetch();
134   }
135
136   refetch() {
137     let getPostsForm: GetPostsForm = {
138       community_id: this.props.communityId,
139       page: this.state.page,
140       limit: fetchLimit,
141       sort: SortType[this.state.sortType],
142       type_: ListingType[this.state.type_]
143     }
144     WebSocketService.Instance.getPosts(getPostsForm);
145   }
146
147   handleTypeChange(i: PostListings, event: any) {
148     i.state.type_ = Number(event.target.value);
149     i.state.page = 1;
150     i.setState(i.state);
151     i.refetch();
152   }
153
154   parseMessage(msg: any) {
155     console.log(msg);
156     let op: UserOperation = msgOp(msg);
157     if (msg.error) {
158       alert(msg.error);
159       return;
160     } else if (op == UserOperation.GetPosts) {
161       let res: GetPostsResponse = msg;
162       this.state.posts = res.posts;
163       this.state.loading = false;
164       this.setState(this.state);
165     } else if (op == UserOperation.CreatePostLike) {
166       let res: CreatePostLikeResponse = msg;
167       let found = this.state.posts.find(c => c.id == res.post.id);
168       found.my_vote = res.post.my_vote;
169       found.score = res.post.score;
170       found.upvotes = res.post.upvotes;
171       found.downvotes = res.post.downvotes;
172       this.setState(this.state);
173     }
174   }
175 }
176
177