From: Dessalines <tyhou13@gmx.com> Date: Wed, 9 Sep 2020 00:48:17 +0000 (-0500) Subject: Add post, inbox, and user routes. X-Git-Url: http://these/git/%7BpictshareAvatarThumbnail%28admin.avatar%29%7D?a=commitdiff_plain;h=95b74ad74c56754d9ebc456beb2c66ddef055705;p=lemmy-ui.git Add post, inbox, and user routes. --- diff --git a/src/shared/components/comment-node.tsx b/src/shared/components/comment-node.tsx index b9edcae..19c1bdc 100644 --- a/src/shared/components/comment-node.tsx +++ b/src/shared/components/comment-node.tsx @@ -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')} > diff --git a/src/shared/components/inbox.tsx b/src/shared/components/inbox.tsx index 8292511..e36b3b8 100644 --- a/src/shared/components/inbox.tsx +++ b/src/shared/components/inbox.tsx @@ -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); } } diff --git a/src/shared/components/post-form.tsx b/src/shared/components/post-form.tsx index ac6ad3b..f37b5bc 100644 --- a/src/shared/components/post-form.tsx +++ b/src/shared/components/post-form.tsx @@ -115,6 +115,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> { } } + this.parseMessage = this.parseMessage.bind(this); this.subscription = wsSubscribe(this.parseMessage); } diff --git a/src/shared/components/post-listing.tsx b/src/shared/components/post-listing.tsx index d82ddc8..93edfb7 100644 --- a/src/shared/components/post-listing.tsx +++ b/src/shared/components/post-listing.tsx @@ -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')} > diff --git a/src/shared/components/post.tsx b/src/shared/components/post.tsx index d35a77d..1406de7 100644 --- a/src/shared/components/post.tsx +++ b/src/shared/components/post.tsx @@ -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); - 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.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(); + } + } + + 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); } } diff --git a/src/shared/components/user-details.tsx b/src/shared/components/user-details.tsx index c249689..834000e 100644 --- a/src/shared/components/user-details.tsx +++ b/src/shared/components/user-details.tsx @@ -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, - }); - } - } } diff --git a/src/shared/components/user.tsx b/src/shared/components/user.tsx index a2d0e9a..84d9cd1 100644 --- a/src/shared/components/user.tsx +++ b/src/shared/components/user.tsx @@ -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 + 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> + + {!this.state.loading && ( + <div class="col-12 col-md-4"> + {this.isCurrentUser && this.userSettings()} + {this.moderates()} + {this.follows()} + </div> )} - {!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()} - </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); } } } diff --git a/src/shared/routes.ts b/src/shared/routes.ts index 6580db4..14d5495 100644 --- a/src/shared/routes.ts +++ b/src/shared/routes.ts @@ -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, diff --git a/src/shared/services/UserService.ts b/src/shared/services/UserService.ts index dce3309..785ce3f 100644 --- a/src/shared/services/UserService.ts +++ b/src/shared/services/UserService.ts @@ -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'); } diff --git a/src/shared/utils.ts b/src/shared/utils.ts index 5ec209d..e48edf0 100644 --- a/src/shared/utils.ts +++ b/src/shared/utils.ts @@ -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) {