mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-12-22 19:01:26 +00:00
Add post, inbox, and user routes.
This commit is contained in:
parent
bfce461a14
commit
95b74ad74c
10 changed files with 509 additions and 512 deletions
|
@ -202,7 +202,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
}}
|
||||
/>
|
||||
<span class="mx-2">•</span>
|
||||
<Link class="mr-2" to={`/post/${node.comment.post_id}`}>
|
||||
<Link className="mr-2" to={`/post/${node.comment.post_id}`}>
|
||||
{node.comment.post_name}
|
||||
</Link>
|
||||
</>
|
||||
|
@ -343,7 +343,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{!this.myComment && (
|
||||
<button class="btn btn-link btn-animate">
|
||||
<Link
|
||||
class="text-muted"
|
||||
className="text-muted"
|
||||
to={`/create_private_message/recipient/${node.comment.creator_id}`}
|
||||
title={i18n.t('message').toLowerCase()}
|
||||
>
|
||||
|
@ -757,7 +757,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
let node = this.props.node;
|
||||
return (
|
||||
<Link
|
||||
class="btn btn-link btn-animate text-muted"
|
||||
className="btn btn-link btn-animate text-muted"
|
||||
to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}
|
||||
title={this.props.showContext ? i18n.t('show_context') : i18n.t('link')}
|
||||
>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Component, linkEvent } from 'inferno';
|
||||
import { Helmet } from 'inferno-helmet';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
||||
import {
|
||||
UserOperation,
|
||||
Comment,
|
||||
|
@ -17,7 +16,6 @@ import {
|
|||
GetPrivateMessagesForm,
|
||||
PrivateMessagesResponse,
|
||||
PrivateMessageResponse,
|
||||
GetSiteResponse,
|
||||
Site,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
|
@ -31,6 +29,11 @@ import {
|
|||
createCommentLikeRes,
|
||||
commentsToFlatNodes,
|
||||
setupTippy,
|
||||
setIsoData,
|
||||
wsSubscribe,
|
||||
lemmyHttp,
|
||||
setAuth,
|
||||
isBrowser,
|
||||
} from '../utils';
|
||||
import { CommentNodes } from './comment-nodes';
|
||||
import { PrivateMessage } from './private-message';
|
||||
|
@ -60,9 +63,11 @@ interface InboxState {
|
|||
sort: SortType;
|
||||
page: number;
|
||||
site: Site;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export class Inbox extends Component<any, InboxState> {
|
||||
private isoData = setIsoData(this.context);
|
||||
private subscription: Subscription;
|
||||
private emptyState: InboxState = {
|
||||
unreadOrAll: UnreadOrAll.Unread,
|
||||
|
@ -72,20 +77,8 @@ export class Inbox extends Component<any, InboxState> {
|
|||
messages: [],
|
||||
sort: SortType.New,
|
||||
page: 1,
|
||||
site: {
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
creator_id: undefined,
|
||||
published: undefined,
|
||||
creator_name: undefined,
|
||||
number_of_users: undefined,
|
||||
number_of_posts: undefined,
|
||||
number_of_comments: undefined,
|
||||
number_of_communities: undefined,
|
||||
enable_downvotes: undefined,
|
||||
open_registration: undefined,
|
||||
enable_nsfw: undefined,
|
||||
},
|
||||
site: this.isoData.site.site,
|
||||
loading: true,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
|
@ -94,77 +87,88 @@ export class Inbox extends Component<any, InboxState> {
|
|||
this.state = this.emptyState;
|
||||
this.handleSortChange = this.handleSortChange.bind(this);
|
||||
|
||||
this.subscription = WebSocketService.Instance.subject
|
||||
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
|
||||
.subscribe(
|
||||
msg => this.parseMessage(msg),
|
||||
err => console.error(err),
|
||||
() => console.log('complete')
|
||||
);
|
||||
this.parseMessage = this.parseMessage.bind(this);
|
||||
this.subscription = wsSubscribe(this.parseMessage);
|
||||
|
||||
this.refetch();
|
||||
WebSocketService.Instance.getSite();
|
||||
// Only fetch the data if coming from another route
|
||||
if (this.isoData.path == this.context.router.route.match.url) {
|
||||
this.state.replies = this.isoData.routeData[0].replies;
|
||||
this.state.mentions = this.isoData.routeData[1].mentions;
|
||||
this.state.messages = this.isoData.routeData[2].messages;
|
||||
this.sendUnreadCount();
|
||||
this.state.loading = false;
|
||||
} else {
|
||||
this.refetch();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.subscription.unsubscribe();
|
||||
if (isBrowser()) {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
if (this.state.site.name) {
|
||||
return `@${UserService.Instance.user.name} ${i18n.t('inbox')} - ${
|
||||
this.state.site.name
|
||||
}`;
|
||||
} else {
|
||||
return 'Lemmy';
|
||||
}
|
||||
return `@${UserService.Instance.user.name} ${i18n.t('inbox')} - ${
|
||||
this.state.site.name
|
||||
}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div class="container">
|
||||
<Helmet title={this.documentTitle} />
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h5 class="mb-1">
|
||||
{i18n.t('inbox')}
|
||||
<small>
|
||||
<a
|
||||
href={`/feeds/inbox/${UserService.Instance.auth}.xml`}
|
||||
target="_blank"
|
||||
title="RSS"
|
||||
rel="noopener"
|
||||
>
|
||||
<svg class="icon ml-2 text-muted small">
|
||||
<use xlinkHref="#icon-rss">#</use>
|
||||
</svg>
|
||||
</a>
|
||||
</small>
|
||||
</h5>
|
||||
{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">
|
||||
<span
|
||||
class="pointer"
|
||||
onClick={linkEvent(this, this.markAllAsRead)}
|
||||
>
|
||||
{i18n.t('mark_all_as_read')}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
)}
|
||||
{this.selects()}
|
||||
{this.state.messageType == MessageType.All && this.all()}
|
||||
{this.state.messageType == MessageType.Replies && this.replies()}
|
||||
{this.state.messageType == MessageType.Mentions && this.mentions()}
|
||||
{this.state.messageType == MessageType.Messages && this.messages()}
|
||||
{this.paginator()}
|
||||
{this.state.loading ? (
|
||||
<h5>
|
||||
<svg class="icon icon-spinner spin">
|
||||
<use xlinkHref="#icon-spinner"></use>
|
||||
</svg>
|
||||
</h5>
|
||||
) : (
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h5 class="mb-1">
|
||||
{i18n.t('inbox')}
|
||||
<small>
|
||||
<a
|
||||
href={`/feeds/inbox/${UserService.Instance.auth}.xml`}
|
||||
target="_blank"
|
||||
title="RSS"
|
||||
rel="noopener"
|
||||
>
|
||||
<svg class="icon ml-2 text-muted small">
|
||||
<use xlinkHref="#icon-rss">#</use>
|
||||
</svg>
|
||||
</a>
|
||||
</small>
|
||||
</h5>
|
||||
{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">
|
||||
<span
|
||||
class="pointer"
|
||||
onClick={linkEvent(this, this.markAllAsRead)}
|
||||
>
|
||||
{i18n.t('mark_all_as_read')}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
)}
|
||||
{this.selects()}
|
||||
{this.state.messageType == MessageType.All && this.all()}
|
||||
{this.state.messageType == MessageType.Replies && this.replies()}
|
||||
{this.state.messageType == MessageType.Mentions &&
|
||||
this.mentions()}
|
||||
{this.state.messageType == MessageType.Messages &&
|
||||
this.messages()}
|
||||
{this.paginator()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -397,6 +401,39 @@ export class Inbox extends Component<any, InboxState> {
|
|||
i.refetch();
|
||||
}
|
||||
|
||||
static fetchInitialData(auth: string, _path: string): Promise<any>[] {
|
||||
let promises: Promise<any>[] = [];
|
||||
|
||||
// It can be /u/me, or /username/1
|
||||
let repliesForm: GetRepliesForm = {
|
||||
sort: SortType.New,
|
||||
unread_only: true,
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
};
|
||||
setAuth(repliesForm, auth);
|
||||
promises.push(lemmyHttp.getReplies(repliesForm));
|
||||
|
||||
let userMentionsForm: GetUserMentionsForm = {
|
||||
sort: SortType.New,
|
||||
unread_only: true,
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
};
|
||||
setAuth(userMentionsForm, auth);
|
||||
promises.push(lemmyHttp.getUserMentions(userMentionsForm));
|
||||
|
||||
let privateMessagesForm: GetPrivateMessagesForm = {
|
||||
unread_only: true,
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
};
|
||||
setAuth(privateMessagesForm, auth);
|
||||
promises.push(lemmyHttp.getPrivateMessages(privateMessagesForm));
|
||||
|
||||
return promises;
|
||||
}
|
||||
|
||||
refetch() {
|
||||
let repliesForm: GetRepliesForm = {
|
||||
sort: this.state.sort,
|
||||
|
@ -450,6 +487,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
} else if (res.op == UserOperation.GetReplies) {
|
||||
let data = res.data as GetRepliesResponse;
|
||||
this.state.replies = data.replies;
|
||||
this.state.loading = false;
|
||||
this.sendUnreadCount();
|
||||
window.scrollTo(0, 0);
|
||||
this.setState(this.state);
|
||||
|
@ -581,10 +619,6 @@ export class Inbox extends Component<any, InboxState> {
|
|||
let data = res.data as CommentResponse;
|
||||
createCommentLikeRes(data, this.state.replies);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.GetSite) {
|
||||
let data = res.data as GetSiteResponse;
|
||||
this.state.site = data.site;
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
}
|
||||
}
|
||||
|
||||
this.parseMessage = this.parseMessage.bind(this);
|
||||
this.subscription = wsSubscribe(this.parseMessage);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
AddAdminForm,
|
||||
TransferSiteForm,
|
||||
TransferCommunityForm,
|
||||
Community,
|
||||
} from 'lemmy-js-client';
|
||||
import { BanType } from '../interfaces';
|
||||
import { MomentTime } from './moment-time';
|
||||
|
@ -61,6 +62,7 @@ interface PostListingState {
|
|||
|
||||
interface PostListingProps {
|
||||
post: Post;
|
||||
communities: Community[];
|
||||
showCommunity?: boolean;
|
||||
showBody?: boolean;
|
||||
moderators?: CommunityUser[];
|
||||
|
@ -127,6 +129,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
onCancel={this.handleEditCancel}
|
||||
enableNsfw={this.props.enableNsfw}
|
||||
enableDownvotes={this.props.enableDownvotes}
|
||||
communities={this.props.communities}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
@ -184,6 +187,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
} else if (post.thumbnail_url) {
|
||||
return pictrsImage(post.thumbnail_url, thumbnail);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -598,7 +603,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
</li>
|
||||
<li className="list-inline-item">
|
||||
<Link
|
||||
class="btn btn-link btn-animate text-muted"
|
||||
className="btn btn-link btn-animate text-muted"
|
||||
to={`/create_post${this.crossPostParams}`}
|
||||
title={i18n.t('cross_post')}
|
||||
>
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
import { Component, linkEvent } from 'inferno';
|
||||
import { Helmet } from 'inferno-helmet';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
||||
import {
|
||||
UserOperation,
|
||||
Community,
|
||||
Post as PostI,
|
||||
GetPostResponse,
|
||||
PostResponse,
|
||||
Comment,
|
||||
MarkCommentAsReadForm,
|
||||
CommentResponse,
|
||||
CommunityUser,
|
||||
CommunityResponse,
|
||||
CommentNode as CommentNodeI,
|
||||
BanFromCommunityResponse,
|
||||
|
@ -26,6 +22,8 @@ import {
|
|||
GetSiteResponse,
|
||||
GetCommunityResponse,
|
||||
WebSocketJsonResponse,
|
||||
ListCategoriesResponse,
|
||||
Category,
|
||||
} from 'lemmy-js-client';
|
||||
import { CommentSortType, CommentViewType } from '../interfaces';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
|
@ -39,6 +37,13 @@ import {
|
|||
commentsToFlatNodes,
|
||||
setupTippy,
|
||||
favIconUrl,
|
||||
setIsoData,
|
||||
getIdFromProps,
|
||||
getCommentIdFromProps,
|
||||
wsSubscribe,
|
||||
setAuth,
|
||||
lemmyHttp,
|
||||
isBrowser,
|
||||
} from '../utils';
|
||||
import { PostListing } from './post-listing';
|
||||
import { Sidebar } from './sidebar';
|
||||
|
@ -48,56 +53,32 @@ import autosize from 'autosize';
|
|||
import { i18n } from '../i18next';
|
||||
|
||||
interface PostState {
|
||||
post: PostI;
|
||||
comments: Comment[];
|
||||
postRes: GetPostResponse;
|
||||
postId: number;
|
||||
commentId?: number;
|
||||
commentSort: CommentSortType;
|
||||
commentViewType: CommentViewType;
|
||||
community: Community;
|
||||
moderators: CommunityUser[];
|
||||
online: number;
|
||||
scrolled?: boolean;
|
||||
scrolled_comment_id?: number;
|
||||
loading: boolean;
|
||||
crossPosts: PostI[];
|
||||
siteRes: GetSiteResponse;
|
||||
categories: Category[];
|
||||
}
|
||||
|
||||
export class Post extends Component<any, PostState> {
|
||||
private subscription: Subscription;
|
||||
private isoData = setIsoData(this.context);
|
||||
private emptyState: PostState = {
|
||||
post: null,
|
||||
comments: [],
|
||||
postRes: null,
|
||||
postId: getIdFromProps(this.props),
|
||||
commentId: getCommentIdFromProps(this.props),
|
||||
commentSort: CommentSortType.Hot,
|
||||
commentViewType: CommentViewType.Tree,
|
||||
community: null,
|
||||
moderators: [],
|
||||
online: null,
|
||||
scrolled: false,
|
||||
loading: true,
|
||||
crossPosts: [],
|
||||
siteRes: {
|
||||
admins: [],
|
||||
banned: [],
|
||||
site: {
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
creator_id: undefined,
|
||||
published: undefined,
|
||||
creator_name: undefined,
|
||||
number_of_users: undefined,
|
||||
number_of_posts: undefined,
|
||||
number_of_comments: undefined,
|
||||
number_of_communities: undefined,
|
||||
enable_downvotes: undefined,
|
||||
open_registration: undefined,
|
||||
enable_nsfw: undefined,
|
||||
icon: undefined,
|
||||
banner: undefined,
|
||||
},
|
||||
online: null,
|
||||
version: null,
|
||||
federated_instances: undefined,
|
||||
},
|
||||
siteRes: this.isoData.site,
|
||||
categories: [],
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
|
@ -105,24 +86,46 @@ export class Post extends Component<any, PostState> {
|
|||
|
||||
this.state = this.emptyState;
|
||||
|
||||
let postId = Number(this.props.match.params.id);
|
||||
if (this.props.match.params.comment_id) {
|
||||
this.state.scrolled_comment_id = this.props.match.params.comment_id;
|
||||
this.parseMessage = this.parseMessage.bind(this);
|
||||
this.subscription = wsSubscribe(this.parseMessage);
|
||||
|
||||
// Only fetch the data if coming from another route
|
||||
if (this.isoData.path == this.context.router.route.match.url) {
|
||||
this.state.postRes = this.isoData.routeData[0];
|
||||
this.state.categories = this.isoData.routeData[1].categories;
|
||||
this.state.loading = false;
|
||||
|
||||
if (isBrowser() && this.state.commentId) {
|
||||
this.scrollCommentIntoView();
|
||||
}
|
||||
} else {
|
||||
this.fetchPost();
|
||||
WebSocketService.Instance.listCategories();
|
||||
}
|
||||
}
|
||||
|
||||
this.subscription = WebSocketService.Instance.subject
|
||||
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
|
||||
.subscribe(
|
||||
msg => this.parseMessage(msg),
|
||||
err => console.error(err),
|
||||
() => console.log('complete')
|
||||
);
|
||||
|
||||
fetchPost() {
|
||||
let form: GetPostForm = {
|
||||
id: postId,
|
||||
id: this.state.postId,
|
||||
};
|
||||
WebSocketService.Instance.getPost(form);
|
||||
WebSocketService.Instance.getSite();
|
||||
}
|
||||
|
||||
static fetchInitialData(auth: string, path: string): Promise<any>[] {
|
||||
let pathSplit = path.split('/');
|
||||
let promises: Promise<any>[] = [];
|
||||
|
||||
let id = Number(pathSplit[2]);
|
||||
|
||||
let postForm: GetPostForm = {
|
||||
id,
|
||||
};
|
||||
setAuth(postForm, auth);
|
||||
|
||||
promises.push(lemmyHttp.getPost(postForm));
|
||||
promises.push(lemmyHttp.listCategories());
|
||||
|
||||
return promises;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -135,17 +138,12 @@ export class Post extends Component<any, PostState> {
|
|||
|
||||
componentDidUpdate(_lastProps: any, lastState: PostState, _snapshot: any) {
|
||||
if (
|
||||
this.state.scrolled_comment_id &&
|
||||
this.state.commentId &&
|
||||
!this.state.scrolled &&
|
||||
lastState.comments.length > 0
|
||||
lastState.postRes &&
|
||||
lastState.postRes.comments.length > 0
|
||||
) {
|
||||
var elmnt = document.getElementById(
|
||||
`comment-${this.state.scrolled_comment_id}`
|
||||
);
|
||||
elmnt.scrollIntoView();
|
||||
elmnt.classList.add('mark');
|
||||
this.state.scrolled = true;
|
||||
this.markScrolledAsRead(this.state.scrolled_comment_id);
|
||||
this.scrollCommentIntoView();
|
||||
}
|
||||
|
||||
// Necessary if you are on a post and you click another post (same route)
|
||||
|
@ -161,12 +159,20 @@ export class Post extends Component<any, PostState> {
|
|||
}
|
||||
}
|
||||
|
||||
scrollCommentIntoView() {
|
||||
var elmnt = document.getElementById(`comment-${this.state.commentId}`);
|
||||
elmnt.scrollIntoView();
|
||||
elmnt.classList.add('mark');
|
||||
this.state.scrolled = true;
|
||||
this.markScrolledAsRead(this.state.commentId);
|
||||
}
|
||||
|
||||
markScrolledAsRead(commentId: number) {
|
||||
let found = this.state.comments.find(c => c.id == commentId);
|
||||
let parent = this.state.comments.find(c => found.parent_id == c.id);
|
||||
let found = this.state.postRes.comments.find(c => c.id == commentId);
|
||||
let parent = this.state.postRes.comments.find(c => found.parent_id == c.id);
|
||||
let parent_user_id = parent
|
||||
? parent.creator_id
|
||||
: this.state.post.creator_id;
|
||||
: this.state.postRes.post.creator_id;
|
||||
|
||||
if (
|
||||
UserService.Instance.user &&
|
||||
|
@ -185,8 +191,8 @@ export class Post extends Component<any, PostState> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
if (this.state.post) {
|
||||
return `${this.state.post.name} - ${this.state.siteRes.site.name}`;
|
||||
if (this.state.postRes) {
|
||||
return `${this.state.postRes.post.name} - ${this.state.siteRes.site.name}`;
|
||||
} else {
|
||||
return 'Lemmy';
|
||||
}
|
||||
|
@ -219,20 +225,21 @@ export class Post extends Component<any, PostState> {
|
|||
<div class="row">
|
||||
<div class="col-12 col-md-8 mb-3">
|
||||
<PostListing
|
||||
post={this.state.post}
|
||||
communities={[this.state.postRes.community]}
|
||||
post={this.state.postRes.post}
|
||||
showBody
|
||||
showCommunity
|
||||
moderators={this.state.moderators}
|
||||
moderators={this.state.postRes.moderators}
|
||||
admins={this.state.siteRes.admins}
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
enableNsfw={this.state.siteRes.site.enable_nsfw}
|
||||
/>
|
||||
<div className="mb-2" />
|
||||
<CommentForm
|
||||
postId={this.state.post.id}
|
||||
disabled={this.state.post.locked}
|
||||
postId={this.state.postId}
|
||||
disabled={this.state.postRes.post.locked}
|
||||
/>
|
||||
{this.state.comments.length > 0 && this.sortRadios()}
|
||||
{this.state.postRes.comments.length > 0 && this.sortRadios()}
|
||||
{this.state.commentViewType == CommentViewType.Tree &&
|
||||
this.commentsTree()}
|
||||
{this.state.commentViewType == CommentViewType.Chat &&
|
||||
|
@ -325,12 +332,12 @@ export class Post extends Component<any, PostState> {
|
|||
return (
|
||||
<div>
|
||||
<CommentNodes
|
||||
nodes={commentsToFlatNodes(this.state.comments)}
|
||||
nodes={commentsToFlatNodes(this.state.postRes.comments)}
|
||||
noIndent
|
||||
locked={this.state.post.locked}
|
||||
moderators={this.state.moderators}
|
||||
locked={this.state.postRes.post.locked}
|
||||
moderators={this.state.postRes.moderators}
|
||||
admins={this.state.siteRes.admins}
|
||||
postCreatorId={this.state.post.creator_id}
|
||||
postCreatorId={this.state.postRes.post.creator_id}
|
||||
showContext
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
sort={this.state.commentSort}
|
||||
|
@ -343,12 +350,13 @@ export class Post extends Component<any, PostState> {
|
|||
return (
|
||||
<div class="mb-3">
|
||||
<Sidebar
|
||||
community={this.state.community}
|
||||
moderators={this.state.moderators}
|
||||
community={this.state.postRes.community}
|
||||
moderators={this.state.postRes.moderators}
|
||||
admins={this.state.siteRes.admins}
|
||||
online={this.state.online}
|
||||
online={this.state.postRes.online}
|
||||
enableNsfw={this.state.siteRes.site.enable_nsfw}
|
||||
showIcon
|
||||
categories={this.state.categories}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -368,7 +376,7 @@ export class Post extends Component<any, PostState> {
|
|||
|
||||
buildCommentsTree(): CommentNodeI[] {
|
||||
let map = new Map<number, CommentNodeI>();
|
||||
for (let comment of this.state.comments) {
|
||||
for (let comment of this.state.postRes.comments) {
|
||||
let node: CommentNodeI = {
|
||||
comment: comment,
|
||||
children: [],
|
||||
|
@ -376,7 +384,7 @@ export class Post extends Component<any, PostState> {
|
|||
map.set(comment.id, { ...node });
|
||||
}
|
||||
let tree: CommentNodeI[] = [];
|
||||
for (let comment of this.state.comments) {
|
||||
for (let comment of this.state.postRes.comments) {
|
||||
let child = map.get(comment.id);
|
||||
if (comment.parent_id) {
|
||||
let parent_ = map.get(comment.parent_id);
|
||||
|
@ -404,10 +412,10 @@ export class Post extends Component<any, PostState> {
|
|||
<div>
|
||||
<CommentNodes
|
||||
nodes={nodes}
|
||||
locked={this.state.post.locked}
|
||||
moderators={this.state.moderators}
|
||||
locked={this.state.postRes.post.locked}
|
||||
moderators={this.state.postRes.moderators}
|
||||
admins={this.state.siteRes.admins}
|
||||
postCreatorId={this.state.post.creator_id}
|
||||
postCreatorId={this.state.postRes.post.creator_id}
|
||||
sort={this.state.commentSort}
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
/>
|
||||
|
@ -427,17 +435,13 @@ export class Post extends Component<any, PostState> {
|
|||
});
|
||||
} else if (res.op == UserOperation.GetPost) {
|
||||
let data = res.data as GetPostResponse;
|
||||
this.state.post = data.post;
|
||||
this.state.comments = data.comments;
|
||||
this.state.community = data.community;
|
||||
this.state.moderators = data.moderators;
|
||||
this.state.online = data.online;
|
||||
this.state.postRes = data;
|
||||
this.state.loading = false;
|
||||
|
||||
// Get cross-posts
|
||||
if (this.state.post.url) {
|
||||
if (this.state.postRes.post.url) {
|
||||
let form: SearchForm = {
|
||||
q: this.state.post.url,
|
||||
q: this.state.postRes.post.url,
|
||||
type_: SearchType.Url,
|
||||
sort: SortType.TopAll,
|
||||
page: 1,
|
||||
|
@ -453,7 +457,7 @@ export class Post extends Component<any, PostState> {
|
|||
|
||||
// Necessary since it might be a user reply
|
||||
if (data.recipient_ids.length == 0) {
|
||||
this.state.comments.unshift(data.comment);
|
||||
this.state.postRes.comments.unshift(data.comment);
|
||||
this.setState(this.state);
|
||||
}
|
||||
} else if (
|
||||
|
@ -462,20 +466,20 @@ export class Post extends Component<any, PostState> {
|
|||
res.op == UserOperation.RemoveComment
|
||||
) {
|
||||
let data = res.data as CommentResponse;
|
||||
editCommentRes(data, this.state.comments);
|
||||
editCommentRes(data, this.state.postRes.comments);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.SaveComment) {
|
||||
let data = res.data as CommentResponse;
|
||||
saveCommentRes(data, this.state.comments);
|
||||
saveCommentRes(data, this.state.postRes.comments);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (res.op == UserOperation.CreateCommentLike) {
|
||||
let data = res.data as CommentResponse;
|
||||
createCommentLikeRes(data, this.state.comments);
|
||||
createCommentLikeRes(data, this.state.postRes.comments);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreatePostLike) {
|
||||
let data = res.data as PostResponse;
|
||||
createPostLikeRes(data, this.state.post);
|
||||
createPostLikeRes(data, this.state.postRes.post);
|
||||
this.setState(this.state);
|
||||
} else if (
|
||||
res.op == UserOperation.EditPost ||
|
||||
|
@ -485,12 +489,12 @@ export class Post extends Component<any, PostState> {
|
|||
res.op == UserOperation.StickyPost
|
||||
) {
|
||||
let data = res.data as PostResponse;
|
||||
this.state.post = data.post;
|
||||
this.state.postRes.post = data.post;
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (res.op == UserOperation.SavePost) {
|
||||
let data = res.data as PostResponse;
|
||||
this.state.post = data.post;
|
||||
this.state.postRes.post = data.post;
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (
|
||||
|
@ -499,36 +503,36 @@ export class Post extends Component<any, PostState> {
|
|||
res.op == UserOperation.RemoveCommunity
|
||||
) {
|
||||
let data = res.data as CommunityResponse;
|
||||
this.state.community = data.community;
|
||||
this.state.post.community_id = data.community.id;
|
||||
this.state.post.community_name = data.community.name;
|
||||
this.state.postRes.community = data.community;
|
||||
this.state.postRes.post.community_id = data.community.id;
|
||||
this.state.postRes.post.community_name = data.community.name;
|
||||
this.setState(this.state);
|
||||
} 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 =
|
||||
this.state.postRes.community.subscribed = data.community.subscribed;
|
||||
this.state.postRes.community.number_of_subscribers =
|
||||
data.community.number_of_subscribers;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.BanFromCommunity) {
|
||||
let data = res.data as BanFromCommunityResponse;
|
||||
this.state.comments
|
||||
this.state.postRes.comments
|
||||
.filter(c => c.creator_id == data.user.id)
|
||||
.forEach(c => (c.banned_from_community = data.banned));
|
||||
if (this.state.post.creator_id == data.user.id) {
|
||||
this.state.post.banned_from_community = data.banned;
|
||||
if (this.state.postRes.post.creator_id == data.user.id) {
|
||||
this.state.postRes.post.banned_from_community = data.banned;
|
||||
}
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.AddModToCommunity) {
|
||||
let data = res.data as AddModToCommunityResponse;
|
||||
this.state.moderators = data.moderators;
|
||||
this.state.postRes.moderators = data.moderators;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.BanUser) {
|
||||
let data = res.data as BanUserResponse;
|
||||
this.state.comments
|
||||
this.state.postRes.comments
|
||||
.filter(c => c.creator_id == data.user.id)
|
||||
.forEach(c => (c.banned = data.banned));
|
||||
if (this.state.post.creator_id == data.user.id) {
|
||||
this.state.post.banned = data.banned;
|
||||
if (this.state.postRes.post.creator_id == data.user.id) {
|
||||
this.state.postRes.post.banned = data.banned;
|
||||
}
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.AddAdmin) {
|
||||
|
@ -541,20 +545,21 @@ export class Post extends Component<any, PostState> {
|
|||
p => p.id != Number(this.props.match.params.id)
|
||||
);
|
||||
if (this.state.crossPosts.length) {
|
||||
this.state.post.duplicates = this.state.crossPosts;
|
||||
this.state.postRes.post.duplicates = this.state.crossPosts;
|
||||
}
|
||||
this.setState(this.state);
|
||||
} else if (
|
||||
res.op == UserOperation.TransferSite ||
|
||||
res.op == UserOperation.GetSite
|
||||
) {
|
||||
} else if (res.op == UserOperation.TransferSite) {
|
||||
let data = res.data as GetSiteResponse;
|
||||
this.state.siteRes = data;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.TransferCommunity) {
|
||||
let data = res.data as GetCommunityResponse;
|
||||
this.state.community = data.community;
|
||||
this.state.moderators = data.moderators;
|
||||
this.state.postRes.community = data.community;
|
||||
this.state.postRes.moderators = data.moderators;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.ListCategories) {
|
||||
let data = res.data as ListCategoriesResponse;
|
||||
this.state.categories = data.categories;
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,13 @@
|
|||
import { Component, linkEvent } from 'inferno';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
||||
import { i18n } from '../i18next';
|
||||
import {
|
||||
UserOperation,
|
||||
Post,
|
||||
Comment,
|
||||
CommunityUser,
|
||||
SortType,
|
||||
UserDetailsResponse,
|
||||
UserView,
|
||||
WebSocketJsonResponse,
|
||||
CommentResponse,
|
||||
BanUserResponse,
|
||||
PostResponse,
|
||||
} from 'lemmy-js-client';
|
||||
import { Post, Comment, SortType, UserDetailsResponse } from 'lemmy-js-client';
|
||||
import { UserDetailsView } from '../interfaces';
|
||||
import {
|
||||
wsJsonToRes,
|
||||
toast,
|
||||
commentsToFlatNodes,
|
||||
setupTippy,
|
||||
editCommentRes,
|
||||
saveCommentRes,
|
||||
createCommentLikeRes,
|
||||
createPostLikeFindRes,
|
||||
} from '../utils';
|
||||
import { commentsToFlatNodes, setupTippy } from '../utils';
|
||||
import { PostListing } from './post-listing';
|
||||
import { CommentNodes } from './comment-nodes';
|
||||
|
||||
interface UserDetailsProps {
|
||||
username?: string;
|
||||
user_id?: number;
|
||||
userRes: UserDetailsResponse;
|
||||
page: number;
|
||||
limit: number;
|
||||
sort: SortType;
|
||||
|
@ -40,67 +15,29 @@ interface UserDetailsProps {
|
|||
enableNsfw: boolean;
|
||||
view: UserDetailsView;
|
||||
onPageChange(page: number): number | any;
|
||||
admins: UserView[];
|
||||
}
|
||||
|
||||
interface UserDetailsState {
|
||||
follows: CommunityUser[];
|
||||
moderates: CommunityUser[];
|
||||
comments: Comment[];
|
||||
posts: Post[];
|
||||
saved?: Post[];
|
||||
}
|
||||
interface UserDetailsState {}
|
||||
|
||||
export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
||||
private subscription: Subscription;
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
follows: [],
|
||||
moderates: [],
|
||||
comments: [],
|
||||
posts: [],
|
||||
saved: [],
|
||||
};
|
||||
|
||||
this.subscription = WebSocketService.Instance.subject
|
||||
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
|
||||
.subscribe(
|
||||
msg => this.parseMessage(msg),
|
||||
err => console.error(err),
|
||||
() => console.log('complete')
|
||||
);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
|
||||
// TODO needed here?
|
||||
componentDidMount() {
|
||||
this.fetchUserData();
|
||||
setupTippy();
|
||||
}
|
||||
|
||||
componentDidUpdate(lastProps: UserDetailsProps) {
|
||||
for (const key of Object.keys(lastProps)) {
|
||||
if (lastProps[key] !== this.props[key]) {
|
||||
this.fetchUserData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetchUserData() {
|
||||
WebSocketService.Instance.getUserDetails({
|
||||
user_id: this.props.user_id,
|
||||
username: this.props.username,
|
||||
sort: this.props.sort,
|
||||
saved_only: this.props.view === UserDetailsView.Saved,
|
||||
page: this.props.page,
|
||||
limit: this.props.limit,
|
||||
});
|
||||
}
|
||||
// TODO wut?
|
||||
// componentDidUpdate(lastProps: UserDetailsProps) {
|
||||
// for (const key of Object.keys(lastProps)) {
|
||||
// if (lastProps[key] !== this.props[key]) {
|
||||
// this.fetchUserData();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
render() {
|
||||
return (
|
||||
|
@ -114,20 +51,20 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
|||
viewSelector(view: UserDetailsView) {
|
||||
if (view === UserDetailsView.Overview || view === UserDetailsView.Saved) {
|
||||
return this.overview();
|
||||
}
|
||||
if (view === UserDetailsView.Comments) {
|
||||
} else if (view === UserDetailsView.Comments) {
|
||||
return this.comments();
|
||||
}
|
||||
if (view === UserDetailsView.Posts) {
|
||||
} else if (view === UserDetailsView.Posts) {
|
||||
return this.posts();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
overview() {
|
||||
const comments = this.state.comments.map((c: Comment) => {
|
||||
const comments = this.props.userRes.comments.map((c: Comment) => {
|
||||
return { type: 'comments', data: c };
|
||||
});
|
||||
const posts = this.state.posts.map((p: Post) => {
|
||||
const posts = this.props.userRes.posts.map((p: Post) => {
|
||||
return { type: 'posts', data: p };
|
||||
});
|
||||
|
||||
|
@ -150,9 +87,10 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
|||
<div>
|
||||
{i.type === 'posts' ? (
|
||||
<PostListing
|
||||
communities={[]}
|
||||
key={(i.data as Post).id}
|
||||
post={i.data as Post}
|
||||
admins={this.props.admins}
|
||||
admins={this.props.userRes.admins}
|
||||
showCommunity
|
||||
enableDownvotes={this.props.enableDownvotes}
|
||||
enableNsfw={this.props.enableNsfw}
|
||||
|
@ -161,7 +99,7 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
|||
<CommentNodes
|
||||
key={(i.data as Comment).id}
|
||||
nodes={[{ comment: i.data as Comment }]}
|
||||
admins={this.props.admins}
|
||||
admins={this.props.userRes.admins}
|
||||
noBorder
|
||||
noIndent
|
||||
showCommunity
|
||||
|
@ -181,8 +119,8 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
|||
return (
|
||||
<div>
|
||||
<CommentNodes
|
||||
nodes={commentsToFlatNodes(this.state.comments)}
|
||||
admins={this.props.admins}
|
||||
nodes={commentsToFlatNodes(this.props.userRes.comments)}
|
||||
admins={this.props.userRes.admins}
|
||||
noIndent
|
||||
showCommunity
|
||||
showContext
|
||||
|
@ -195,11 +133,12 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
|||
posts() {
|
||||
return (
|
||||
<div>
|
||||
{this.state.posts.map(post => (
|
||||
{this.props.userRes.posts.map(post => (
|
||||
<>
|
||||
<PostListing
|
||||
communities={[]}
|
||||
post={post}
|
||||
admins={this.props.admins}
|
||||
admins={this.props.userRes.admins}
|
||||
showCommunity
|
||||
enableDownvotes={this.props.enableDownvotes}
|
||||
enableNsfw={this.props.enableNsfw}
|
||||
|
@ -222,7 +161,8 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
|||
{i18n.t('prev')}
|
||||
</button>
|
||||
)}
|
||||
{this.state.comments.length + this.state.posts.length > 0 && (
|
||||
{this.props.userRes.comments.length + this.props.userRes.posts.length >
|
||||
0 && (
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
onClick={linkEvent(this, this.nextPage)}
|
||||
|
@ -241,75 +181,4 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
|||
prevPage(i: UserDetails) {
|
||||
i.props.onPageChange(i.props.page - 1);
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
console.log(msg);
|
||||
const res = wsJsonToRes(msg);
|
||||
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
if (msg.error == 'couldnt_find_that_username_or_email') {
|
||||
this.context.router.history.push('/');
|
||||
}
|
||||
return;
|
||||
} else if (msg.reconnect) {
|
||||
this.fetchUserData();
|
||||
} else if (res.op == UserOperation.GetUserDetails) {
|
||||
const data = res.data as UserDetailsResponse;
|
||||
this.setState({
|
||||
comments: data.comments,
|
||||
follows: data.follows,
|
||||
moderates: data.moderates,
|
||||
posts: data.posts,
|
||||
});
|
||||
} else if (res.op == UserOperation.CreateCommentLike) {
|
||||
const data = res.data as CommentResponse;
|
||||
createCommentLikeRes(data, this.state.comments);
|
||||
this.setState({
|
||||
comments: this.state.comments,
|
||||
});
|
||||
} else if (
|
||||
res.op == UserOperation.EditComment ||
|
||||
res.op == UserOperation.DeleteComment ||
|
||||
res.op == UserOperation.RemoveComment
|
||||
) {
|
||||
const data = res.data as CommentResponse;
|
||||
editCommentRes(data, this.state.comments);
|
||||
this.setState({
|
||||
comments: this.state.comments,
|
||||
});
|
||||
} else if (res.op == UserOperation.CreateComment) {
|
||||
const data = res.data as CommentResponse;
|
||||
if (
|
||||
UserService.Instance.user &&
|
||||
data.comment.creator_id == UserService.Instance.user.id
|
||||
) {
|
||||
toast(i18n.t('reply_sent'));
|
||||
}
|
||||
} else if (res.op == UserOperation.SaveComment) {
|
||||
const data = res.data as CommentResponse;
|
||||
saveCommentRes(data, this.state.comments);
|
||||
this.setState({
|
||||
comments: this.state.comments,
|
||||
});
|
||||
} else if (res.op == UserOperation.CreatePostLike) {
|
||||
const data = res.data as PostResponse;
|
||||
createPostLikeFindRes(data, this.state.posts);
|
||||
this.setState({
|
||||
posts: this.state.posts,
|
||||
});
|
||||
} else if (res.op == UserOperation.BanUser) {
|
||||
const data = res.data as BanUserResponse;
|
||||
this.state.comments
|
||||
.filter(c => c.creator_id == data.user.id)
|
||||
.forEach(c => (c.banned = data.banned));
|
||||
this.state.posts
|
||||
.filter(c => c.creator_id == data.user.id)
|
||||
.forEach(c => (c.banned = data.banned));
|
||||
this.setState({
|
||||
posts: this.state.posts,
|
||||
comments: this.state.comments,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,10 @@ import { Component, linkEvent } from 'inferno';
|
|||
import { Helmet } from 'inferno-helmet';
|
||||
import { Link } from 'inferno-router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
||||
import {
|
||||
UserOperation,
|
||||
CommunityUser,
|
||||
SortType,
|
||||
ListingType,
|
||||
UserView,
|
||||
UserSettingsForm,
|
||||
LoginResponse,
|
||||
DeleteAccountForm,
|
||||
|
@ -16,6 +13,10 @@ import {
|
|||
GetSiteResponse,
|
||||
UserDetailsResponse,
|
||||
AddAdminResponse,
|
||||
GetUserDetailsForm,
|
||||
CommentResponse,
|
||||
PostResponse,
|
||||
BanUserResponse,
|
||||
} from 'lemmy-js-client';
|
||||
import { UserDetailsView } from '../interfaces';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
|
@ -33,6 +34,16 @@ import {
|
|||
mdToHtml,
|
||||
elementUrl,
|
||||
favIconUrl,
|
||||
setIsoData,
|
||||
getIdFromProps,
|
||||
getUsernameFromProps,
|
||||
wsSubscribe,
|
||||
createCommentLikeRes,
|
||||
editCommentRes,
|
||||
saveCommentRes,
|
||||
createPostLikeFindRes,
|
||||
setAuth,
|
||||
lemmyHttp,
|
||||
} from '../utils';
|
||||
import { UserListing } from './user-listing';
|
||||
import { SortSelect } from './sort-select';
|
||||
|
@ -46,11 +57,9 @@ import { ImageUploadForm } from './image-upload-form';
|
|||
import { BannerIconHeader } from './banner-icon-header';
|
||||
|
||||
interface UserState {
|
||||
user: UserView;
|
||||
user_id: number;
|
||||
username: string;
|
||||
follows: CommunityUser[];
|
||||
moderates: CommunityUser[];
|
||||
userRes: UserDetailsResponse;
|
||||
userId: number;
|
||||
userName: string;
|
||||
view: UserDetailsView;
|
||||
sort: SortType;
|
||||
page: number;
|
||||
|
@ -78,25 +87,12 @@ interface UrlParams {
|
|||
}
|
||||
|
||||
export class User extends Component<any, UserState> {
|
||||
private isoData = setIsoData(this.context);
|
||||
private subscription: Subscription;
|
||||
private emptyState: UserState = {
|
||||
user: {
|
||||
id: null,
|
||||
name: null,
|
||||
published: null,
|
||||
number_of_posts: null,
|
||||
post_score: null,
|
||||
number_of_comments: null,
|
||||
comment_score: null,
|
||||
banned: null,
|
||||
avatar: null,
|
||||
actor_id: null,
|
||||
local: null,
|
||||
},
|
||||
user_id: null,
|
||||
username: null,
|
||||
follows: [],
|
||||
moderates: [],
|
||||
userRes: undefined,
|
||||
userId: getIdFromProps(this.props),
|
||||
userName: getUsernameFromProps(this.props),
|
||||
loading: true,
|
||||
view: User.getViewFromProps(this.props.match.view),
|
||||
sort: User.getSortTypeFromProps(this.props.match.sort),
|
||||
|
@ -119,31 +115,7 @@ export class User extends Component<any, UserState> {
|
|||
deleteAccountForm: {
|
||||
password: null,
|
||||
},
|
||||
siteRes: {
|
||||
admins: [],
|
||||
banned: [],
|
||||
online: undefined,
|
||||
site: {
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
creator_id: undefined,
|
||||
published: undefined,
|
||||
creator_name: undefined,
|
||||
number_of_users: undefined,
|
||||
number_of_posts: undefined,
|
||||
number_of_comments: undefined,
|
||||
number_of_communities: undefined,
|
||||
enable_downvotes: undefined,
|
||||
open_registration: undefined,
|
||||
enable_nsfw: undefined,
|
||||
icon: undefined,
|
||||
banner: undefined,
|
||||
creator_preferred_username: undefined,
|
||||
},
|
||||
version: undefined,
|
||||
my_user: undefined,
|
||||
federated_instances: undefined,
|
||||
},
|
||||
siteRes: this.isoData.site,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
|
@ -168,25 +140,37 @@ export class User extends Component<any, UserState> {
|
|||
this.handleBannerUpload = this.handleBannerUpload.bind(this);
|
||||
this.handleBannerRemove = this.handleBannerRemove.bind(this);
|
||||
|
||||
this.state.user_id = Number(this.props.match.params.id) || null;
|
||||
this.state.username = this.props.match.params.username;
|
||||
this.parseMessage = this.parseMessage.bind(this);
|
||||
this.subscription = wsSubscribe(this.parseMessage);
|
||||
|
||||
this.subscription = WebSocketService.Instance.subject
|
||||
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
|
||||
.subscribe(
|
||||
msg => this.parseMessage(msg),
|
||||
err => console.error(err),
|
||||
() => console.log('complete')
|
||||
);
|
||||
// Only fetch the data if coming from another route
|
||||
if (this.isoData.path == this.context.router.route.match.url) {
|
||||
this.state.userRes = this.isoData.routeData[0];
|
||||
this.setUserInfo();
|
||||
this.state.loading = false;
|
||||
} else {
|
||||
this.fetchUserData();
|
||||
}
|
||||
|
||||
WebSocketService.Instance.getSite();
|
||||
setupTippy();
|
||||
}
|
||||
|
||||
fetchUserData() {
|
||||
let form: GetUserDetailsForm = {
|
||||
user_id: this.state.userId,
|
||||
username: this.state.userName,
|
||||
sort: this.state.sort,
|
||||
saved_only: this.state.view === UserDetailsView.Saved,
|
||||
page: this.state.page,
|
||||
limit: fetchLimit,
|
||||
};
|
||||
WebSocketService.Instance.getUserDetails(form);
|
||||
}
|
||||
|
||||
get isCurrentUser() {
|
||||
return (
|
||||
UserService.Instance.user &&
|
||||
UserService.Instance.user.id == this.state.user.id
|
||||
UserService.Instance.user.id == this.state.userRes.user.id
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -202,6 +186,44 @@ export class User extends Component<any, UserState> {
|
|||
return page ? Number(page) : 1;
|
||||
}
|
||||
|
||||
static fetchInitialData(auth: string, path: string): Promise<any>[] {
|
||||
let pathSplit = path.split('/');
|
||||
let promises: Promise<any>[] = [];
|
||||
|
||||
// It can be /u/me, or /username/1
|
||||
let idOrName = pathSplit[2];
|
||||
let user_id: number;
|
||||
let username: string;
|
||||
if (isNaN(Number(idOrName))) {
|
||||
username = idOrName;
|
||||
} else {
|
||||
user_id = Number(idOrName);
|
||||
}
|
||||
|
||||
let view = this.getViewFromProps(pathSplit[4]);
|
||||
let sort = this.getSortTypeFromProps(pathSplit[6]);
|
||||
let page = this.getPageFromProps(Number(pathSplit[8]));
|
||||
|
||||
let form: GetUserDetailsForm = {
|
||||
sort,
|
||||
saved_only: view === UserDetailsView.Saved,
|
||||
page,
|
||||
limit: fetchLimit,
|
||||
};
|
||||
this.setIdOrName(form, user_id, username);
|
||||
setAuth(form, auth);
|
||||
promises.push(lemmyHttp.getUserDetails(form));
|
||||
return promises;
|
||||
}
|
||||
|
||||
static setIdOrName(obj: any, id: number, name_: string) {
|
||||
if (id) {
|
||||
obj.user_id = id;
|
||||
} else {
|
||||
obj.username = name_;
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
|
@ -229,7 +251,7 @@ export class User extends Component<any, UserState> {
|
|||
|
||||
get documentTitle(): string {
|
||||
if (this.state.siteRes.site.name) {
|
||||
return `@${this.state.username} - ${this.state.siteRes.site.name}`;
|
||||
return `@${this.state.userName} - ${this.state.siteRes.site.name}`;
|
||||
} else {
|
||||
return 'Lemmy';
|
||||
}
|
||||
|
@ -252,43 +274,41 @@ export class User extends Component<any, UserState> {
|
|||
href={this.favIcon}
|
||||
/>
|
||||
</Helmet>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-8">
|
||||
{this.state.loading ? (
|
||||
<h5>
|
||||
<svg class="icon icon-spinner spin">
|
||||
<use xlinkHref="#icon-spinner"></use>
|
||||
</svg>
|
||||
</h5>
|
||||
) : (
|
||||
{this.state.loading ? (
|
||||
<h5>
|
||||
<svg class="icon icon-spinner spin">
|
||||
<use xlinkHref="#icon-spinner"></use>
|
||||
</svg>
|
||||
</h5>
|
||||
) : (
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-8">
|
||||
<>
|
||||
{this.userInfo()}
|
||||
<hr />
|
||||
</>
|
||||
)}
|
||||
{!this.state.loading && this.selects()}
|
||||
<UserDetails
|
||||
user_id={this.state.user_id}
|
||||
username={this.state.username}
|
||||
sort={this.state.sort}
|
||||
page={this.state.page}
|
||||
limit={fetchLimit}
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
enableNsfw={this.state.siteRes.site.enable_nsfw}
|
||||
admins={this.state.siteRes.admins}
|
||||
view={this.state.view}
|
||||
onPageChange={this.handlePageChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{!this.state.loading && (
|
||||
<div class="col-12 col-md-4">
|
||||
{this.isCurrentUser && this.userSettings()}
|
||||
{this.moderates()}
|
||||
{this.follows()}
|
||||
{!this.state.loading && this.selects()}
|
||||
<UserDetails
|
||||
userRes={this.state.userRes}
|
||||
sort={this.state.sort}
|
||||
page={this.state.page}
|
||||
limit={fetchLimit}
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
enableNsfw={this.state.siteRes.site.enable_nsfw}
|
||||
view={this.state.view}
|
||||
onPageChange={this.handlePageChange}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{!this.state.loading && (
|
||||
<div class="col-12 col-md-4">
|
||||
{this.isCurrentUser && this.userSettings()}
|
||||
{this.moderates()}
|
||||
{this.follows()}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -362,7 +382,7 @@ export class User extends Component<any, UserState> {
|
|||
hideHot
|
||||
/>
|
||||
<a
|
||||
href={`/feeds/u/${this.state.username}.xml?sort=${this.state.sort}`}
|
||||
href={`/feeds/u/${this.state.userName}.xml?sort=${this.state.sort}`}
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
title="RSS"
|
||||
|
@ -376,14 +396,11 @@ export class User extends Component<any, UserState> {
|
|||
}
|
||||
|
||||
userInfo() {
|
||||
let user = this.state.user;
|
||||
let user = this.state.userRes.user;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BannerIconHeader
|
||||
banner={this.state.user.banner}
|
||||
icon={this.state.user.avatar}
|
||||
/>
|
||||
<BannerIconHeader banner={user.banner} icon={user.avatar} />
|
||||
<div class="mb-3">
|
||||
<div class="">
|
||||
<div class="mb-0 d-flex flex-wrap">
|
||||
|
@ -420,17 +437,17 @@ export class User extends Component<any, UserState> {
|
|||
<>
|
||||
<a
|
||||
className={`d-flex align-self-start btn btn-secondary ml-2 ${
|
||||
!this.state.user.matrix_user_id && 'invisible'
|
||||
!user.matrix_user_id && 'invisible'
|
||||
}`}
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
href={`https://matrix.to/#/${this.state.user.matrix_user_id}`}
|
||||
href={`https://matrix.to/#/${user.matrix_user_id}`}
|
||||
>
|
||||
{i18n.t('send_secure_message')}
|
||||
</a>
|
||||
<Link
|
||||
class="d-flex align-self-start btn btn-secondary ml-2"
|
||||
to={`/create_private_message/recipient/${this.state.user.id}`}
|
||||
to={`/create_private_message/recipient/${user.id}`}
|
||||
>
|
||||
{i18n.t('send_message')}
|
||||
</Link>
|
||||
|
@ -818,12 +835,12 @@ export class User extends Component<any, UserState> {
|
|||
moderates() {
|
||||
return (
|
||||
<div>
|
||||
{this.state.moderates.length > 0 && (
|
||||
{this.state.userRes.moderates.length > 0 && (
|
||||
<div class="card bg-transparent border-secondary mb-3">
|
||||
<div class="card-body">
|
||||
<h5>{i18n.t('moderates')}</h5>
|
||||
<ul class="list-unstyled mb-0">
|
||||
{this.state.moderates.map(community => (
|
||||
{this.state.userRes.moderates.map(community => (
|
||||
<li>
|
||||
<Link to={`/c/${community.community_name}`}>
|
||||
{community.community_name}
|
||||
|
@ -841,12 +858,12 @@ export class User extends Component<any, UserState> {
|
|||
follows() {
|
||||
return (
|
||||
<div>
|
||||
{this.state.follows.length > 0 && (
|
||||
{this.state.userRes.follows.length > 0 && (
|
||||
<div class="card bg-transparent border-secondary mb-3">
|
||||
<div class="card-body">
|
||||
<h5>{i18n.t('subscribed')}</h5>
|
||||
<ul class="list-unstyled mb-0">
|
||||
{this.state.follows.map(community => (
|
||||
{this.state.userRes.follows.map(community => (
|
||||
<li>
|
||||
<Link to={`/c/${community.community_name}`}>
|
||||
{community.community_name}
|
||||
|
@ -866,7 +883,7 @@ export class User extends Component<any, UserState> {
|
|||
const viewStr = paramUpdates.view || UserDetailsView[this.state.view];
|
||||
const sortStr = paramUpdates.sort || this.state.sort;
|
||||
this.props.history.push(
|
||||
`/u/${this.state.username}/view/${viewStr}/sort/${sortStr}/page/${page}`
|
||||
`/u/${this.state.userName}/view/${viewStr}/sort/${sortStr}/page/${page}`
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -966,7 +983,7 @@ export class User extends Component<any, UserState> {
|
|||
i.state.userSettingsForm.matrix_user_id = event.target.value;
|
||||
if (
|
||||
i.state.userSettingsForm.matrix_user_id == '' &&
|
||||
!i.state.user.matrix_user_id
|
||||
!i.state.userRes.user.matrix_user_id
|
||||
) {
|
||||
i.state.userSettingsForm.matrix_user_id = undefined;
|
||||
}
|
||||
|
@ -1029,6 +1046,33 @@ export class User extends Component<any, UserState> {
|
|||
WebSocketService.Instance.deleteAccount(i.state.deleteAccountForm);
|
||||
}
|
||||
|
||||
setUserInfo() {
|
||||
if (this.isCurrentUser) {
|
||||
this.state.userSettingsForm.show_nsfw =
|
||||
UserService.Instance.user.show_nsfw;
|
||||
this.state.userSettingsForm.theme = UserService.Instance.user.theme
|
||||
? UserService.Instance.user.theme
|
||||
: 'darkly';
|
||||
this.state.userSettingsForm.default_sort_type =
|
||||
UserService.Instance.user.default_sort_type;
|
||||
this.state.userSettingsForm.default_listing_type =
|
||||
UserService.Instance.user.default_listing_type;
|
||||
this.state.userSettingsForm.lang = UserService.Instance.user.lang;
|
||||
this.state.userSettingsForm.avatar = UserService.Instance.user.avatar;
|
||||
this.state.userSettingsForm.banner = UserService.Instance.user.banner;
|
||||
this.state.userSettingsForm.preferred_username =
|
||||
UserService.Instance.user.preferred_username;
|
||||
this.state.userSettingsForm.show_avatars =
|
||||
UserService.Instance.user.show_avatars;
|
||||
this.state.userSettingsForm.email = UserService.Instance.user.email;
|
||||
this.state.userSettingsForm.bio = UserService.Instance.user.bio;
|
||||
this.state.userSettingsForm.send_notifications_to_email =
|
||||
UserService.Instance.user.send_notifications_to_email;
|
||||
this.state.userSettingsForm.matrix_user_id =
|
||||
UserService.Instance.user.matrix_user_id;
|
||||
}
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
console.log(msg);
|
||||
const res = wsJsonToRes(msg);
|
||||
|
@ -1042,50 +1086,24 @@ export class User extends Component<any, UserState> {
|
|||
userSettingsLoading: false,
|
||||
});
|
||||
return;
|
||||
} else if (msg.reconnect) {
|
||||
this.fetchUserData();
|
||||
} else if (res.op == UserOperation.GetUserDetails) {
|
||||
// Since the UserDetails contains posts/comments as well as some general user info we listen here as well
|
||||
// and set the parent state if it is not set or differs
|
||||
// TODO this might need to get abstracted
|
||||
const data = res.data as UserDetailsResponse;
|
||||
|
||||
if (this.state.user.id !== data.user.id) {
|
||||
this.state.user = data.user;
|
||||
this.state.follows = data.follows;
|
||||
this.state.moderates = data.moderates;
|
||||
|
||||
if (this.isCurrentUser) {
|
||||
this.state.userSettingsForm.show_nsfw =
|
||||
UserService.Instance.user.show_nsfw;
|
||||
this.state.userSettingsForm.theme = UserService.Instance.user.theme
|
||||
? UserService.Instance.user.theme
|
||||
: 'darkly';
|
||||
this.state.userSettingsForm.default_sort_type =
|
||||
UserService.Instance.user.default_sort_type;
|
||||
this.state.userSettingsForm.default_listing_type =
|
||||
UserService.Instance.user.default_listing_type;
|
||||
this.state.userSettingsForm.lang = UserService.Instance.user.lang;
|
||||
this.state.userSettingsForm.avatar = UserService.Instance.user.avatar;
|
||||
this.state.userSettingsForm.banner = UserService.Instance.user.banner;
|
||||
this.state.userSettingsForm.preferred_username =
|
||||
UserService.Instance.user.preferred_username;
|
||||
this.state.userSettingsForm.show_avatars =
|
||||
UserService.Instance.user.show_avatars;
|
||||
this.state.userSettingsForm.email = UserService.Instance.user.email;
|
||||
this.state.userSettingsForm.bio = UserService.Instance.user.bio;
|
||||
this.state.userSettingsForm.send_notifications_to_email =
|
||||
UserService.Instance.user.send_notifications_to_email;
|
||||
this.state.userSettingsForm.matrix_user_id =
|
||||
UserService.Instance.user.matrix_user_id;
|
||||
}
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
}
|
||||
this.state.userRes = data;
|
||||
this.setUserInfo();
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.SaveUserSettings) {
|
||||
const data = res.data as LoginResponse;
|
||||
UserService.Instance.login(data);
|
||||
this.state.user.bio = this.state.userSettingsForm.bio;
|
||||
this.state.user.preferred_username = this.state.userSettingsForm.preferred_username;
|
||||
this.state.user.banner = this.state.userSettingsForm.banner;
|
||||
this.state.user.avatar = this.state.userSettingsForm.avatar;
|
||||
this.state.userRes.user.bio = this.state.userSettingsForm.bio;
|
||||
this.state.userRes.user.preferred_username = this.state.userSettingsForm.preferred_username;
|
||||
this.state.userRes.user.banner = this.state.userSettingsForm.banner;
|
||||
this.state.userRes.user.avatar = this.state.userSettingsForm.avatar;
|
||||
this.state.userSettingsLoading = false;
|
||||
this.setState(this.state);
|
||||
|
||||
|
@ -1096,14 +1114,47 @@ export class User extends Component<any, UserState> {
|
|||
deleteAccountShowConfirm: false,
|
||||
});
|
||||
this.context.router.history.push('/');
|
||||
} else if (res.op == UserOperation.GetSite) {
|
||||
const data = res.data as GetSiteResponse;
|
||||
this.state.siteRes = data;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.AddAdmin) {
|
||||
const data = res.data as AddAdminResponse;
|
||||
this.state.siteRes.admins = data.admins;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreateCommentLike) {
|
||||
const data = res.data as CommentResponse;
|
||||
createCommentLikeRes(data, this.state.userRes.comments);
|
||||
this.setState(this.state);
|
||||
} else if (
|
||||
res.op == UserOperation.EditComment ||
|
||||
res.op == UserOperation.DeleteComment ||
|
||||
res.op == UserOperation.RemoveComment
|
||||
) {
|
||||
const data = res.data as CommentResponse;
|
||||
editCommentRes(data, this.state.userRes.comments);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreateComment) {
|
||||
const data = res.data as CommentResponse;
|
||||
if (
|
||||
UserService.Instance.user &&
|
||||
data.comment.creator_id == UserService.Instance.user.id
|
||||
) {
|
||||
toast(i18n.t('reply_sent'));
|
||||
}
|
||||
} else if (res.op == UserOperation.SaveComment) {
|
||||
const data = res.data as CommentResponse;
|
||||
saveCommentRes(data, this.state.userRes.comments);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreatePostLike) {
|
||||
const data = res.data as PostResponse;
|
||||
createPostLikeFindRes(data, this.state.userRes.posts);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.BanUser) {
|
||||
const data = res.data as BanUserResponse;
|
||||
this.state.userRes.comments
|
||||
.filter(c => c.creator_id == data.user.id)
|
||||
.forEach(c => (c.banned = data.banned));
|
||||
this.state.userRes.posts
|
||||
.filter(c => c.creator_id == data.user.id)
|
||||
.forEach(c => (c.banned = data.banned));
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,8 +64,13 @@ export const routes: IRoutePropsWithFetch[] = [
|
|||
{
|
||||
path: `/post/:id/comment/:comment_id`,
|
||||
component: Post,
|
||||
fetchInitialData: (auth, path) => Post.fetchInitialData(auth, path),
|
||||
},
|
||||
{
|
||||
path: `/post/:id`,
|
||||
component: Post,
|
||||
fetchInitialData: (auth, path) => Post.fetchInitialData(auth, path),
|
||||
},
|
||||
{ path: `/post/:id`, component: Post },
|
||||
{
|
||||
path: `/c/:name/data_type/:data_type/sort/:sort/page/:page`,
|
||||
component: Community,
|
||||
|
@ -84,10 +89,23 @@ export const routes: IRoutePropsWithFetch[] = [
|
|||
{
|
||||
path: `/u/:username/view/:view/sort/:sort/page/:page`,
|
||||
component: User,
|
||||
fetchInitialData: (auth, path) => User.fetchInitialData(auth, path),
|
||||
},
|
||||
{
|
||||
path: `/user/:id`,
|
||||
component: User,
|
||||
fetchInitialData: (auth, path) => User.fetchInitialData(auth, path),
|
||||
},
|
||||
{
|
||||
path: `/u/:username`,
|
||||
component: User,
|
||||
fetchInitialData: (auth, path) => User.fetchInitialData(auth, path),
|
||||
},
|
||||
{
|
||||
path: `/inbox`,
|
||||
component: Inbox,
|
||||
fetchInitialData: (auth, path) => Inbox.fetchInitialData(auth, path),
|
||||
},
|
||||
{ path: `/user/:id`, component: User },
|
||||
{ path: `/u/:username`, component: User },
|
||||
{ path: `/inbox`, component: Inbox },
|
||||
{
|
||||
path: `/modlog/community/:community_id`,
|
||||
component: Modlog,
|
||||
|
|
|
@ -31,7 +31,9 @@ export class UserService {
|
|||
|
||||
public login(res: LoginResponse) {
|
||||
this.setClaims(res.jwt);
|
||||
IsomorphicCookie.save('jwt', res.jwt, { expires: 365 });
|
||||
let expires = new Date();
|
||||
expires.setDate(expires.getDate() + 365);
|
||||
IsomorphicCookie.save('jwt', res.jwt, { expires });
|
||||
console.log('jwt cookie set');
|
||||
}
|
||||
|
||||
|
|
|
@ -845,6 +845,18 @@ export function getRecipientIdFromProps(props: any): number {
|
|||
: 1;
|
||||
}
|
||||
|
||||
export function getIdFromProps(props: any): number {
|
||||
return Number(props.match.params.id);
|
||||
}
|
||||
|
||||
export function getCommentIdFromProps(props: any): number {
|
||||
return Number(props.match.params.comment_id);
|
||||
}
|
||||
|
||||
export function getUsernameFromProps(props: any): string {
|
||||
return props.match.params.username;
|
||||
}
|
||||
|
||||
export function editCommentRes(data: CommentResponse, comments: Comment[]) {
|
||||
let found = comments.find(c => c.id == data.comment.id);
|
||||
if (found) {
|
||||
|
|
Loading…
Reference in a new issue