diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/src/components/communities.tsx | 41 | ||||
-rw-r--r-- | ui/src/components/community.tsx | 68 | ||||
-rw-r--r-- | ui/src/components/data-type-select.tsx | 15 | ||||
-rw-r--r-- | ui/src/components/listing-type-select.tsx | 15 | ||||
-rw-r--r-- | ui/src/components/main.tsx | 86 | ||||
-rw-r--r-- | ui/src/components/search.tsx | 109 | ||||
-rw-r--r-- | ui/src/components/sort-select.tsx | 10 | ||||
-rw-r--r-- | ui/src/components/user-details.tsx | 307 | ||||
-rw-r--r-- | ui/src/components/user.tsx | 425 | ||||
-rw-r--r-- | ui/src/interfaces.ts | 7 | ||||
-rw-r--r-- | ui/src/version.ts | 2 |
11 files changed, 631 insertions, 454 deletions
diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx index 10a3ab80..ba362acc 100644 --- a/ui/src/components/communities.tsx +++ b/ui/src/components/communities.tsx @@ -13,7 +13,7 @@ import { GetSiteResponse, } from '../interfaces'; import { WebSocketService } from '../services'; -import { wsJsonToRes, toast } from '../utils'; +import { wsJsonToRes, toast, getPageFromProps } from '../utils'; import { CommunityLink } from './community-link'; import { i18n } from '../i18next'; @@ -27,12 +27,16 @@ interface CommunitiesState { loading: boolean; } +interface CommunitiesProps { + page: number; +} + export class Communities extends Component<any, CommunitiesState> { private subscription: Subscription; private emptyState: CommunitiesState = { communities: [], loading: true, - page: this.getPageFromProps(this.props), + page: getPageFromProps(this.props), }; constructor(props: any, context: any) { @@ -50,19 +54,19 @@ export class Communities extends Component<any, CommunitiesState> { WebSocketService.Instance.getSite(); } - getPageFromProps(props: any): number { - return props.match.params.page ? Number(props.match.params.page) : 1; - } - componentWillUnmount() { this.subscription.unsubscribe(); } - // Necessary for back button for some reason - componentWillReceiveProps(nextProps: any) { - if (nextProps.history.action == 'POP') { - this.state = this.emptyState; - this.state.page = this.getPageFromProps(nextProps); + static getDerivedStateFromProps(props: any): CommunitiesProps { + return { + page: getPageFromProps(props), + }; + } + + componentDidUpdate(_: any, lastState: CommunitiesState) { + if (lastState.page !== this.state.page) { + this.setState({ loading: true }); this.refetch(); } } @@ -172,22 +176,17 @@ export class Communities extends Component<any, CommunitiesState> { ); } - updateUrl() { - this.props.history.push(`/communities/page/${this.state.page}`); + updateUrl(paramUpdates: CommunitiesProps) { + const page = paramUpdates.page || this.state.page; + this.props.history.push(`/communities/page/${page}`); } nextPage(i: Communities) { - i.state.page++; - i.setState(i.state); - i.updateUrl(); - i.refetch(); + i.updateUrl({ page: i.state.page + 1 }); } prevPage(i: Communities) { - i.state.page--; - i.setState(i.state); - i.updateUrl(); - i.refetch(); + i.updateUrl({ page: i.state.page - 1 }); } handleUnsubscribe(communityId: number) { diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx index fc999b25..99b692ca 100644 --- a/ui/src/components/community.tsx +++ b/ui/src/components/community.tsx @@ -65,6 +65,18 @@ interface State { site: Site; } +interface CommunityProps { + dataType: DataType; + sort: SortType; + page: number; +} + +interface UrlParams { + dataType?: string; + sort?: string; + page?: number; +} + export class Community extends Component<any, State> { private subscription: Subscription; private emptyState: State = { @@ -143,16 +155,21 @@ export class Community extends Component<any, State> { this.subscription.unsubscribe(); } - // Necessary for back button for some reason - componentWillReceiveProps(nextProps: any) { + static getDerivedStateFromProps(props: any): CommunityProps { + return { + dataType: getDataTypeFromProps(props), + sort: getSortTypeFromProps(props), + page: getPageFromProps(props), + }; + } + + componentDidUpdate(_: any, lastState: State) { if ( - nextProps.history.action == 'POP' || - nextProps.history.action == 'PUSH' + lastState.dataType !== this.state.dataType || + lastState.sort !== this.state.sort || + lastState.page !== this.state.page ) { - this.state.dataType = getDataTypeFromProps(nextProps); - this.state.sort = getSortTypeFromProps(nextProps); - this.state.page = getPageFromProps(nextProps); - this.setState(this.state); + this.setState({ loading: true }); this.fetchData(); } } @@ -273,46 +290,33 @@ export class Community extends Component<any, State> { } nextPage(i: Community) { - i.state.page++; - i.setState(i.state); - i.updateUrl(); - i.fetchData(); + i.updateUrl({ page: i.state.page + 1 }); window.scrollTo(0, 0); } prevPage(i: Community) { - i.state.page--; - i.setState(i.state); - i.updateUrl(); - i.fetchData(); + i.updateUrl({ page: i.state.page - 1 }); window.scrollTo(0, 0); } handleSortChange(val: SortType) { - this.state.sort = val; - this.state.page = 1; - this.state.loading = true; - this.setState(this.state); - this.updateUrl(); - this.fetchData(); + this.updateUrl({ sort: SortType[val].toLowerCase(), page: 1 }); window.scrollTo(0, 0); } handleDataTypeChange(val: DataType) { - this.state.dataType = val; - this.state.page = 1; - this.state.loading = true; - this.setState(this.state); - this.updateUrl(); - this.fetchData(); + this.updateUrl({ dataType: DataType[val].toLowerCase(), page: 1 }); window.scrollTo(0, 0); } - updateUrl() { - let dataTypeStr = DataType[this.state.dataType].toLowerCase(); - let sortStr = SortType[this.state.sort].toLowerCase(); + updateUrl(paramUpdates: UrlParams) { + const dataTypeStr = + paramUpdates.dataType || DataType[this.state.dataType].toLowerCase(); + const sortStr = + paramUpdates.sort || SortType[this.state.sort].toLowerCase(); + const page = paramUpdates.page || this.state.page; this.props.history.push( - `/c/${this.state.community.name}/data_type/${dataTypeStr}/sort/${sortStr}/page/${this.state.page}` + `/c/${this.state.community.name}/data_type/${dataTypeStr}/sort/${sortStr}/page/${page}` ); } diff --git a/ui/src/components/data-type-select.tsx b/ui/src/components/data-type-select.tsx index f2539c81..d16c785d 100644 --- a/ui/src/components/data-type-select.tsx +++ b/ui/src/components/data-type-select.tsx @@ -25,6 +25,12 @@ export class DataTypeSelect extends Component< this.state = this.emptyState; } + static getDerivedStateFromProps(props: any): DataTypeSelectProps { + return { + type_: props.type_, + }; + } + render() { return ( <div class="btn-group btn-group-toggle"> @@ -42,8 +48,9 @@ export class DataTypeSelect extends Component< {i18n.t('posts')} </label> <label - className={`pointer btn btn-sm btn-secondary ${this.state.type_ == - DataType.Comment && 'active'}`} + className={`pointer btn btn-sm btn-secondary ${ + this.state.type_ == DataType.Comment && 'active' + }`} > <input type="radio" @@ -58,8 +65,6 @@ export class DataTypeSelect extends Component< } handleTypeChange(i: DataTypeSelect, event: any) { - i.state.type_ = Number(event.target.value); - i.setState(i.state); - i.props.onChange(i.state.type_); + i.props.onChange(Number(event.target.value)); } } diff --git a/ui/src/components/listing-type-select.tsx b/ui/src/components/listing-type-select.tsx index d583b93c..e9b5a031 100644 --- a/ui/src/components/listing-type-select.tsx +++ b/ui/src/components/listing-type-select.tsx @@ -26,6 +26,12 @@ export class ListingTypeSelect extends Component< this.state = this.emptyState; } + static getDerivedStateFromProps(props: any): ListingTypeSelectProps { + return { + type_: props.type_, + }; + } + render() { return ( <div class="btn-group btn-group-toggle"> @@ -45,8 +51,9 @@ export class ListingTypeSelect extends Component< {i18n.t('subscribed')} </label> <label - className={`pointer btn btn-sm btn-secondary ${this.state.type_ == - ListingType.All && 'active'}`} + className={`pointer btn btn-sm btn-secondary ${ + this.state.type_ == ListingType.All && 'active' + }`} > <input type="radio" @@ -61,8 +68,6 @@ export class ListingTypeSelect extends Component< } handleTypeChange(i: ListingTypeSelect, event: any) { - i.state.type_ = Number(event.target.value); - i.setState(i.state); - i.props.onChange(i.state.type_); + i.props.onChange(Number(event.target.value)); } } diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx index 9063a039..0392090a 100644 --- a/ui/src/components/main.tsx +++ b/ui/src/components/main.tsx @@ -70,6 +70,20 @@ interface MainState { page: number; } +interface MainProps { + listingType: ListingType; + dataType: DataType; + sort: SortType; + page: number; +} + +interface UrlParams { + listingType?: string; + dataType?: string; + sort?: string; + page?: number; +} + export class Main extends Component<any, MainState> { private subscription: Subscription; private emptyState: MainState = { @@ -141,17 +155,23 @@ export class Main extends Component<any, MainState> { this.subscription.unsubscribe(); } - // Necessary for back button for some reason - componentWillReceiveProps(nextProps: any) { + static getDerivedStateFromProps(props: any): MainProps { + return { + listingType: getListingTypeFromProps(props), + dataType: getDataTypeFromProps(props), + sort: getSortTypeFromProps(props), + page: getPageFromProps(props), + }; + } + + componentDidUpdate(_: any, lastState: MainState) { if ( - nextProps.history.action == 'POP' || - nextProps.history.action == 'PUSH' + lastState.listingType !== this.state.listingType || + lastState.dataType !== this.state.dataType || + lastState.sort !== this.state.sort || + lastState.page !== this.state.page ) { - this.state.listingType = getListingTypeFromProps(nextProps); - this.state.dataType = getDataTypeFromProps(nextProps); - this.state.sort = getSortTypeFromProps(nextProps); - this.state.page = getPageFromProps(nextProps); - this.setState(this.state); + this.setState({ loading: true }); this.fetchData(); } } @@ -257,12 +277,17 @@ export class Main extends Component<any, MainState> { ); } - updateUrl() { - let listingTypeStr = ListingType[this.state.listingType].toLowerCase(); - let dataTypeStr = DataType[this.state.dataType].toLowerCase(); - let sortStr = SortType[this.state.sort].toLowerCase(); + updateUrl(paramUpdates: UrlParams) { + const listingTypeStr = + paramUpdates.listingType || + ListingType[this.state.listingType].toLowerCase(); + const dataTypeStr = + paramUpdates.dataType || DataType[this.state.dataType].toLowerCase(); + const sortStr = + paramUpdates.sort || SortType[this.state.sort].toLowerCase(); + const page = paramUpdates.page || this.state.page; this.props.history.push( - `/home/data_type/${dataTypeStr}/listing_type/${listingTypeStr}/sort/${sortStr}/page/${this.state.page}` + `/home/data_type/${dataTypeStr}/listing_type/${listingTypeStr}/sort/${sortStr}/page/${page}` ); } @@ -529,50 +554,27 @@ export class Main extends Component<any, MainState> { } nextPage(i: Main) { - i.state.page++; - i.state.loading = true; - i.setState(i.state); - i.updateUrl(); - i.fetchData(); + i.updateUrl({ page: i.state.page + 1 }); window.scrollTo(0, 0); } prevPage(i: Main) { - i.state.page--; - i.state.loading = true; - i.setState(i.state); - i.updateUrl(); - i.fetchData(); + i.updateUrl({ page: i.state.page - 1 }); window.scrollTo(0, 0); } handleSortChange(val: SortType) { - this.state.sort = val; - this.state.page = 1; - this.state.loading = true; - this.setState(this.state); - this.updateUrl(); - this.fetchData(); + this.updateUrl({ sort: SortType[val].toLowerCase(), page: 1 }); window.scrollTo(0, 0); } handleListingTypeChange(val: ListingType) { - this.state.listingType = val; - this.state.page = 1; - this.state.loading = true; - this.setState(this.state); - this.updateUrl(); - this.fetchData(); + this.updateUrl({ listingType: ListingType[val].toLowerCase(), page: 1 }); window.scrollTo(0, 0); } handleDataTypeChange(val: DataType) { - this.state.dataType = val; - this.state.page = 1; - this.state.loading = true; - this.setState(this.state); - this.updateUrl(); - this.fetchData(); + this.updateUrl({ dataType: DataType[val].toLowerCase(), page: 1 }); window.scrollTo(0, 0); } diff --git a/ui/src/components/search.tsx b/ui/src/components/search.tsx index b2e55497..d1d99cee 100644 --- a/ui/src/components/search.tsx +++ b/ui/src/components/search.tsx @@ -28,6 +28,7 @@ import { createCommentLikeRes, createPostLikeFindRes, commentsToFlatNodes, + getPageFromProps, } from '../utils'; import { PostListing } from './post-listing'; import { UserListing } from './user-listing'; @@ -44,15 +45,31 @@ interface SearchState { searchResponse: SearchResponse; loading: boolean; site: Site; + searchText: string; +} + +interface SearchProps { + q: string; + type_: SearchType; + sort: SortType; + page: number; +} + +interface UrlParams { + q?: string; + type_?: string; + sort?: string; + page?: number; } export class Search extends Component<any, SearchState> { private subscription: Subscription; private emptyState: SearchState = { - q: this.getSearchQueryFromProps(this.props), - type_: this.getSearchTypeFromProps(this.props), - sort: this.getSortTypeFromProps(this.props), - page: this.getPageFromProps(this.props), + q: Search.getSearchQueryFromProps(this.props), + type_: Search.getSearchTypeFromProps(this.props), + sort: Search.getSortTypeFromProps(this.props), + page: getPageFromProps(this.props), + searchText: Search.getSearchQueryFromProps(this.props), searchResponse: { type_: null, posts: [], @@ -77,26 +94,22 @@ export class Search extends Component<any, SearchState> { }, }; - getSearchQueryFromProps(props: any): string { + static getSearchQueryFromProps(props: any): string { return props.match.params.q ? props.match.params.q : ''; } - getSearchTypeFromProps(props: any): SearchType { + static getSearchTypeFromProps(props: any): SearchType { return props.match.params.type ? routeSearchTypeToEnum(props.match.params.type) : SearchType.All; } - getSortTypeFromProps(props: any): SortType { + static getSortTypeFromProps(props: any): SortType { return props.match.params.sort ? routeSortTypeToEnum(props.match.params.sort) : SortType.TopAll; } - getPageFromProps(props: any): number { - return props.match.params.page ? Number(props.match.params.page) : 1; - } - constructor(props: any, context: any) { super(props, context); @@ -122,17 +135,23 @@ export class Search extends Component<any, SearchState> { this.subscription.unsubscribe(); } - // Necessary for back button for some reason - componentWillReceiveProps(nextProps: any) { + static getDerivedStateFromProps(props: any): SearchProps { + return { + q: Search.getSearchQueryFromProps(props), + type_: Search.getSearchTypeFromProps(props), + sort: Search.getSortTypeFromProps(props), + page: getPageFromProps(props), + }; + } + + componentDidUpdate(_: any, lastState: SearchState) { if ( - nextProps.history.action == 'POP' || - nextProps.history.action == 'PUSH' + lastState.q !== this.state.q || + lastState.type_ !== this.state.type_ || + lastState.sort !== this.state.sort || + lastState.page !== this.state.page ) { - this.state.q = this.getSearchQueryFromProps(nextProps); - this.state.type_ = this.getSearchTypeFromProps(nextProps); - this.state.sort = this.getSortTypeFromProps(nextProps); - this.state.page = this.getPageFromProps(nextProps); - this.setState(this.state); + this.setState({ loading: true, searchText: this.state.q }); this.search(); } } @@ -163,7 +182,7 @@ export class Search extends Component<any, SearchState> { <input type="text" class="form-control mr-2" - value={this.state.q} + value={this.state.searchText} placeholder={`${i18n.t('search')}...`} onInput={linkEvent(this, this.handleQChange)} required @@ -413,17 +432,11 @@ export class Search extends Component<any, SearchState> { } nextPage(i: Search) { - i.state.page++; - i.setState(i.state); - i.updateUrl(); - i.search(); + i.updateUrl({ page: i.state.page + 1 }); } prevPage(i: Search) { - i.state.page--; - i.setState(i.state); - i.updateUrl(); - i.search(); + i.updateUrl({ page: i.state.page - 1 }); } search() { @@ -441,37 +454,39 @@ export class Search extends Component<any, SearchState> { } handleSortChange(val: SortType) { - this.state.sort = val; - this.state.page = 1; - this.setState(this.state); - this.updateUrl(); + this.updateUrl({ sort: SortType[val].toLowerCase(), page: 1 }); } handleTypeChange(i: Search, event: any) { - i.state.type_ = Number(event.target.value); - i.state.page = 1; - i.setState(i.state); - i.updateUrl(); + i.updateUrl({ + type_: SearchType[Number(event.target.value)].toLowerCase(), + page: 1, + }); } handleSearchSubmit(i: Search, event: any) { event.preventDefault(); - i.state.loading = true; - i.search(); - i.setState(i.state); - i.updateUrl(); + i.updateUrl({ + q: i.state.searchText, + type_: SearchType[i.state.type_].toLowerCase(), + sort: SortType[i.state.sort].toLowerCase(), + page: i.state.page, + }); } handleQChange(i: Search, event: any) { - i.state.q = event.target.value; - i.setState(i.state); + i.setState({ searchText: event.target.value }); } - updateUrl() { - let typeStr = SearchType[this.state.type_].toLowerCase(); - let sortStr = SortType[this.state.sort].toLowerCase(); + updateUrl(paramUpdates: UrlParams) { + const qStr = paramUpdates.q || this.state.q; + const typeStr = + paramUpdates.type_ || SearchType[this.state.type_].toLowerCase(); + const sortStr = + paramUpdates.sort || SortType[this.state.sort].toLowerCase(); + const page = paramUpdates.page || this.state.page; this.props.history.push( - `/search/q/${this.state.q}/type/${typeStr}/sort/${sortStr}/page/${this.state.page}` + `/search/q/${qStr}/type/${typeStr}/sort/${sortStr}/page/${page}` ); } diff --git a/ui/src/components/sort-select.tsx b/ui/src/components/sort-select.tsx index 05abdb20..33d65819 100644 --- a/ui/src/components/sort-select.tsx +++ b/ui/src/components/sort-select.tsx @@ -23,6 +23,12 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> { this.state = this.emptyState; } + static getDerivedStateFromProps(props: any): SortSelectState { + return { + sort: props.sort, + }; + } + render() { return ( <> @@ -59,8 +65,6 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> { } handleSortChange(i: SortSelect, event: any) { - i.state.sort = Number(event.target.value); - i.setState(i.state); - i.props.onChange(i.state.sort); + i.props.onChange(event.target.value); } } 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, + }); + } + } +} diff --git a/ui/src/components/user.tsx b/ui/src/components/user.tsx index 854dd6ef..945206c1 100644 --- a/ui/src/components/user.tsx +++ b/ui/src/components/user.tsx @@ -4,24 +4,18 @@ import { Subscription } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; import { UserOperation, - Post, - Comment, CommunityUser, - GetUserDetailsForm, SortType, ListingType, - UserDetailsResponse, UserView, - CommentResponse, UserSettingsForm, LoginResponse, - BanUserResponse, - AddAdminResponse, DeleteAccountForm, - PostResponse, WebSocketJsonResponse, GetSiteResponse, Site, + UserDetailsView, + UserDetailsResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { @@ -34,28 +28,15 @@ import { languages, showAvatars, toast, - editCommentRes, - saveCommentRes, - createCommentLikeRes, - createPostLikeFindRes, - commentsToFlatNodes, setupTippy, } from '../utils'; -import { PostListing } from './post-listing'; import { UserListing } from './user-listing'; import { SortSelect } from './sort-select'; import { ListingTypeSelect } from './listing-type-select'; -import { CommentNodes } from './comment-nodes'; import { MomentTime } from './moment-time'; import { i18n } from '../i18next'; import moment from 'moment'; - -enum View { - Overview, - Comments, - Posts, - Saved, -} +import { UserDetails } from './user-details'; interface UserState { user: UserView; @@ -63,11 +44,7 @@ interface UserState { username: string; follows: Array<CommunityUser>; moderates: Array<CommunityUser>; - comments: Array<Comment>; - posts: Array<Post>; - saved?: Array<Post>; - admins: Array<UserView>; - view: View; + view: UserDetailsView; sort: SortType; page: number; loading: boolean; @@ -80,6 +57,20 @@ interface UserState { site: Site; } +interface UserProps { + view: UserDetailsView; + sort: SortType; + page: number; + user_id: number | null; + username: string; +} + +interface UrlParams { + view?: string; + sort?: string; + page?: number; +} + export class User extends Component<any, UserState> { private subscription: Subscription; private emptyState: UserState = { @@ -102,14 +93,11 @@ export class User extends Component<any, UserState> { username: null, follows: [], moderates: |