summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorDessalines <tyhou13@gmx.com>2020-01-23 19:39:59 -0500
committerDessalines <tyhou13@gmx.com>2020-01-23 19:39:59 -0500
commit8b88a8e75bf0732c1cc757445a7444edb48c68d2 (patch)
tree6b59100db56dc0acf34ed64232ce91102b4b191b /ui
parent9f499faa299cf68ab7c423efd12fd16f595e2ecf (diff)
Squashed commit of the following:
commit f5b75f342bdc35b6c770358b2408a7ffc9ce80ad Merge: bd1fc2b 69389f6 Author: Dessalines <happydooby@gmail.com> Date: Thu Jan 23 19:17:42 2020 -0500 Done merging http-api and private_message commit bd1fc2b80b8c6a42f0df721d91863b8688b339ee Author: Dessalines <happydooby@gmail.com> Date: Thu Jan 23 16:46:07 2020 -0500 Remove danger from private-message.tsx commit 69389f61c9944319b5c71d7fb398294f1f8b8e7c Author: Dessalines <happydooby@gmail.com> Date: Thu Jan 23 11:21:21 2020 -0500 Fixing http curl POST docs. commit 7fdcae4f0739df79cbf8d7ea2138519d87f2aa32 Merge: dbe9ad0 752318f Author: Dessalines <happydooby@gmail.com> Date: Thu Jan 23 11:01:06 2020 -0500 Merge remote-tracking branch 'nutomic/http-api' into dessalines-http-api commit 752318fdf3cf95633744e89bbfe22a761fecc53d Author: Felix <me@nutomic.com> Date: Thu Jan 23 15:22:17 2020 +0100 api fixes commit 9ccff18f23509d309261670b57563b87e8f61f77 Author: Dessalines <happydooby@gmail.com> Date: Wed Jan 22 22:29:11 2020 -0500 Adding a toaster to replace alerts. Fixes #457 commit 5197407dd29a895fff37d4f0982e44d5e727d426 Merge: bacb9ac 58f673a Author: Dessalines <happydooby@gmail.com> Date: Wed Jan 22 21:20:38 2020 -0500 Merge branch 'private_messaging' into dev commit 58f673ab7856d2380cfaedbc46baf944fedfabb5 Author: Dessalines <happydooby@gmail.com> Date: Wed Jan 22 21:09:17 2020 -0500 Adding message to comment node actions. commit bacb9ac59ed3a6d8b4a80f37103ccf9c3ab751c9 Merge: 10c6505 7d3adda Author: Dessalines <happydooby@gmail.com> Date: Wed Jan 22 20:37:08 2020 -0500 Merge branch 'private_messaging' into dev commit 10c65059686ff74fc2ce412572e2d6fc3497c43a Author: Dessalines <happydooby@gmail.com> Date: Wed Jan 22 20:35:20 2020 -0500 Adding correct hello_name to mail. commit 7d3adda0cd4888e70b362cbad1b82f46d79c8d4c Author: Dessalines <happydooby@gmail.com> Date: Wed Jan 22 16:35:29 2020 -0500 Adding private messaging, and matrix user ids. - Fixes #244 commit dbe9ad0998b80d174130d82c11473555c7d6bc0e Author: Dessalines <happydooby@gmail.com> Date: Mon Jan 20 18:49:54 2020 -0500 Fixing last. commit 20c9c54806429395f8a4c1a4e7a6a0f677d4e6b8 Author: Dessalines <happydooby@gmail.com> Date: Sun Jan 19 13:31:37 2020 -0500 Updating API docs. commit dc84ccaac94b9887f8512e3c32aeea0df89520be Merge: 6c61dd2 3edd75e Author: Dessalines <happydooby@gmail.com> Date: Sun Jan 19 10:06:25 2020 -0500 Merge branch 'master' into dessalines-http-api commit 6c61dd266bb6e389312ec56e7fc50f4a6b71b374 Merge: c5eecd0 e518954 Author: Dessalines <happydooby@gmail.com> Date: Sun Jan 19 09:09:00 2020 -0500 Merge remote-tracking branch 'nutomic/websocket-generics' into dessalines-http-api commit e518954bcab2553906cec9f2bcfa6d1b5fdc2f38 Author: Felix <me@nutomic.com> Date: Sun Jan 19 14:25:50 2020 +0100 Use generics to reduce code duplication in websocket commit c5eecd055e79510421aebe26e5d4f173a5916a3e Author: Dessalines <happydooby@gmail.com> Date: Sun Jan 19 00:38:45 2020 -0500 Strongly typing WebsocketJsonResponse. Forgot comment-form.tsx commit 0c5eb471359929c532a4e6a63477a39ab6db67b6 Author: Dessalines <happydooby@gmail.com> Date: Sat Jan 18 23:54:10 2020 -0500 First pass at fixing UI to work with new websocketresponses. commit baf77bb6be88e796683bc21fd16a0359e68c7791 Author: Felix <me@nutomic.com> Date: Sat Jan 18 17:25:45 2020 +0100 simplify json serialization code commit 047ec97e1857888aeeac53629a76a4dc7e2f110b Author: Felix <me@nutomic.com> Date: Sat Jan 18 14:22:25 2020 +0100 rewrite api endpoint urls commit 2fb4900b0cf586674d6212e0aa2c1b852d104a1a Author: Felix <me@nutomic.com> Date: Thu Jan 16 17:04:37 2020 +0100 fix typo commit cba80815797b6578ab817b99fee35575cccef27d Author: Felix <me@nutomic.com> Date: Thu Jan 16 16:47:38 2020 +0100 fix formatting commit d7285d8c25c9a88c33519ec12f3c730d6b45fcf5 Author: Felix <me@nutomic.com> Date: Thu Jan 16 16:09:01 2020 +0100 small fix commit 415040a1e9b90fcb71872a41fbb6e7e7131d966d Author: Felix <me@nutomic.com> Date: Thu Jan 16 15:39:08 2020 +0100 working! commit 7a97c981a0b74cf6f66574690e58917a47508395 Author: Felix <me@nutomic.com> Date: Wed Jan 15 16:48:21 2020 +0100 try to simplify code with higher order functions commit c41082f98f459da2cc48dcfd7d9d5c2ac08865d0 Author: Felix <me@nutomic.com> Date: Wed Jan 15 16:37:25 2020 +0100 Implement HTTP API using generics (fixes #380)
Diffstat (limited to 'ui')
-rw-r--r--ui/assets/css/toastify.css78
-rw-r--r--ui/package.json1
-rw-r--r--ui/src/components/comment-form.tsx21
-rw-r--r--ui/src/components/comment-node.tsx10
-rw-r--r--ui/src/components/communities.tsx27
-rw-r--r--ui/src/components/community-form.tsx50
-rw-r--r--ui/src/components/community.tsx56
-rw-r--r--ui/src/components/create-private-message.tsx53
-rw-r--r--ui/src/components/inbox.tsx222
-rw-r--r--ui/src/components/login.tsx43
-rw-r--r--ui/src/components/main.tsx65
-rw-r--r--ui/src/components/modlog.tsx27
-rw-r--r--ui/src/components/moment-time.tsx2
-rw-r--r--ui/src/components/navbar.tsx77
-rw-r--r--ui/src/components/password_change.tsx24
-rw-r--r--ui/src/components/post-form.tsx56
-rw-r--r--ui/src/components/post.tsx181
-rw-r--r--ui/src/components/private-message-form.tsx293
-rw-r--r--ui/src/components/private-message.tsx254
-rw-r--r--ui/src/components/search.tsx50
-rw-r--r--ui/src/components/setup.tsx35
-rw-r--r--ui/src/components/user.tsx169
-rw-r--r--ui/src/index.html1
-rw-r--r--ui/src/index.tsx5
-rw-r--r--ui/src/interfaces.ts115
-rw-r--r--ui/src/services/WebSocketService.ts29
-rw-r--r--ui/src/translations/en.ts14
-rw-r--r--ui/src/utils.ts23
-rw-r--r--ui/yarn.lock5
29 files changed, 1465 insertions, 521 deletions
diff --git a/ui/assets/css/toastify.css b/ui/assets/css/toastify.css
new file mode 100644
index 00000000..8804e229
--- /dev/null
+++ b/ui/assets/css/toastify.css
@@ -0,0 +1,78 @@
+/*!
+ * Toastify js 1.6.2
+ * https://github.com/apvarun/toastify-js
+ * @license MIT licensed
+ *
+ * Copyright (C) 2018 Varun A P
+ */
+
+.toastify {
+ padding: 12px 20px;
+ color: #ffffff;
+ display: inline-block;
+ box-shadow: 0 3px 6px -1px rgba(0, 0, 0, 0.12), 0 10px 36px -4px rgba(77, 96, 232, 0.3);
+ background: -webkit-linear-gradient(315deg, #73a5ff, #5477f5);
+ background: linear-gradient(135deg, #73a5ff, #5477f5);
+ position: fixed;
+ opacity: 0;
+ transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1);
+ border-radius: 2px;
+ cursor: pointer;
+ text-decoration: none;
+ max-width: calc(50% - 20px);
+ z-index: 2147483647;
+}
+
+.toastify.on {
+ opacity: 1;
+}
+
+.toast-close {
+ opacity: 0.4;
+ padding: 0 5px;
+}
+
+.toastify-right {
+ right: 15px;
+}
+
+.toastify-left {
+ left: 15px;
+}
+
+.toastify-top {
+ top: -150px;
+}
+
+.toastify-bottom {
+ bottom: -150px;
+}
+
+.toastify-rounded {
+ border-radius: 25px;
+}
+
+.toastify-avatar {
+ width: 1.5em;
+ height: 1.5em;
+ margin: 0 5px;
+ border-radius: 2px;
+}
+
+.toastify-center {
+ margin-left: auto;
+ margin-right: auto;
+ left: 0;
+ right: 0;
+ max-width: fit-content;
+}
+
+@media only screen and (max-width: 360px) {
+ .toastify-right, .toastify-left {
+ margin-left: auto;
+ margin-right: auto;
+ left: 0;
+ right: 0;
+ max-width: fit-content;
+ }
+}
diff --git a/ui/package.json b/ui/package.json
index ea6343da..41f47088 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -36,6 +36,7 @@
"prettier": "^1.18.2",
"rxjs": "^6.4.0",
"terser": "^4.6.0",
+ "toastify-js": "^1.6.2",
"tributejs": "^4.1.1",
"twemoji": "^12.1.2",
"ws": "^7.0.0"
diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx
index f5816899..b8ea0a5a 100644
--- a/ui/src/components/comment-form.tsx
+++ b/ui/src/components/comment-form.tsx
@@ -10,12 +10,13 @@ import {
} from '../interfaces';
import { Subscription } from 'rxjs';
import {
+ wsJsonToRes,
capitalizeFirstLetter,
mentionDropdownFetchLimit,
- msgOp,
mdToHtml,
randomStr,
markdownHelpUrl,
+ toast,
} from '../utils';
import { WebSocketService, UserService } from '../services';
import autosize from 'autosize';
@@ -293,7 +294,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
.catch(error => {
i.state.imageLoading = false;
i.setState(i.state);
- alert(error);
+ toast(error, 'danger');
});
}
@@ -311,10 +312,10 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
this.userSub = WebSocketService.Instance.subject.subscribe(
msg => {
- let op: UserOperation = msgOp(msg);
- if (op == UserOperation.Search) {
- let res: SearchResponse = msg;
- let users = res.users.map(u => {
+ let res = wsJsonToRes(msg);
+ if (res.op == UserOperation.Search) {
+ let data = res.data as SearchResponse;
+ let users = data.users.map(u => {
return { key: u.name };
});
cb(users);
@@ -343,10 +344,10 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
this.communitySub = WebSocketService.Instance.subject.subscribe(
msg => {
- let op: UserOperation = msgOp(msg);
- if (op == UserOperation.Search) {
- let res: SearchResponse = msg;
- let communities = res.communities.map(u => {
+ let res = wsJsonToRes(msg);
+ if (res.op == UserOperation.Search) {
+ let data = res.data as SearchResponse;
+ let communities = data.communities.map(u => {
return { key: u.name };
});
cb(communities);
diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx
index baaf63e9..046fc88d 100644
--- a/ui/src/components/comment-node.tsx
+++ b/ui/src/components/comment-node.tsx
@@ -293,6 +293,16 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
</li>
</>
)}
+ {!this.myComment && (
+ <li className="list-inline-item">
+ <Link
+ class="text-muted"
+ to={`/create_private_message?recipient_id=${node.comment.creator_id}`}
+ >
+ {i18n.t('message').toLowerCase()}
+ </Link>
+ </li>
+ )}
<li className="list-inline-item">•</li>
<li className="list-inline-item">
<span
diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx
index 598a5dad..867cfd81 100644
--- a/ui/src/components/communities.tsx
+++ b/ui/src/components/communities.tsx
@@ -10,9 +10,10 @@ import {
FollowCommunityForm,
ListCommunitiesForm,
SortType,
+ WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService } from '../services';
-import { msgOp } from '../utils';
+import { wsJsonToRes, toast } from '../utils';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
@@ -231,15 +232,15 @@ export class Communities extends Component<any, CommunitiesState> {
WebSocketService.Instance.listCommunities(listCommunitiesForm);
}
- parseMessage(msg: any) {
+ parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
- alert(i18n.t(msg.error));
+ let res = wsJsonToRes(msg);
+ if (res.error) {
+ toast(i18n.t(msg.error), 'danger');
return;
- } else if (op == UserOperation.ListCommunities) {
- let res: ListCommunitiesResponse = msg;
- this.state.communities = res.communities;
+ } else if (res.op == UserOperation.ListCommunities) {
+ let data = res.data as ListCommunitiesResponse;
+ this.state.communities = data.communities;
this.state.communities.sort(
(a, b) => b.number_of_subscribers - a.number_of_subscribers
);
@@ -248,11 +249,11 @@ export class Communities extends Component<any, CommunitiesState> {
this.setState(this.state);
let table = document.querySelector('#community_table');
Sortable.initTable(table);
- } else if (op == UserOperation.FollowCommunity) {
- let res: CommunityResponse = msg;
- let found = this.state.communities.find(c => c.id == res.community.id);
- found.subscribed = res.community.subscribed;
- found.number_of_subscribers = res.community.number_of_subscribers;
+ } else if (res.op == UserOperation.FollowCommunity) {
+ let data = res.data as CommunityResponse;
+ let found = this.state.communities.find(c => c.id == data.community.id);
+ found.subscribed = data.community.subscribed;
+ found.number_of_subscribers = data.community.number_of_subscribers;
this.setState(this.state);
}
}
diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx
index 2085da28..4dc7bfcb 100644
--- a/ui/src/components/community-form.tsx
+++ b/ui/src/components/community-form.tsx
@@ -8,10 +8,11 @@ import {
ListCategoriesResponse,
CommunityResponse,
GetSiteResponse,
+ WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService } from '../services';
-import { msgOp, capitalizeFirstLetter } from '../utils';
-import * as autosize from 'autosize';
+import { wsJsonToRes, capitalizeFirstLetter, toast } from '../utils';
+import autosize from 'autosize';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
@@ -67,14 +68,7 @@ export class CommunityForm extends Component<
}
this.subscription = WebSocketService.Instance.subject
- .pipe(
- retryWhen(errors =>
- errors.pipe(
- delay(3000),
- take(10)
- )
- )
- )
+ .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
.subscribe(
msg => this.parseMessage(msg),
err => console.error(err),
@@ -246,34 +240,34 @@ export class CommunityForm extends Component<
i.props.onCancel();
}
- parseMessage(msg: any) {
- let op: UserOperation = msgOp(msg);
+ parseMessage(msg: WebSocketJsonResponse) {
+ let res = wsJsonToRes(msg);
console.log(msg);
- if (msg.error) {
- alert(i18n.t(msg.error));
+ if (res.error) {
+ toast(i18n.t(msg.error), 'danger');
this.state.loading = false;
this.setState(this.state);
return;
- } else if (op == UserOperation.ListCategories) {
- let res: ListCategoriesResponse = msg;
- this.state.categories = res.categories;
+ } else if (res.op == UserOperation.ListCategories) {
+ let data = res.data as ListCategoriesResponse;
+ this.state.categories = data.categories;
if (!this.props.community) {
- this.state.communityForm.category_id = res.categories[0].id;
+ this.state.communityForm.category_id = data.categories[0].id;
}
this.setState(this.state);
- } else if (op == UserOperation.CreateCommunity) {
- let res: CommunityResponse = msg;
+ } else if (res.op == UserOperation.CreateCommunity) {
+ let data = res.data as CommunityResponse;
this.state.loading = false;
- this.props.onCreate(res.community);
+ this.props.onCreate(data.community);
}
- // TODO is ths necessary
- else if (op == UserOperation.EditCommunity) {
- let res: CommunityResponse = msg;
+ // TODO is this necessary
+ else if (res.op == UserOperation.EditCommunity) {
+ let data = res.data as CommunityResponse;
this.state.loading = false;
- this.props.onEdit(res.community);
- } else if (op == UserOperation.GetSite) {
- let res: GetSiteResponse = msg;
- this.state.enable_nsfw = res.site.enable_nsfw;
+ this.props.onEdit(data.community);
+ } else if (res.op == UserOperation.GetSite) {
+ let data = res.data as GetSiteResponse;
+ this.state.enable_nsfw = data.site.enable_nsfw;
this.setState(this.state);
}
}
diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx
index 873b5a8a..9d02dd86 100644
--- a/ui/src/components/community.tsx
+++ b/ui/src/components/community.tsx
@@ -14,16 +14,18 @@ import {
ListingType,
GetPostsResponse,
CreatePostLikeResponse,
+ WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
import { PostListings } from './post-listings';
import { SortSelect } from './sort-select';
import { Sidebar } from './sidebar';
import {
- msgOp,
+ wsJsonToRes,
routeSortTypeToEnum,
fetchLimit,
postRefetchSeconds,
+ toast,
} from '../utils';
import { T } from 'inferno-i18next';
import { i18n } from '../i18next';
@@ -253,43 +255,43 @@ export class Community extends Component<any, State> {
WebSocketService.Instance.getPosts(getPostsForm);
}
- parseMessage(msg: any) {
+ parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
- alert(i18n.t(msg.error));
+ let res = wsJsonToRes(msg);
+ if (res.error) {
+ toast(i18n.t(msg.error), 'danger');
this.context.router.history.push('/');
return;
- } else if (op == UserOperation.GetCommunity) {
- let res: GetCommunityResponse = msg;
- this.state.community = res.community;
- this.state.moderators = res.moderators;
- this.state.admins = res.admins;
+ } else if (res.op == UserOperation.GetCommunity) {
+ let data = res.data as GetCommunityResponse;
+ this.state.community = data.community;
+ this.state.moderators = data.moderators;
+ this.state.admins = data.admins;
document.title = `/c/${this.state.community.name} - ${WebSocketService.Instance.site.name}`;
this.setState(this.state);
this.keepFetchingPosts();
- } else if (op == UserOperation.EditCommunity) {
- let res: CommunityResponse = msg;
- this.state.community = res.community;
+ } else if (res.op == UserOperation.EditCommunity) {
+ let data = res.data as CommunityResponse;
+ this.state.community = data.community;
this.setState(this.state);
- } else if (op == UserOperation.FollowCommunity) {
- let res: CommunityResponse = msg;
- this.state.community.subscribed = res.community.subscribed;
+ } else if (res.op == UserOperation.FollowCommunity) {
+ let data = res.data as CommunityResponse;
+ this.state.community.subscribed = data.community.subscribed;
this.state.community.number_of_subscribers =
- res.community.number_of_subscribers;
+ data.community.number_of_subscribers;
this.setState(this.state);
- } else if (op == UserOperation.GetPosts) {
- let res: GetPostsResponse = msg;
- this.state.posts = res.posts;
+ } else if (res.op == UserOperation.GetPosts) {
+ let data = res.data as GetPostsResponse;
+ this.state.posts = data.posts;
this.state.loading = false;
this.setState(this.state);
- } else if (op == UserOperation.CreatePostLike) {
- let res: CreatePostLikeResponse = msg;
- let found = this.state.posts.find(c => c.id == res.post.id);
- found.my_vote = res.post.my_vote;
- found.score = res.post.score;
- found.upvotes = res.post.upvotes;
- found.downvotes = res.post.downvotes;
+ } else if (res.op == UserOperation.CreatePostLike) {
+ let data = res.data as CreatePostLikeResponse;
+ let found = this.state.posts.find(c => c.id == data.post.id);
+ found.my_vote = data.post.my_vote;
+ found.score = data.post.score;
+ found.upvotes = data.post.upvotes;
+ found.downvotes = data.post.downvotes;
this.setState(this.state);
}
}
diff --git a/ui/src/components/create-private-message.tsx b/ui/src/components/create-private-message.tsx
new file mode 100644
index 00000000..7160bc52
--- /dev/null
+++ b/ui/src/components/create-private-message.tsx
@@ -0,0 +1,53 @@
+import { Component } from 'inferno';
+import { PrivateMessageForm } from './private-message-form';
+import { WebSocketService } from '../services';
+import { PrivateMessageFormParams } from '../interfaces';
+import { toast } from '../utils';
+import { i18n } from '../i18next';
+
+export class CreatePrivateMessage extends Component<any, any> {
+ constructor(props: any, context: any) {
+ super(props, context);
+ this.handlePrivateMessageCreate = this.handlePrivateMessageCreate.bind(
+ this
+ );
+ }
+
+ componentDidMount() {
+ document.title = `${i18n.t('create_private_message')} - ${
+ WebSocketService.Instance.site.name
+ }`;
+ }
+
+ render() {
+ return (
+ <div class="container">
+ <div class="row">
+ <div class="col-12 col-lg-6 offset-lg-3 mb-4">
+ <h5>{i18n.t('create_private_message')}</h5>
+ <PrivateMessageForm
+ onCreate={this.handlePrivateMessageCreate}
+ params={this.params}
+ />
+ </div>
+ </div>
+ </div>
+ );
+ }
+
+ get params(): PrivateMessageFormParams {
+ let urlParams = new URLSearchParams(this.props.location.search);
+ let params: PrivateMessageFormParams = {
+ recipient_id: Number(urlParams.get('recipient_id')),
+ };
+
+ return params;
+ }
+
+ handlePrivateMessageCreate() {
+ toast(i18n.t('message_sent'));
+
+ // Navigate to the front
+ this.props.history.push(`/`);
+ }
+}
diff --git a/ui/src/components/inbox.tsx b/ui/src/components/inbox.tsx
index a302b834..5c3ff6d2 100644
--- a/ui/src/components/inbox.tsx
+++ b/ui/src/components/inbox.tsx
@@ -12,10 +12,16 @@ import {
GetUserMentionsResponse,
UserMentionResponse,
CommentResponse,
+ WebSocketJsonResponse,
+ PrivateMessage as PrivateMessageI,
+ GetPrivateMessagesForm,
+ PrivateMessagesResponse,
+ PrivateMessageResponse,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
-import { msgOp, fetchLimit } from '../utils';
+import { wsJsonToRes, fetchLimit, isCommentType, toast } from '../utils';
import { CommentNodes } from './comment-nodes';
+import { PrivateMessage } from './private-message';
import { SortSelect } from './sort-select';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
@@ -26,9 +32,10 @@ enum UnreadOrAll {
}
enum UnreadType {
- Both,
+ All,
Replies,
Mentions,
+ Messages,
}
interface InboxState {
@@ -36,6 +43,7 @@ interface InboxState {
unreadType: UnreadType;
replies: Array<Comment>;
mentions: Array<Comment>;
+ messages: Array<PrivateMessageI>;
sort: SortType;
page: number;
}
@@ -44,9 +52,10 @@ export class Inbox extends Component<any, InboxState> {
private subscription: Subscription;
private emptyState: InboxState = {
unreadOrAll: UnreadOrAll.Unread,
- unreadType: UnreadType.Both,
+ unreadType: UnreadType.All,
replies: [],
mentions: [],
+ messages: [],
sort: SortType.New,
page: 1,
};
@@ -103,7 +112,10 @@ export class Inbox extends Component<any, InboxState> {
</a>
</small>
</h5>
- {this.state.replies.length + this.state.mentions.length > 0 &&
+ {this.state.replies.length +
+ this.state.mentions.length +
+ this.state.messages.length >
+ 0 &&
this.state.unreadOrAll == UnreadOrAll.Unread && (
<ul class="list-inline mb-1 text-muted small font-weight-bold">
<li className="list-inline-item">
@@ -114,9 +126,10 @@ export class Inbox extends Component<any, InboxState> {
</ul>
)}
{this.selects()}
- {this.state.unreadType == UnreadType.Both && this.both()}
+ {this.state.unreadType == UnreadType.All && this.all()}
{this.state.unreadType == UnreadType.Replies && this.replies()}
{this.state.unreadType == UnreadType.Mentions && this.mentions()}
+ {this.state.unreadType == UnreadType.Messages && this.messages()}
{this.paginator()}
</div>
</div>
@@ -150,8 +163,8 @@ export class Inbox extends Component<any, InboxState> {
<option disabled>
<T i18nKey="type">#</T>
</option>
- <option value={UnreadType.Both}>
- <T i18nKey="both">#</T>
+ <option value={UnreadType.All}>
+ <T i18nKey="all">#</T>
</option>
<option value={UnreadType.Replies}>
<T i18nKey="replies">#</T>
@@ -159,6 +172,9 @@ export class Inbox extends Component<any, InboxState> {
<option value={UnreadType.Mentions}>
<T i18nKey="mentions">#</T>
</option>
+ <option value={UnreadType.Messages}>
+ <T i18nKey="messages">#</T>
+ </option>
</select>
<SortSelect
sort={this.state.sort}
@@ -169,33 +185,25 @@ export class Inbox extends Component<any, InboxState> {
);
}
- both() {
- let combined: Array<{
- type_: string;
- data: Comment;
- }> = [];
- let replies = this.state.replies.map(e => {
- return { type_: 'replies', data: e };
- });
- let mentions = this.state.mentions.map(e => {
- return { type_: 'mentions', data: e };
- });
+ all() {
+ let combined: Array<Comment | PrivateMessageI> = [];
- combined.push(...replies);
- combined.push(...mentions);
+ combined.push(...this.state.replies);
+ combined.push(...this.state.mentions);
+ combined.push(...this.state.messages);
// Sort it
- if (this.state.sort == SortType.New) {
- combined.sort((a, b) => b.data.published.localeCompare(a.data.published));
- } else {
- combined.sort((a, b) => b.data.score - a.data.score);
- }
+ combined.sort((a, b) => b.published.localeCompare(a.published));
return (
<div>
- {combined.map(i => (
- <CommentNodes nodes={[{ comment: i.data }]} noIndent markable />
- ))}
+ {combined.map(i =>
+ isCommentType(i) ? (
+ <CommentNodes nodes={[{ comment: i }]} noIndent markable />
+ ) : (
+ <PrivateMessage privateMessage={i} />
+ )
+ )}
</div>
);
}
@@ -220,6 +228,16 @@ export class Inbox extends Component<any, InboxState> {
);
}
+ messages() {
+ return (
+ <div>
+ {this.state.messages.map(message => (
+ <PrivateMessage privateMessage={message} />
+ ))}
+ </div>
+ );
+ }
+
paginator() {
return (
<div class="mt-2">
@@ -283,6 +301,13 @@ export class Inbox extends Component<any, InboxState> {
limit: fetchLimit,
};
WebSocketService.Instance.getUserMentions(userMentionsForm);
+
+ let privateMessagesForm: GetPrivateMessagesForm = {
+ unread_only: this.state.unreadOrAll == UnreadOrAll.Unread,
+ page: this.state.page,
+ limit: fetchLimit,
+ };
+ WebSocketService.Instance.getPrivateMessages(privateMessagesForm);
}
handleSortChange(val: SortType) {
@@ -296,94 +321,122 @@ export class Inbox extends Component<any, InboxState> {
WebSocketService.Instance.markAllAsRead();
}
- parseMessage(msg: any) {
+ parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
- let op: UserOperation = msgOp(msg);
- if (msg.error) {
- alert(i18n.t(msg.error));
+ let res = wsJsonToRes(msg);
+ if (res.error) {
+ toast(i18n.t(msg.error), 'danger');
return;
- } else if (op == UserOperation.GetReplies) {
- let res: GetRepliesResponse = msg;
- this.state.replies = res.replies;
+ } else if (res.op == UserOperation.GetReplies) {
+ let data = res.data as GetRepliesResponse;
+ this.state.replies = data.replies;
+ this.sendUnreadCount();
+ window.scrollTo(0, 0);
+ this.setState(this.state);
+ } else if (res.op == UserOperation.GetUserMentions) {
+ let data = res.data as GetUserMentionsResponse;
+ this.state.mentions = data.mentions;
+ this.sendUnreadCount();
+ window.scrollTo(0, 0);
+ this.setState(this.state);
+ } else if (res.op == UserOperation.GetPrivateMessages) {
+ let data = res.data as PrivateMessagesResponse;
+ this.state.messages = data.messages;
this.sendUnreadCount();
window.scrollTo(0, 0);
this.setState(this.state);
- } else if (op == UserOperation.GetUserMentions) {
- let res: GetUserMentionsResponse = msg;
- this.state.mentions = res.mentions;
+ } else if (res.op == UserOperation.EditPrivateMessage) {
+ let data = res.data as PrivateMessageResponse;
+ let found: PrivateMessageI = this.state.messages.find(
+ m => m.id === data.message.id
+ );
+ found.content = data.message.content;
+ found.updated = data.message.updated;
+ found.deleted = data.message.deleted;
+ // If youre in the unread view, just remove it from the list
+ if (this.state.unreadOrAll == UnreadOrAll.Unread && data.message.read) {
+ this.state.messages = this.state.messages.filter(
+ r => r.id !== data.message.id
+ );
+ } else {
+ let found = this.state.messages.find(c => c.id == data.message.id);
+ found.read = data.message.read;