summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/src/components/community.tsx57
-rw-r--r--ui/src/components/inbox.tsx23
-rw-r--r--ui/src/components/login.tsx2
-rw-r--r--ui/src/components/main.tsx105
-rw-r--r--ui/src/components/navbar.tsx88
-rw-r--r--ui/src/components/post.tsx11
-rw-r--r--ui/src/components/sidebar.tsx17
-rw-r--r--ui/src/env.ts8
-rw-r--r--ui/src/interfaces.ts12
-rw-r--r--ui/src/services/WebSocketService.ts10
-rw-r--r--ui/src/translations/de.ts8
-rw-r--r--ui/src/translations/es.ts21
-rw-r--r--ui/src/translations/fi.ts49
-rw-r--r--ui/yarn.lock503
14 files changed, 635 insertions, 279 deletions
diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx
index 3c5f6890..866b9eec 100644
--- a/ui/src/components/community.tsx
+++ b/ui/src/components/community.tsx
@@ -14,20 +14,17 @@ import {
GetCommunityForm,
ListingType,
GetPostsResponse,
+ PostResponse,
CreatePostLikeResponse,
+ AddModToCommunityResponse,
+ BanFromCommunityResponse,
WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
import { PostListings } from './post-listings';
import { SortSelect } from './sort-select';
import { Sidebar } from './sidebar';
-import {
- wsJsonToRes,
- routeSortTypeToEnum,
- fetchLimit,
- postRefetchSeconds,
- toast,
-} from '../utils';
+import { wsJsonToRes, routeSortTypeToEnum, fetchLimit, toast } from '../utils';
import { T } from 'inferno-i18next';
import { i18n } from '../i18next';
@@ -37,6 +34,7 @@ interface State {
communityName: string;
moderators: Array<CommunityUser>;
admins: Array<UserView>;
+ online: number;
loading: boolean;
posts: Array<Post>;
sort: SortType;
@@ -45,7 +43,6 @@ interface State {
export class Community extends Component<any, State> {
private subscription: Subscription;
- private postFetcher: any;
private emptyState: State = {
community: {
id: null,
@@ -67,6 +64,7 @@ export class Community extends Component<any, State> {
admins: [],
communityId: Number(this.props.match.params.id),
communityName: this.props.match.params.name,
+ online: null,
loading: true,
posts: [],
sort: this.getSortTypeFromProps(this.props),
@@ -108,7 +106,6 @@ export class Community extends Component<any, State> {
componentWillUnmount() {
this.subscription.unsubscribe();
- clearInterval(this.postFetcher);
}
// Necessary for back button for some reason
@@ -158,6 +155,7 @@ export class Community extends Component<any, State> {
community={this.state.community}
moderators={this.state.moderators}
admins={this.state.admins}
+ online={this.state.online}
/>
</div>
</div>
@@ -240,11 +238,6 @@ export class Community extends Component<any, State> {
);
}
- keepFetchingPosts() {
- this.fetchPosts();
- this.postFetcher = setInterval(() => this.fetchPosts(), postRefetchSeconds);
- }
-
fetchPosts() {
let getPostsForm: GetPostsForm = {
page: this.state.page,
@@ -268,9 +261,10 @@ export class Community extends Component<any, State> {
this.state.community = data.community;
this.state.moderators = data.moderators;
this.state.admins = data.admins;
+ this.state.online = data.online;
document.title = `/c/${this.state.community.name} - ${WebSocketService.Instance.site.name}`;
this.setState(this.state);
- this.keepFetchingPosts();
+ this.fetchPosts();
} else if (res.op == UserOperation.EditCommunity) {
let data = res.data as CommunityResponse;
this.state.community = data.community;
@@ -286,13 +280,44 @@ export class Community extends Component<any, State> {
this.state.posts = data.posts;
this.state.loading = false;
this.setState(this.state);
+ } else if (res.op == UserOperation.EditPost) {
+ let data = res.data as PostResponse;
+ let found = this.state.posts.find(c => c.id == data.post.id);
+
+ found.url = data.post.url;
+ found.name = data.post.name;
+ found.nsfw = data.post.nsfw;
+
+ this.setState(this.state);
+ } else if (res.op == UserOperation.CreatePost) {
+ let data = res.data as PostResponse;
+ this.state.posts.unshift(data.post);
+ this.setState(this.state);
} 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;
+ if (data.post.my_vote !== null) {
+ found.my_vote = data.post.my_vote;
+ found.upvoteLoading = false;
+ found.downvoteLoading = false;
+ }
+
+ this.setState(this.state);
+ } else if (res.op == UserOperation.AddModToCommunity) {
+ let data = res.data as AddModToCommunityResponse;
+ this.state.moderators = data.moderators;
+ this.setState(this.state);
+ } else if (res.op == UserOperation.BanFromCommunity) {
+ let data = res.data as BanFromCommunityResponse;
+
+ this.state.posts
+ .filter(p => p.creator_id == data.user.id)
+ .forEach(p => (p.banned = data.banned));
+
this.setState(this.state);
}
}
diff --git a/ui/src/components/inbox.tsx b/ui/src/components/inbox.tsx
index 41c1ce60..5fd9dbdc 100644
--- a/ui/src/components/inbox.tsx
+++ b/ui/src/components/inbox.tsx
@@ -421,10 +421,25 @@ export class Inbox extends Component<any, InboxState> {
this.sendUnreadCount();
this.setState(this.state);
} else if (res.op == UserOperation.CreateComment) {
- // let res: CommentResponse = msg;
- toast(i18n.t('reply_sent'));
- // this.state.replies.unshift(res.comment); // TODO do this right
- // this.setState(this.state);
+ let data = res.data as CommentResponse;
+
+ if (data.recipient_ids.includes(UserService.Instance.user.id)) {
+ this.state.replies.unshift(data.comment);
+ this.setState(this.state);
+ } else if (data.comment.creator_id == UserService.Instance.user.id) {
+ toast(i18n.t('reply_sent'));
+ }
+ this.setState(this.state);
+ } else if (res.op == UserOperation.CreatePrivateMessage) {
+ let data = res.data as PrivateMessageResponse;
+
+ if (data.message.recipient_id == UserService.Instance.user.id) {
+ this.state.messages.unshift(data.message);
+ this.setState(this.state);
+ } else if (data.message.creator_id == UserService.Instance.user.id) {
+ toast(i18n.t('message_sent'));
+ }
+ this.setState(this.state);
} else if (res.op == UserOperation.SaveComment) {
let data = res.data as CommentResponse;
let found = this.state.replies.find(c => c.id == data.comment.id);
diff --git a/ui/src/components/login.tsx b/ui/src/components/login.tsx
index 64687a3d..b65b7a83 100644
--- a/ui/src/components/login.tsx
+++ b/ui/src/components/login.tsx
@@ -306,6 +306,7 @@ export class Login extends Component<any, State> {
this.state = this.emptyState;
this.setState(this.state);
UserService.Instance.login(data);
+ WebSocketService.Instance.userJoin();
toast(i18n.t('logged_in'));
this.props.history.push('/');
} else if (res.op == UserOperation.Register) {
@@ -313,6 +314,7 @@ export class Login extends Component<any, State> {
this.state = this.emptyState;
this.setState(this.state);
UserService.Instance.login(data);
+ WebSocketService.Instance.userJoin();
this.props.history.push('/communities');
} else if (res.op == UserOperation.PasswordReset) {
toast(i18n.t('reset_password_mail_sent'));
diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx
index 6bf4164f..9ff6af44 100644
--- a/ui/src/components/main.tsx
+++ b/ui/src/components/main.tsx
@@ -15,8 +15,11 @@ import {
SiteResponse,
GetPostsResponse,
CreatePostLikeResponse,
+ PostResponse,
Post,
GetPostsForm,
+ AddAdminResponse,
+ BanUserResponse,
WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
@@ -31,7 +34,6 @@ import {
fetchLimit,
routeSortTypeToEnum,
routeListingTypeToEnum,
- postRefetchSeconds,
pictshareAvatarThumbnail,
showAvatars,
toast,
@@ -42,7 +44,7 @@ import { T } from 'inferno-i18next';
interface MainState {
subscribedCommunities: Array<CommunityUser>;
trendingCommunities: Array<Community>;
- site: GetSiteResponse;
+ siteRes: GetSiteResponse;
showEditSite: boolean;
loading: boolean;
posts: Array<Post>;
@@ -53,11 +55,10 @@ interface MainState {
export class Main extends Component<any, MainState> {
private subscription: Subscription;
- private postFetcher: any;
private emptyState: MainState = {
subscribedCommunities: [],
trendingCommunities: [],
- site: {
+ siteRes: {
site: {
id: null,
name: null,
@@ -133,12 +134,11 @@ export class Main extends Component<any, MainState> {
WebSocketService.Instance.listCommunities(listCommunitiesForm);
- this.keepFetchingPosts();
+ this.fetchPosts();
}
componentWillUnmount() {
this.subscription.unsubscribe();
- clearInterval(this.postFetcher);
}
// Necessary for back button for some reason
@@ -241,7 +241,7 @@ export class Main extends Component<any, MainState> {
this.siteInfo()
) : (
<SiteForm
- site={this.state.site.site}
+ site={this.state.siteRes.site}
onCancel={this.handleEditCancel}
/>
)}
@@ -262,7 +262,7 @@ export class Main extends Component<any, MainState> {
<div>
<div class="card border-secondary mb-3">
<div class="card-body">
- <h5 class="mb-0">{`${this.state.site.site.name}`}</h5>
+ <h5 class="mb-0">{`${this.state.siteRes.site.name}`}</h5>
{this.canAdmin && (
<ul class="list-inline mb-1 text-muted small font-weight-bold">
<li className="list-inline-item">
@@ -279,7 +279,7 @@ export class Main extends Component<any, MainState> {
<li className="list-inline-item badge badge-secondary">
<T
i18nKey="number_online"
- interpolation={{ count: this.state.site.online }}
+ interpolation={{ count: this.state.siteRes.online }}
>
#
</T>
@@ -288,7 +288,7 @@ export class Main extends Component<any, MainState> {
<T
i18nKey="number_of_users"
interpolation={{
- count: this.state.site.site.number_of_users,
+ count: this.state.siteRes.site.number_of_users,
}}
>
#
@@ -298,7 +298,7 @@ export class Main extends Component<any, MainState> {
<T
i18nKey="number_of_communities"
interpolation={{
- count: this.state.site.site.number_of_communities,
+ count: this.state.siteRes.site.number_of_communities,
}}
>
#
@@ -308,7 +308,7 @@ export class Main extends Component<any, MainState> {
<T
i18nKey="number_of_posts"
interpolation={{
- count: this.state.site.site.number_of_posts,
+ count: this.state.siteRes.site.number_of_posts,
}}
>
#
@@ -318,7 +318,7 @@ export class Main extends Component<any, MainState> {
<T
i18nKey="number_of_comments"
interpolation={{
- count: this.state.site.site.number_of_comments,
+ count: this.state.siteRes.site.number_of_comments,
}}
>
#
@@ -337,7 +337,7 @@ export class Main extends Component<any, MainState> {
</T>
:
</li>
- {this.state.site.admins.map(admin => (
+ {this.state.siteRes.admins.map(admin => (
<li class="list-inline-item">
<Link class="text-info" to={`/u/${admin.name}`}>
{admin.avatar && showAvatars() && (
@@ -355,13 +355,13 @@ export class Main extends Component<any, MainState> {
</ul>
</div>
</div>
- {this.state.site.site.description && (
+ {this.state.siteRes.site.description && (
<div class="card border-secondary mb-3">
<div class="card-body">
<div
className="md-div"
dangerouslySetInnerHTML={mdToHtml(
- this.state.site.site.description
+ this.state.siteRes.site.description
)}
/>
</div>
@@ -494,7 +494,7 @@ export class Main extends Component<any, MainState> {
get canAdmin(): boolean {
return (
UserService.Instance.user &&
- this.state.site.admins
+ this.state.siteRes.admins
.map(a => a.id)
.includes(UserService.Instance.user.id)
);
@@ -548,11 +548,6 @@ export class Main extends Component<any, MainState> {
window.scrollTo(0, 0);
}
- keepFetchingPosts() {
- this.fetchPosts();
- this.postFetcher = setInterval(() => this.fetchPosts(), postRefetchSeconds);
- }
-
fetchPosts() {
let getPostsForm: GetPostsForm = {
page: this.state.page,
@@ -584,15 +579,15 @@ export class Main extends Component<any, MainState> {
if (!data.site) {
this.context.router.history.push('/setup');
}
- this.state.site.admins = data.admins;
- this.state.site.site = data.site;
- this.state.site.banned = data.banned;
- this.state.site.online = data.online;
+ this.state.siteRes.admins = data.admins;
+ this.state.siteRes.site = data.site;
+ this.state.siteRes.banned = data.banned;
+ this.state.siteRes.online = data.online;
this.setState(this.state);
document.title = `${WebSocketService.Instance.site.name}`;
} else if (res.op == UserOperation.EditSite) {
let data = res.data as SiteResponse;
- this.state.site.site = data.site;
+ this.state.siteRes.site = data.site;
this.state.showEditSite = false;
this.setState(this.state);
} else if (res.op == UserOperation.GetPosts) {
@@ -600,13 +595,67 @@ export class Main extends Component<any, MainState> {
this.state.posts = data.posts;
this.state.loading = false;
this.setState(this.state);
+ } else if (res.op == UserOperation.CreatePost) {
+ let data = res.data as PostResponse;
+
+ // If you're on subscribed, only push it if you're subscribed.
+ if (this.state.type_ == ListingType.Subscribed) {
+ if (
+ this.state.subscribedCommunities
+ .map(c => c.community_id)
+ .includes(data.post.community_id)
+ ) {
+ this.state.posts.unshift(data.post);
+ }
+ } else {
+ this.state.posts.unshift(data.post);
+ }
+
+ this.setState(this.state);
+ } else if (res.op == UserOperation.EditPost) {
+ let data = res.data as PostResponse;
+ let found = this.state.posts.find(c => c.id == data.post.id);
+
+ found.url = data.post.url;
+ found.name = data.post.name;
+ found.nsfw = data.post.nsfw;
+
+ this.setState(this.state);
} 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;
+ if (data.post.my_vote !== null) {
+ found.my_vote = data.post.my_vote;
+ found.upvoteLoading = false;
+ found.downvoteLoading = false;
+ }
+
+ this.setState(this.state);
+ } else if (res.op == UserOperation.AddAdmin) {
+ let data = res.data as AddAdminResponse;
+ this.state.siteRes.admins = data.admins;
+ this.setState(this.state);
+ } else if (res.op == UserOperation.BanUser) {
+ let data = res.data as BanUserResponse;
+ let found = this.state.siteRes.banned.find(u => (u.id = data.user.id));
+
+ // Remove the banned if its found in the list, and the action is an unban
+ if (found && !data.banned) {
+ this.state.siteRes.banned = this.state.siteRes.banned.filter(
+ i => i.id !== data.user.id
+ );
+ } else {
+ this.state.siteRes.banned.push(data.user);
+ }
+
+ this.state.posts
+ .filter(p => p.creator_id == data.user.id)
+ .forEach(p => (p.banned = data.banned));
+
this.setState(this.state);
}
}
diff --git a/ui/src/components/navbar.tsx b/ui/src/components/navbar.tsx
index eccc8116..c03dcd87 100644
--- a/ui/src/components/navbar.tsx
+++ b/ui/src/components/navbar.tsx
@@ -14,7 +14,9 @@ import {
SortType,
GetSiteResponse,
Comment,
+ CommentResponse,
PrivateMessage,
+ PrivateMessageResponse,
WebSocketJsonResponse,
} from '../interfaces';
import {
@@ -35,7 +37,6 @@ interface NavbarState {
replies: Array<Comment>;
mentions: Array<Comment>;
messages: Array<PrivateMessage>;
- fetchCount: number;
unreadCount: number;
siteName: string;
}
@@ -46,7 +47,6 @@ export class Navbar extends Component<any, NavbarState> {
emptyState: NavbarState = {
isLoggedIn: UserService.Instance.user !== undefined,
unreadCount: 0,
- fetchCount: 0,
replies: [],
mentions: [],
messages: [],
@@ -58,8 +58,6 @@ export class Navbar extends Component<any, NavbarState> {
super(props, context);
this.state = this.emptyState;
- this.keepFetchingUnreads();
-
// Subscribe to user changes
this.userSub = UserService.Instance.sub.subscribe(user => {
this.state.isLoggedIn = user.user !== undefined;
@@ -78,6 +76,8 @@ export class Navbar extends Component<any, NavbarState> {
if (this.state.isLoggedIn) {
this.requestNotificationPermission();
+ // TODO couldn't get re-logging in to re-fetch unreads
+ this.fetchUnreads();
}
WebSocketService.Instance.getSite();
@@ -211,45 +211,51 @@ export class Navbar extends Component<any, NavbarState> {
} else if (res.op == UserOperation.GetReplies) {
let data = res.data as GetRepliesResponse;
let unreadReplies = data.replies.filter(r => !r.read);
- if (
- unreadReplies.length > 0 &&
- this.state.fetchCount > 1 &&
- JSON.stringify(this.state.replies) !== JSON.stringify(unreadReplies)
- ) {
- this.notify(unreadReplies);
- }
this.state.replies = unreadReplies;
+ this.state.unreadCount = this.calculateUnreadCount();
this.setState(this.state);
this.sendUnreadCount();
} else if (res.op == UserOperation.GetUserMentions) {
let data = res.data as GetUserMentionsResponse;
let unreadMentions = data.mentions.filter(r => !r.read);
- if (
- unreadMentions.length > 0 &&
- this.state.fetchCount > 1 &&
- JSON.stringify(this.state.mentions) !== JSON.stringify(unreadMentions)
- ) {
- this.notify(unreadMentions);
- }
this.state.mentions = unreadMentions;
+ this.state.unreadCount = this.calculateUnreadCount();
this.setState(this.state);
this.sendUnreadCount();
} else if (res.op == UserOperation.GetPrivateMessages) {
let data = res.data as PrivateMessagesResponse;
let unreadMessages = data.messages.filter(r => !r.read);
- if (
- unreadMessages.length > 0 &&
- this.state.fetchCount > 1 &&
- JSON.stringify(this.state.messages) !== JSON.stringify(unreadMessages)
- ) {
- this.notify(unreadMessages);
- }
this.state.messages = unreadMessages;
+ this.state.unreadCount = this.calculateUnreadCount();
this.setState(this.state);
this.sendUnreadCount();
+ } else if (res.op == UserOperation.CreateComment) {
+ let data = res.data as CommentResponse;
+
+ if (this.state.isLoggedIn) {
+ if (data.recipient_ids.includes(UserService.Instance.user.id)) {
+ this.state.replies.push(data.comment);
+ this.state.unreadCount++;
+ this.setState(this.state);
+ this.sendUnreadCount();
+ this.notify(data.comment);
+ }
+ }
+ } else if (res.op == UserOperation.CreatePrivateMessage) {
+ let data = res.data as PrivateMessageResponse;
+
+ if (this.state.isLoggedIn) {
+ if (data.message.recipient_id == UserService.Instance.user.id) {
+ this.state.messages.push(data.message);
+ this.state.unreadCount++;
+ this.setState(this.state);
+ this.sendUnreadCount();
+ this.notify(data.message);
+ }
+ }
} else if (res.op == UserOperation.GetSite) {
let data = res.data as GetSiteResponse;
@@ -261,11 +267,6 @@ export class Navbar extends Component<any, NavbarState> {
}
}
- keepFetchingUnreads() {
- this.fetchUnreads();
- setInterval(() => this.fetchUnreads(), 15000);
- }
-
fetchUnreads() {
if (this.state.isLoggedIn) {
let repliesForm: GetRepliesForm = {
@@ -292,7 +293,6 @@ export class Navbar extends Component<any, NavbarState> {
WebSocketService.Instance.getReplies(repliesForm);
WebSocketService.Instance.getUserMentions(userMentionsForm);
WebSocketService.Instance.getPrivateMessages(privateMessagesForm);
- this.state.fetchCount++;
}
}
}
@@ -304,11 +304,11 @@ export class Navbar extends Component<any, NavbarState> {
sendUnreadCount() {
UserService.Instance.sub.next({
user: UserService.Instance.user,
- unreadCount: this.unreadCount,
+ unreadCount: this.state.unreadCount,
});
}
- get unreadCount() {
+ calculateUnreadCount(): number {
return (
this.state.replies.filter(r => !r.read).length +
this.state.mentions.filter(r => !r.read).length +
@@ -330,24 +330,20 @@ export class Navbar extends Component<any, NavbarState> {
}
}
- notify(replies: Array<Comment | PrivateMessage>) {
- let recentReply = replies[0];
+ notify(reply: Comment | PrivateMessage) {
if (Notification.permission !== 'granted') Notification.requestPermission();
else {
- var notification = new Notification(
- `${replies.length} ${i18n.t('unread_messages')}`,
- {
- icon: recentReply.creator_avatar
- ? recentReply.creator_avatar
- : `${window.location.protocol}//${window.location.host}/static/assets/apple-touch-icon.png`,
- body: `${recentReply.creator_name}: ${recentReply.content}`,
- }
- );
+ var notification = new Notification(reply.creator_name, {
+ icon: reply.creator_avatar
+ ? reply.creator_avatar
+ : `${window.location.protocol}//${window.location.host}/static/assets/apple-touch-icon.png`,
+ body: `${reply.content}`,
+ });
notification.onclick = () => {
this.context.router.history.push(
- isCommentType(recentReply)
- ? `/post/${recentReply.post_id}/comment/${recentReply.id}`
+ isCommentType(reply)
+ ? `/post/${reply.post_id}/comment/${reply.id}`
: `/inbox`
);
};
diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx
index 36621248..99a20b46 100644
--- a/ui/src/components/post.tsx
+++ b/ui/src/components/post.tsx
@@ -47,6 +47,7 @@ interface PostState {
community: Community;
moderators: Array<CommunityUser>;
admins: Array<UserView>;
+ online: number;
scrolled?: boolean;
scrolled_comment_id?: number;
loading: boolean;
@@ -62,6 +63,7 @@ export class Post extends Component<any, PostState> {
community: null,
moderators: [],
admins: [],
+ online: null,
scrolled: false,
loading: true,
crossPosts: [],
@@ -280,6 +282,7 @@ export class Post extends Component<any, PostState> {
community={this.state.community}
moderators={this.state.moderators}
admins={this.state.admins}
+ online={this.state.online}
/>
</div>
);
@@ -378,6 +381,7 @@ export class Post extends Component<any, PostState> {
this.state.community = data.community;
this.state.moderators = data.moderators;
this.state.admins = data.admins;
+ this.state.online = data.online;
this.state.loading = false;
document.title = `${this.state.post.name} - ${WebSocketService.Instance.site.name}`;
@@ -432,10 +436,15 @@ export class Post extends Component<any, PostState> {
this.setState(this.state);
} else if (res.op == UserOperation.CreatePostLike) {
let data = res.data as CreatePostLikeResponse;
- this.state.post.my_vote = data.post.my_vote;
this.state.post.score = data.post.score;
this.state.post.upvotes = data.post.upvotes;
this.state.post.downvotes = data.post.downvotes;
+ if (data.post.my_vote !== null) {
+ this.state.post.my_vote = data.post.my_vote;
+ this.state.post.upvoteLoading = false;
+ this.state.post.downvoteLoading = false;
+ }
+
this.setState(this.state);
} else if (res.op == UserOperation.EditPost) {
let data = res.data as PostResponse;
diff --git a/ui/src/components/sidebar.tsx b/ui/src/components/sidebar.tsx
index 089dd558..0e6b68e6 100644
--- a/ui/src/components/sidebar.tsx
+++ b/ui/src/components/sidebar.tsx
@@ -22,6 +22,7 @@ interface SidebarProps {
community: Community;
moderators: Array<CommunityUser>;
admins: Array<UserView>;
+ online: number;
}
interface SidebarState {
@@ -156,10 +157,13 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
</form>
)}
<ul class="my-1 list-inline">
- <li className="list-inline-item">
- <Link className="badge badge-secondary" to="/communities">
- {community.category_name}
- </Link>
+ <li className="list-inline-item badge badge-secondary">
+ <T
+ i18nKey="number_online"
+ interpolation={{ count: this.props.online }}
+ >
+ #
+ </T>
</li>
<li className="list-inline-item badge badge-secondary">
<T
@@ -186,6 +190,11 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
</T>
</li>
<li className="list-inline-item">
+ <Link className="badge badge-secondary" to="/communities">
+ {community.category_name}
+ </Link>
+ </li>
+ <li className="list-inline-item">
<Link
className="badge badge-secondary"
to={`/modlog/community/${this.props.community.id}`}
diff --git a/ui/src/env.ts b/ui/src/env.ts
index af9aad5d..5003986b 100644
--- a/ui/src/env.ts
+++ b/ui/src/env.ts
@@ -1,5 +1,9 @@
const host = `${window.location.hostname}`;
-const port = `${window.location.port == '4444' ? '8536' : window.location.port}`;
+const port = `${
+ window.location.port == '4444' ? '8536' : window.location.port
+}`;
const endpoint = `${host}:${port}`;
-export const wsUri = `${window.location.protocol == 'https:' ? 'wss://' : 'ws://'}${endpoint}/api/v1/ws`;
+export const wsUri = `${
+ window.location.protocol == 'https:' ? 'wss://' : 'ws://'
+}${endpoint}/api/v1/ws`;
diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts
index f83595d7..4036f7e6 100644
--- a/ui/src/interfaces.ts
+++ b/ui/src/interfaces.ts
@@ -41,6 +41,7 @@ export enum UserOperation {
CreatePrivateMessage,
EditPrivateMessage,
GetPrivateMessages,
+ UserJoin,
}
export enum CommentSortType {
@@ -538,6 +539,7 @@ export interface GetCommunityResponse {
community: Community;
moderators: Array<CommunityUser>;
admins: Array<UserView>;
+ online: number;
}
export interface CommunityResponse {
@@ -594,6 +596,7 @@ export interface GetPostResponse {
community: Community;
moderators: Array<CommunityUser>;
admins: Array<UserView>;
+ online: number;
}
export interface SavePostForm {
@@ -627,6 +630,7 @@ export interface SaveCommentForm {
export interface CommentResponse {
comment: Comment;
+ recipient_ids: Array<number>;
}
export interface CommentLikeForm {
@@ -775,6 +779,14 @@ export interface PrivateMessageResponse {
message: PrivateMessage;
}
+export interface UserJoinForm {
+ auth: string;
+}
+
+export interface UserJoinResponse {
+ user_id: number;
+}
+
export type MessageType =
| EditPrivateMessageForm
| LoginForm
diff --git a/ui/src/services/WebSocketService.ts b/ui/src/services/WebSocketService.ts
index a7e9b7e0..f1a6d156 100644
--- a/ui/src/services/WebSocketService.ts
+++ b/ui/src/services/WebSocketService.ts
@@ -38,6 +38,7 @@ import {
PrivateMessageForm,
EditPrivateMessageForm,
GetPrivateMessagesForm,
+ UserJoinForm,
MessageType,
} from '../interfaces';
import { webSocket } from 'rxjs/webSocket';
@@ -71,12 +72,21 @@ export class WebSocketService {
.subscribe();
console.log(`Connected to ${wsUri}`);
+
+ if (UserService.Instance.user) {
+ this.userJoin();
+ }
}
public static get Instance() {
return this._instance || (this._instance = new this());
}
+ public userJoin() {
+ let form: UserJoinForm = { auth: UserService.Instance.auth };
+ this.subject.next(this.wsSendWrapper(UserOperation.UserJoin, form));
+ }
+
public login(loginForm: LoginForm) {
this.subject.next(this.wsSendWrapper(UserOperation.Login, loginForm));
}
diff --git a/ui/src/translations/de.ts b/ui/src/translations/de.ts
index fafec579..7a1b0f5d 100644
--- a/ui/src/translations/de.ts
+++ b/ui/src/translations/de.ts
@@ -116,10 +116,11 @@ export const de = {
password: 'Passwort',
verify_password: 'Passwort überprüfen',
forgot_password: 'Passwort vergessen',
- reset_password_mail_sent: 'Eine E-Mail wurde geschickt, um dein Passwort zurückzusetzen.',
+ reset_password_mail_sent:
+ 'Eine E-Mail wurde geschickt, um dein Passwort zurückzusetzen.',
password_change: 'Passwort geändert',
new_password: 'neues Passwort',
- no_email_setup: "Dieser Server hat E-Mails nicht korrekt eingerichtet.",
+ no_email_setup: 'Dieser Server hat E-Mails nicht korrekt eingerichtet.',
login: 'Einloggen',
sign_up: 'Registrieren',
email: 'E-Mail',
@@ -182,7 +183,8 @@ export const de = {
community_already_exists: 'Gemeinschaft existiert bereits.',
community_moderator_already_exists:
'Gemeinschaft Moderator existiert bereits.',
- community_follower_already_exists: 'Gemeinschaft Follower existiert bereits.',
+ community_follower_already_exists:
+ 'Gemeinschaft Follower existiert bereits.',
community_user_already_banned: 'Gemeinschaft Nutzer schon gebannt.',
couldnt_create_post: 'Konnte Beitrag nicht anlegen.',
couldnt_like_post: 'Konnte Beitrag nicht liken.',
diff --git a/ui/src/translations/es.ts b/ui/src/translations/es.ts
index 6fb49482..d61ebfb8 100644
--- a/ui/src/translations/es.ts
+++ b/ui/src/translations/es.ts
@@ -132,7 +132,7 @@ export const es = {
reset_password_mail_sent: 'Enviar correo para reestablecer la contraseña.',
password_change: 'Cambio de Contraseña',
new_password: 'Nueva Contraseña',
- no_email_setup: "Este servidor no ha activado correctamente el correo.",
+ no_email_setup: 'Este servidor no ha activado correctamente el correo.',
email: 'Correo electrónico',
matrix_user_id: 'Usuario Matricial',
private_message_disclaimer:
@@ -204,9 +204,12 @@ export const es = {
couldnt_find_community: 'No se pudo encontrar la comunidad.',
couldnt_update_community: 'No se pudo actualizar la comunidad.',
community_already_exists: 'Esta comunidad ya existe.',
- community_moderator_already_exists: 'Este moderador de la comunidad ya existe.',