summaryrefslogtreecommitdiffstats
path: root/ui/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'ui/src/components')
-rw-r--r--ui/src/components/comment-form.tsx3
-rw-r--r--ui/src/components/comment-node.tsx105
-rw-r--r--ui/src/components/communities.tsx22
-rw-r--r--ui/src/components/community-form.tsx5
-rw-r--r--ui/src/components/community.tsx25
-rw-r--r--ui/src/components/create-post.tsx2
-rw-r--r--ui/src/components/create-private-message.tsx53
-rw-r--r--ui/src/components/footer.tsx2
-rw-r--r--ui/src/components/inbox.tsx117
-rw-r--r--ui/src/components/login.tsx7
-rw-r--r--ui/src/components/main.tsx27
-rw-r--r--ui/src/components/modlog.tsx4
-rw-r--r--ui/src/components/navbar.tsx59
-rw-r--r--ui/src/components/password_change.tsx4
-rw-r--r--ui/src/components/post-form.tsx5
-rw-r--r--ui/src/components/post-listing.tsx113
-rw-r--r--ui/src/components/post.tsx12
-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.tsx215
-rw-r--r--ui/src/components/setup.tsx4
-rw-r--r--ui/src/components/sponsors.tsx3
-rw-r--r--ui/src/components/symbols.tsx5
-rw-r--r--ui/src/components/user.tsx75
24 files changed, 1119 insertions, 295 deletions
diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx
index dddcbe72..b8ea0a5a 100644
--- a/ui/src/components/comment-form.tsx
+++ b/ui/src/components/comment-form.tsx
@@ -16,6 +16,7 @@ import {
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');
});
}
diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx
index 21a82954..046fc88d 100644
--- a/ui/src/components/comment-node.tsx
+++ b/ui/src/components/comment-node.tsx
@@ -47,8 +47,8 @@ interface CommentNodeState {
showConfirmAppointAsAdmin: boolean;
collapsed: boolean;
viewSource: boolean;
- my_vote: number;
- score: number;
+ upvoteLoading: boolean;
+ downvoteLoading: boolean;
}
interface CommentNodeProps {
@@ -78,8 +78,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
showConfirmTransferCommunity: false,
showConfirmAppointAsMod: false,
showConfirmAppointAsAdmin: false,
- my_vote: this.props.node.comment.my_vote,
- score: this.props.node.comment.score,
+ upvoteLoading: this.props.node.comment.upvoteLoading,
+ downvoteLoading: this.props.node.comment.downvoteLoading,
};
constructor(props: any, context: any) {
@@ -87,8 +87,20 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this.state = this.emptyState;
this.handleReplyCancel = this.handleReplyCancel.bind(this);
- this.handleCommentLike = this.handleCommentLike.bind(this);
- this.handleCommentDisLike = this.handleCommentDisLike.bind(this);
+ this.handleCommentUpvote = this.handleCommentUpvote.bind(this);
+ this.handleCommentDownvote = this.handleCommentDownvote.bind(this);
+ }
+
+ componentWillReceiveProps(nextProps: CommentNodeProps) {
+ if (
+ nextProps.node.comment.upvoteLoading !== this.state.upvoteLoading ||
+ nextProps.node.comment.downvoteLoading !== this.state.downvoteLoading
+ ) {
+ this.setState({
+ upvoteLoading: false,
+ downvoteLoading: false,
+ });
+ }
}
render() {
@@ -107,26 +119,40 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<button
disabled={!UserService.Instance.user}
className={`btn p-0 ${
- this.state.my_vote == 1 ? 'text-info' : 'text-muted'
+ node.comment.my_vote == 1 ? 'text-info' : 'text-muted'
}`}
- onClick={linkEvent(node, this.handleCommentLike)}
+ onClick={linkEvent(node, this.handleCommentUpvote)}
>
- <svg class="icon upvote">
- <use xlinkHref="#icon-arrow-up"></use>
- </svg>
+ {this.state.upvoteLoading ? (
+ <svg class="icon icon-spinner spin upvote">
+ <use xlinkHref="#icon-spinner"></use>
+ </svg>
+ ) : (
+ <svg class="icon upvote">
+ <use xlinkHref="#icon-arrow-up"></use>
+ </svg>
+ )}
</button>
- <div class={`font-weight-bold text-muted`}>{this.state.score}</div>
+ <div class={`font-weight-bold text-muted`}>
+ {node.comment.score}
+ </div>
{WebSocketService.Instance.site.enable_downvotes && (
<button
disabled={!UserService.Instance.user}
className={`btn p-0 ${
- this.state.my_vote == -1 ? 'text-danger' : 'text-muted'
+ node.comment.my_vote == -1 ? 'text-danger' : 'text-muted'
}`}
- onClick={linkEvent(node, this.handleCommentDisLike)}
+ onClick={linkEvent(node, this.handleCommentDownvote)}
>
- <svg class="icon downvote">
- <use xlinkHref="#icon-arrow-down"></use>
- </svg>
+ {this.state.downvoteLoading ? (
+ <svg class="icon icon-spinner spin downvote">
+ <use xlinkHref="#icon-spinner"></use>
+ </svg>
+ ) : (
+ <svg class="icon downvote">
+ <use xlinkHref="#icon-arrow-down"></use>
+ </svg>
+ )}
</button>
)}
</div>
@@ -267,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
@@ -724,41 +760,26 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this.setState(this.state);
}
- handleCommentLike(i: CommentNodeI) {
- this.state.my_vote = i.comment.my_vote == 1 ? 0 : 1;
- let add = 1;
- if (i.comment.my_vote == 1) {
- add = -1;
- } else if (i.comment.my_vote == -1) {
- add = 2;
- }
-
- this.state.score = i.comment.score + add;
- this.setState(this.state);
-
+ handleCommentUpvote(i: CommentNodeI) {
+ this.setState({
+ upvoteLoading: true,
+ });
let form: CommentLikeForm = {
comment_id: i.comment.id,
post_id: i.comment.post_id,
- score: this.state.my_vote,
+ score: i.comment.my_vote == 1 ? 0 : 1,
};
WebSocketService.Instance.likeComment(form);
}
- handleCommentDisLike(i: CommentNodeI) {
- this.state.my_vote = i.comment.my_vote == -1 ? 0 : -1;
- let add = -1;
- if (i.comment.my_vote == 1) {
- add = -2;
- } else if (i.comment.my_vote == -1) {
- add = 1;
- }
- this.state.score = i.comment.score + add;
- this.setState(this.state);
-
+ handleCommentDownvote(i: CommentNodeI) {
+ this.setState({
+ downvoteLoading: true,
+ });
let form: CommentLikeForm = {
comment_id: i.comment.id,
post_id: i.comment.post_id,
- score: this.state.my_vote,
+ score: i.comment.my_vote == -1 ? 0 : -1,
};
WebSocketService.Instance.likeComment(form);
}
diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx
index ebcbc345..867cfd81 100644
--- a/ui/src/components/communities.tsx
+++ b/ui/src/components/communities.tsx
@@ -13,12 +13,14 @@ import {
WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService } from '../services';
-import { wsJsonToRes } from '../utils';
+import { wsJsonToRes, toast } from '../utils';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
declare const Sortable: any;
+const communityLimit = 100;
+
interface CommunitiesState {
communities: Array<Community>;
page: number;
@@ -174,12 +176,14 @@ export class Communities extends Component<any, CommunitiesState> {
<T i18nKey="prev">#</T>
</button>
)}
- <button
- class="btn btn-sm btn-secondary"
- onClick={linkEvent(this, this.nextPage)}
- >
- <T i18nKey="next">#</T>
- </button>
+ {this.state.communities.length == communityLimit && (
+ <button
+ class="btn btn-sm btn-secondary"
+ onClick={linkEvent(this, this.nextPage)}
+ >
+ <T i18nKey="next">#</T>
+ </button>
+ )}
</div>
);
}
@@ -221,7 +225,7 @@ export class Communities extends Component<any, CommunitiesState> {
refetch() {
let listCommunitiesForm: ListCommunitiesForm = {
sort: SortType[SortType.TopAll],
- limit: 100,
+ limit: communityLimit,
page: this.state.page,
};
@@ -232,7 +236,7 @@ export class Communities extends Component<any, CommunitiesState> {
console.log(msg);
let res = wsJsonToRes(msg);
if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
return;
} else if (res.op == UserOperation.ListCommunities) {
let data = res.data as ListCommunitiesResponse;
diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx
index 14cd8e4f..4dc7bfcb 100644
--- a/ui/src/components/community-form.tsx
+++ b/ui/src/components/community-form.tsx
@@ -8,9 +8,10 @@ import {
ListCategoriesResponse,
CommunityResponse,
GetSiteResponse,
+ WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService } from '../services';
-import { wsJsonToRes, capitalizeFirstLetter } from '../utils';
+import { wsJsonToRes, capitalizeFirstLetter, toast } from '../utils';
import autosize from 'autosize';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
@@ -243,7 +244,7 @@ export class CommunityForm extends Component<
let res = wsJsonToRes(msg);
console.log(msg);
if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
this.state.loading = false;
this.setState(this.state);
return;
diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx
index 357fe260..9d02dd86 100644
--- a/ui/src/components/community.tsx
+++ b/ui/src/components/community.tsx
@@ -25,6 +25,7 @@ import {
routeSortTypeToEnum,
fetchLimit,
postRefetchSeconds,
+ toast,
} from '../utils';
import { T } from 'inferno-i18next';
import { i18n } from '../i18next';
@@ -148,7 +149,7 @@ export class Community extends Component<any, State> {
)}
</h5>
{this.selects()}
- {this.state.posts && <PostListings posts={this.state.posts} />}
+ <PostListings posts={this.state.posts} />
{this.paginator()}
</div>
<div class="col-12 col-md-4">
@@ -193,12 +194,14 @@ export class Community extends Component<any, State> {
<T i18nKey="prev">#</T>
</button>
)}
- <button
- class="btn btn-sm btn-secondary"
- onClick={linkEvent(this, this.nextPage)}
- >
- <T i18nKey="next">#</T>
- </button>
+ {this.state.posts.length == fetchLimit && (
+ <button
+ class="btn btn-sm btn-secondary"
+ onClick={linkEvent(this, this.nextPage)}
+ >
+ <T i18nKey="next">#</T>
+ </button>
+ )}
</div>
);
}
@@ -256,7 +259,7 @@ export class Community extends Component<any, State> {
console.log(msg);
let res = wsJsonToRes(msg);
if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
this.context.router.history.push('/');
return;
} else if (res.op == UserOperation.GetCommunity) {
@@ -279,12 +282,6 @@ export class Community extends Component<any, State> {
this.setState(this.state);
} else if (res.op == UserOperation.GetPosts) {
let data = res.data as GetPostsResponse;
-
- // TODO rework this
- // This is needed to refresh the view
- this.state.posts = undefined;
- this.setState(this.state);
-
this.state.posts = data.posts;
this.state.loading = false;
this.setState(this.state);
diff --git a/ui/src/components/create-post.tsx b/ui/src/components/create-post.tsx
index eeb9bc6c..ad013d09 100644
--- a/ui/src/components/create-post.tsx
+++ b/ui/src/components/create-post.tsx
@@ -35,7 +35,7 @@ export class CreatePost extends Component<any, any> {
get params(): PostFormParams {
let urlParams = new URLSearchParams(this.props.location.search);
let params: PostFormParams = {
- name: urlParams.get('name'),
+ name: urlParams.get('title'),
community: urlParams.get('community') || this.prevCommunityName,
body: urlParams.get('body'),
url: urlParams.get('url'),
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/footer.tsx b/ui/src/components/footer.tsx
index 8aa05072..5451da2c 100644
--- a/ui/src/components/footer.tsx
+++ b/ui/src/components/footer.tsx
@@ -29,7 +29,7 @@ export class Footer extends Component<any, any> {
</li>
<li class="nav-item">
<Link class="nav-link" to="/sponsors">
- <T i18nKey="sponsors">#</T>
+ <T i18nKey="donate">#</T>
</Link>
</li>
<li class="nav-item">
diff --git a/ui/src/components/inbox.tsx b/ui/src/components/inbox.tsx
index 4aa9cebe..5c3ff6d2 100644
--- a/ui/src/components/inbox.tsx
+++ b/ui/src/components/inbox.tsx
@@ -13,10 +13,15 @@ import {
UserMentionResponse,
CommentResponse,
WebSocketJsonResponse,
+ PrivateMessage as PrivateMessageI,
+ GetPrivateMessagesForm,
+ PrivateMessagesResponse,
+ PrivateMessageResponse,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
-import { wsJsonToRes, 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';
@@ -27,9 +32,10 @@ enum UnreadOrAll {
}
enum UnreadType {
- Both,
+ All,
Replies,
Mentions,
+ Messages,
}
interface InboxState {
@@ -37,6 +43,7 @@ interface InboxState {
unreadType: UnreadType;
replies: Array<Comment>;
mentions: Array<Comment>;
+ messages: Array<PrivateMessageI>;
sort: SortType;
page: number;
}
@@ -45,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,
};
@@ -104,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">
@@ -115,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>
@@ -151,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>
@@ -160,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}
@@ -170,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>
);
}
@@ -221,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">
@@ -284,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) {
@@ -301,7 +325,7 @@ export class Inbox extends Component<any, InboxState> {
console.log(msg);
let res = wsJsonToRes(msg);
if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
return;
} else if (res.op == UserOperation.GetReplies) {
let data = res.data as GetRepliesResponse;
@@ -315,9 +339,37 @@ export class Inbox extends Component<any, InboxState> {
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 (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;
+ }
+ this.sendUnreadCount();
+ window.scrollTo(0, 0);
+ this.setState(this.state);
} else if (res.op == UserOperation.MarkAllAsRead) {
this.state.replies = [];
this.state.mentions = [];
+ this.state.messages = [];
+ this.sendUnreadCount();
window.scrollTo(0, 0);
this.setState(this.state);
} else if (res.op == UserOperation.EditComment) {
@@ -368,7 +420,7 @@ export class Inbox extends Component<any, InboxState> {
this.setState(this.state);
} else if (res.op == UserOperation.CreateComment) {
// let res: CommentResponse = msg;
- alert(i18n.t('reply_sent'));
+ toast(i18n.t('reply_sent'));
// this.state.replies.unshift(res.comment); // TODO do this right
// this.setState(this.state);
} else if (res.op == UserOperation.SaveComment) {
@@ -392,7 +444,10 @@ export class Inbox extends Component<any, InboxState> {
sendUnreadCount() {
let count =
this.state.replies.filter(r => !r.read).length +
- this.state.mentions.filter(r => !r.read).length;
+ this.state.mentions.filter(r => !r.read).length +
+ this.state.messages.filter(
+ r => !r.read && r.creator_id !== UserService.Instance.user.id
+ ).length;
UserService.Instance.sub.next({
user: UserService.Instance.user,
unreadCount: count,
diff --git a/ui/src/components/login.tsx b/ui/src/components/login.tsx
index 29482f45..ac60ba74 100644
--- a/ui/src/components/login.tsx
+++ b/ui/src/components/login.tsx
@@ -11,7 +11,7 @@ import {
WebSocketJsonResponse,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
-import { wsJsonToRes, validEmail } from '../utils';
+import { wsJsonToRes, validEmail, toast } from '../utils';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
@@ -296,7 +296,7 @@ export class Login extends Component<any, State> {
parseMessage(msg: WebSocketJsonResponse) {
let res = wsJsonToRes(msg);
if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
this.state = this.emptyState;
this.setState(this.state);
return;
@@ -306,6 +306,7 @@ export class Login extends Component<any, State> {
this.state = this.emptyState;
this.setState(this.state);
UserService.Instance.login(data);
+ toast(i18n.t('logged_in'));
this.props.history.push('/');
} else if (res.op == UserOperation.Register) {
let data = res.data as LoginResponse;
@@ -314,7 +315,7 @@ export class Login extends Component<any, State> {
UserService.Instance.login(data);
this.props.history.push('/communities');
} else if (res.op == UserOperation.PasswordReset) {
- alert(i18n.t('reset_password_mail_sent'));
+ toast(i18n.t('reset_password_mail_sent'));
} else if (res.op == UserOperation.GetSite) {
let data = res.data as GetSiteResponse;
this.state.enable_nsfw = data.site.enable_nsfw;
diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx
index 1ccebc80..9f16edb5 100644
--- a/ui/src/components/main.tsx
+++ b/ui/src/components/main.tsx
@@ -34,6 +34,7 @@ import {
postRefetchSeconds,
pictshareAvatarThumbnail,
showAvatars,
+ toast,
} from '../utils';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
@@ -422,9 +423,7 @@ export class Main extends Component<any, MainState> {
) : (
<div>
{this.selects()}
- {this.state.posts && (
- <PostListings posts={this.state.posts} showCommunity />
- )}
+ <PostListings posts={this.state.posts} showCommunity />
{this.paginator()}
</div>
)}
@@ -480,12 +479,14 @@ export class Main extends Component<any, MainState> {
<T i18nKey="prev">#</T>
</button>
)}
- <button
- class="btn btn-sm btn-secondary"
- onClick={linkEvent(this, this.nextPage)}
- >
- <T i18nKey="next">#</T>
- </button>
+ {this.state.posts.length == fetchLimit && (
+ <button
+ class="btn btn-sm btn-secondary"
+ onClick={linkEvent(this, this.nextPage)}
+ >
+ <T i18nKey="next">#</T>
+ </button>
+ )}
</div>
);
}
@@ -566,7 +567,7 @@ export class Main extends Component<any, MainState> {
console.log(msg);
let res = wsJsonToRes(msg);
if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
return;
} else if (res.op == UserOperation.GetFollowedCommunities) {
let data = res.data as GetFollowedCommunitiesResponse;
@@ -596,12 +597,6 @@ export class Main extends Component<any, MainState> {
this.setState(this.state);
} else if (res.op == UserOperation.GetPosts) {
let data = res.data as GetPostsResponse;
-
- // This is needed to refresh the view
- // TODO mess with this
- this.state.posts = undefined;
- this.setState(this.state);
-
this.state.posts = data.posts;
this.state.loading = false;
this.setState(this.state);
diff --git a/ui/src/components/modlog.tsx b/ui/src/components/modlog.tsx
index b2011af5..dd651092 100644
--- a/ui/src/components/modlog.tsx
+++ b/ui/src/components/modlog.tsx
@@ -17,7 +17,7 @@ import {
ModAdd,
} from '../interfaces';
import { WebSocketService } from '../services';
-import { wsJsonToRes, addTypeInfo, fetchLimit } from '../utils';
+import { wsJsonToRes, addTypeInfo, fetchLimit, toast } from '../utils';
import { MomentTime } from './moment-time';
import moment from 'moment';
import { i18n } from '../i18next';
@@ -426,7 +426,7 @@ export class Modlog extends Component<any, ModlogState> {
console.log(msg);
let res = wsJsonToRes(msg);
if (res.error) {
- alert(i18n.t(res.error));
+ toast(i18n.t(msg.error), 'danger');
return;
} else if (res.op == UserOperation.GetModlog) {
let data = res.data as GetModlogResponse;
diff --git a/ui/src/components/navbar.tsx b/ui/src/components/navbar.ts