]> Untitled Git - lemmy.git/blob - ui/src/components/inbox.tsx
Adding emoji support
[lemmy.git] / ui / src / components / inbox.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, Comment, SortType, GetRepliesForm, GetRepliesResponse, CommentResponse } from '../interfaces';
6 import { WebSocketService, UserService } from '../services';
7 import { msgOp } from '../utils';
8 import { CommentNodes } from './comment-nodes';
9
10 enum UnreadType {
11   Unread, All
12 }
13
14 interface InboxState {
15   unreadType: UnreadType;
16   replies: Array<Comment>;
17   sort: SortType;
18   page: number;
19 }
20
21 export class Inbox extends Component<any, InboxState> {
22
23   private subscription: Subscription;
24   private emptyState: InboxState = {
25     unreadType: UnreadType.Unread,
26     replies: [],
27     sort: SortType.New,
28     page: 1,
29   }
30
31   constructor(props: any, context: any) {
32     super(props, context);
33
34     this.state = this.emptyState;
35
36     this.subscription = WebSocketService.Instance.subject
37     .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
38     .subscribe(
39       (msg) => this.parseMessage(msg),
40         (err) => console.error(err),
41         () => console.log('complete')
42     );
43
44     this.refetch();
45   }
46
47   componentWillUnmount() {
48     this.subscription.unsubscribe();
49   }
50
51   componentDidMount() {
52     document.title = `/u/${UserService.Instance.user.username} Inbox - Lemmy`;
53   }
54
55   render() {
56     let user = UserService.Instance.user;
57     return (
58       <div class="container">
59         <div class="row">
60           <div class="col-12">
61             <h5 class="mb-0">
62               <span>Inbox for <Link to={`/u/${user.username}`}>{user.username}</Link></span>
63             </h5>
64             {this.state.replies.length > 0 && this.state.unreadType == UnreadType.Unread &&
65               <ul class="list-inline mb-1 text-muted small font-weight-bold">
66                 <li className="list-inline-item">
67                   <span class="pointer" onClick={this.markAllAsRead}>mark all as read</span>
68                 </li>
69               </ul>
70             }
71             {this.selects()}
72             {this.replies()}
73             {this.paginator()}
74           </div>
75         </div>
76       </div>
77     )
78   }
79
80   selects() {
81     return (
82       <div className="mb-2">
83         <select value={this.state.unreadType} onChange={linkEvent(this, this.handleUnreadTypeChange)} class="custom-select custom-select-sm w-auto">
84           <option disabled>Type</option>
85           <option value={UnreadType.Unread}>Unread</option>
86           <option value={UnreadType.All}>All</option>
87         </select>
88         <select value={this.state.sort} onChange={linkEvent(this, this.handleSortChange)} class="custom-select custom-select-sm w-auto ml-2">
89           <option disabled>Sort Type</option>
90           <option value={SortType.New}>New</option>
91           <option value={SortType.TopDay}>Top Day</option>
92           <option value={SortType.TopWeek}>Week</option>
93           <option value={SortType.TopMonth}>Month</option>
94           <option value={SortType.TopYear}>Year</option>
95           <option value={SortType.TopAll}>All</option>
96         </select>
97       </div>
98     )
99
100   }
101
102   replies() {
103     return (
104       <div>
105         {this.state.replies.map(reply => 
106           <CommentNodes nodes={[{comment: reply}]} noIndent markable />
107         )}
108       </div>
109     );
110   }
111
112   paginator() {
113     return (
114       <div class="mt-2">
115         {this.state.page > 1 && 
116           <button class="btn btn-sm btn-secondary mr-1" onClick={linkEvent(this, this.prevPage)}>Prev</button>
117         }
118         <button class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.nextPage)}>Next</button>
119       </div>
120     );
121   }
122
123   nextPage(i: Inbox) { 
124     i.state.page++;
125     i.setState(i.state);
126     i.refetch();
127   }
128
129   prevPage(i: Inbox) { 
130     i.state.page--;
131     i.setState(i.state);
132     i.refetch();
133   }
134
135   handleUnreadTypeChange(i: Inbox, event: any) {
136     i.state.unreadType = Number(event.target.value);
137     i.state.page = 1;
138     i.setState(i.state);
139     i.refetch();
140   }
141
142   refetch() {
143     let form: GetRepliesForm = {
144       sort: SortType[this.state.sort],
145       unread_only: (this.state.unreadType == UnreadType.Unread),
146       page: this.state.page,
147       limit: 9999,
148     };
149     WebSocketService.Instance.getReplies(form);
150   }
151
152   handleSortChange(i: Inbox, event: any) {
153     i.state.sort = Number(event.target.value);
154     i.state.page = 1;
155     i.setState(i.state);
156     i.refetch();
157   }
158
159   markAllAsRead() {
160     WebSocketService.Instance.markAllAsRead();
161   }
162
163   parseMessage(msg: any) {
164     console.log(msg);
165     let op: UserOperation = msgOp(msg);
166     if (msg.error) {
167       alert(msg.error);
168       return;
169     } else if (op == UserOperation.GetReplies || op == UserOperation.MarkAllAsRead) {
170       let res: GetRepliesResponse = msg;
171       this.state.replies = res.replies;
172       this.sendRepliesCount();
173       window.scrollTo(0,0);
174       this.setState(this.state);
175     } else if (op == UserOperation.EditComment) {
176       let res: CommentResponse = msg;
177
178       let found = this.state.replies.find(c => c.id == res.comment.id);
179       found.content = res.comment.content;
180       found.updated = res.comment.updated;
181       found.removed = res.comment.removed;
182       found.deleted = res.comment.deleted;
183       found.upvotes = res.comment.upvotes;
184       found.downvotes = res.comment.downvotes;
185       found.score = res.comment.score;
186
187       // If youre in the unread view, just remove it from the list
188       if (this.state.unreadType == UnreadType.Unread && res.comment.read) {
189         this.state.replies = this.state.replies.filter(r => r.id !== res.comment.id);
190       } else {
191         let found = this.state.replies.find(c => c.id == res.comment.id);
192         found.read = res.comment.read;
193       }
194       this.sendRepliesCount();
195
196       this.setState(this.state);
197     } else if (op == UserOperation.CreateComment) {
198       // let res: CommentResponse = msg;
199       alert('Reply sent');
200       // this.state.replies.unshift(res.comment); // TODO do this right
201       // this.setState(this.state);
202     } else if (op == UserOperation.SaveComment) {
203       let res: CommentResponse = msg;
204       let found = this.state.replies.find(c => c.id == res.comment.id);
205       found.saved = res.comment.saved;
206       this.setState(this.state);
207     } else if (op == UserOperation.CreateCommentLike) {
208       let res: CommentResponse = msg;
209       let found: Comment = this.state.replies.find(c => c.id === res.comment.id);
210       found.score = res.comment.score;
211       found.upvotes = res.comment.upvotes;
212       found.downvotes = res.comment.downvotes;
213       if (res.comment.my_vote !== null) 
214         found.my_vote = res.comment.my_vote;
215       this.setState(this.state);
216     }
217   }
218
219   sendRepliesCount() {
220     UserService.Instance.sub.next({user: UserService.Instance.user, unreadCount: this.state.replies.filter(r => !r.read).length});
221   }
222 }
223