summaryrefslogtreecommitdiffstats
path: root/ui/src/components/user-details.tsx
diff options
context:
space:
mode:
authorDessalines <tyhou13@gmx.com>2020-07-14 11:26:16 -0400
committerDessalines <tyhou13@gmx.com>2020-07-14 11:26:16 -0400
commitd6fdfe0b6d348e0c3da5deaf5beea329ff04f068 (patch)
treea8042afde4b1617f38b4e67fbdce33949680e3a5 /ui/src/components/user-details.tsx
parent5ccf81349e18e100fb13c10b05921a7d9619ddd5 (diff)
parentef62f4698a62e996bcd54faa1f360eff89b8ac4b (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.tsx307
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,
+ });
+ }
+ }
+}