diff options
author | Dessalines <tyhou13@gmx.com> | 2020-07-14 11:26:16 -0400 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2020-07-14 11:26:16 -0400 |
commit | d6fdfe0b6d348e0c3da5deaf5beea329ff04f068 (patch) | |
tree | a8042afde4b1617f38b4e67fbdce33949680e3a5 /ui/src/components/user-details.tsx | |
parent | 5ccf81349e18e100fb13c10b05921a7d9619ddd5 (diff) | |
parent | ef62f4698a62e996bcd54faa1f360eff89b8ac4b (diff) |
Merge branch 'fix_frontend_duplicate_requests' of https://github.com/masterstur/lemmy into masterstur-fix_frontend_duplicate_requests
Diffstat (limited to 'ui/src/components/user-details.tsx')
-rw-r--r-- | ui/src/components/user-details.tsx | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/ui/src/components/user-details.tsx b/ui/src/components/user-details.tsx new file mode 100644 index 00000000..e4b4b24a --- /dev/null +++ b/ui/src/components/user-details.tsx @@ -0,0 +1,307 @@ +import { Component, linkEvent } from 'inferno'; +import { WebSocketService, UserService } from '../services'; +import { Subscription } from 'rxjs'; +import { retryWhen, delay, take, last } from 'rxjs/operators'; +import { i18n } from '../i18next'; +import { + UserOperation, + Post, + Comment, + CommunityUser, + SortType, + UserDetailsResponse, + UserView, + WebSocketJsonResponse, + UserDetailsView, + CommentResponse, + BanUserResponse, + PostResponse, + AddAdminResponse, +} from '../interfaces'; +import { + wsJsonToRes, + toast, + commentsToFlatNodes, + setupTippy, + editCommentRes, + saveCommentRes, + createCommentLikeRes, + createPostLikeFindRes, +} from '../utils'; +import { PostListing } from './post-listing'; +import { CommentNodes } from './comment-nodes'; + +interface UserDetailsProps { + username?: string; + user_id?: number; + page: number; + limit: number; + sort: string; + enableDownvotes: boolean; + enableNsfw: boolean; + view: UserDetailsView; + onPageChange(page: number): number | any; +} + +interface UserDetailsState { + follows: Array<CommunityUser>; + moderates: Array<CommunityUser>; + comments: Array<Comment>; + posts: Array<Post>; + saved?: Array<Post>; + admins: Array<UserView>; +} + +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: [], + admins: [], + }; + + 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(); + } + + componentDidMount() { + this.fetchUserData(); + } + + componentDidUpdate(lastProps: UserDetailsProps) { + for (const key of Object.keys(lastProps)) { + if (lastProps[key] !== this.props[key]) { + this.fetchUserData(); + break; + } + } + setupTippy(); + } + + 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, + }); + } + + render() { + return ( + <div> + {this.viewSelector(this.props.view)} + {this.paginator()} + </div> + ); + } + + viewSelector(view: UserDetailsView) { + if (view === UserDetailsView.Overview || view === UserDetailsView.Saved) { + return this.overview(); + } + if (view === UserDetailsView.Comments) { + return this.comments(); + } + if (view === UserDetailsView.Posts) { + return this.posts(); + } + } + + overview() { + const comments = this.state.comments.map((c: Comment) => { + return { type: 'comments', data: c }; + }); + const posts = this.state.posts.map((p: Post) => { + return { type: 'posts', data: p }; + }); + + const combined: Array<{ type: string; data: Comment | Post }> = [ + ...comments, + ...posts, + ]; + + // Sort it + if (SortType[this.props.sort] === SortType.New) { + combined.sort((a, b) => b.data.published.localeCompare(a.data.published)); + } else { + combined.sort((a, b) => b.data.score - a.data.score); + } + + return ( + <div> + {combined.map(i => ( + <div> + {i.type === 'posts' ? ( + <PostListing + post={i.data as Post} + admins={this.state.admins} + showCommunity + enableDownvotes={this.props.enableDownvotes} + enableNsfw={this.props.enableNsfw} + /> + ) : ( + <CommentNodes + nodes={[{ comment: i.data as Comment }]} + admins={this.state.admins} + noIndent + showContext + enableDownvotes={this.props.enableDownvotes} + /> + )} + </div> + ))} + </div> + ); + } + + comments() { + return ( + <div> + <CommentNodes + nodes={commentsToFlatNodes(this.state.comments)} + admins={this.state.admins} + noIndent + showContext + enableDownvotes={this.props.enableDownvotes} + /> + </div> + ); + } + + posts() { + return ( + <div> + {this.state.posts.map(post => ( + <PostListing + post={post} + admins={this.state.admins} + showCommunity + enableDownvotes={this.props.enableDownvotes} + enableNsfw={this.props.enableNsfw} + /> + ))} + </div> + ); + } + + paginator() { + return ( + <div class="my-2"> + {this.props.page > 1 && ( + <button + class="btn btn-sm btn-secondary mr-1" + onClick={linkEvent(this, this.prevPage)} + > + {i18n.t('prev')} + </button> + )} + {this.state.comments.length + this.state.posts.length > 0 && ( + <button + class="btn btn-sm btn-secondary" + onClick={linkEvent(this, this.nextPage)} + > + {i18n.t('next')} + </button> + )} + </div> + ); + } + + nextPage(i: UserDetails) { + i.props.onPageChange(i.props.page + 1); + } + + prevPage(i: UserDetails) { + i.props.onPageChange(i.props.page - 1); + } + + parseMessage(msg: WebSocketJsonResponse) { + 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, + admins: data.admins, + }); + } 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) { + 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, + }); + } else if (res.op == UserOperation.AddAdmin) { + const data = res.data as AddAdminResponse; + this.setState({ + admins: data.admins, + }); + } + } +} |