From 6562b6f4f01247bddb3eb93f2f10b9177a969c6d Mon Sep 17 00:00:00 2001 From: Dessalines Date: Tue, 8 Sep 2020 10:17:49 -0500 Subject: [PATCH] Community page done. --- package.json | 2 +- src/shared/components/community.tsx | 215 ++++++++++++++++------------ src/shared/routes.ts | 13 +- yarn.lock | 8 +- 4 files changed, 139 insertions(+), 99 deletions(-) diff --git a/package.json b/package.json index 4ddde80..ccd754b 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "eslint-plugin-jane": "^8.0.4", "husky": "^4.2.5", "jest": "^26.4.2", - "lemmy-js-client": "^1.0.9", + "lemmy-js-client": "^1.0.11", "lint-staged": "^10.1.3", "mini-css-extract-plugin": "^0.11.0", "node-sass": "^4.12.0", diff --git a/src/shared/components/community.tsx b/src/shared/components/community.tsx index afd0cfb..bd23b17 100644 --- a/src/shared/components/community.tsx +++ b/src/shared/components/community.tsx @@ -1,15 +1,11 @@ import { Component, linkEvent } from 'inferno'; import { Helmet } from 'inferno-helmet'; import { Subscription } from 'rxjs'; -import { retryWhen, delay, take } from 'rxjs/operators'; import { DataType } from '../interfaces'; import { UserOperation, - Community as CommunityI, GetCommunityResponse, CommunityResponse, - CommunityUser, - UserView, SortType, Post, GetPostsForm, @@ -25,9 +21,8 @@ import { CommentResponse, WebSocketJsonResponse, GetSiteResponse, - Site, } from 'lemmy-js-client'; -import { WebSocketService } from '../services'; +import { UserService, WebSocketService } from '../services'; import { PostListings } from './post-listings'; import { CommentNodes } from './comment-nodes'; import { SortSelect } from './sort-select'; @@ -51,23 +46,25 @@ import { setupTippy, favIconUrl, notifyPost, + setIsoData, + wsSubscribe, + isBrowser, + lemmyHttp, + setAuth, } from '../utils'; import { i18n } from '../i18next'; interface State { - community: CommunityI; + communityRes: GetCommunityResponse; + siteRes: GetSiteResponse; communityId: number; communityName: string; - moderators: CommunityUser[]; - admins: UserView[]; - online: number; loading: boolean; posts: Post[]; comments: Comment[]; dataType: DataType; sort: SortType; page: number; - site: Site; } interface CommunityProps { @@ -83,57 +80,19 @@ interface UrlParams { } export class Community extends Component { + private isoData = setIsoData(this.context); private subscription: Subscription; private emptyState: State = { - community: { - id: null, - name: null, - title: null, - category_id: null, - category_name: null, - creator_id: null, - creator_name: null, - number_of_subscribers: null, - number_of_posts: null, - number_of_comments: null, - published: null, - removed: null, - nsfw: false, - deleted: null, - local: null, - actor_id: null, - last_refreshed_at: null, - creator_actor_id: null, - creator_local: null, - }, - moderators: [], - admins: [], + communityRes: undefined, communityId: Number(this.props.match.params.id), communityName: this.props.match.params.name, - online: null, loading: true, posts: [], comments: [], dataType: getDataTypeFromProps(this.props), sort: getSortTypeFromProps(this.props), page: getPageFromProps(this.props), - 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, - }, + siteRes: this.isoData.site, }; constructor(props: any, context: any) { @@ -143,24 +102,37 @@ export class Community extends Component { this.handleSortChange = this.handleSortChange.bind(this); this.handleDataTypeChange = this.handleDataTypeChange.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); + // Only fetch the data if coming from another route + if (this.isoData.path == this.context.router.route.match.url) { + this.state.communityRes = this.isoData.routeData[0]; + if (this.state.dataType == DataType.Post) { + this.state.posts = this.isoData.routeData[1].posts; + } else { + this.state.comments = this.isoData.routeData[1].comments; + } + this.state.loading = false; + } else { + this.fetchCommunity(); + this.fetchData(); + } + setupTippy(); + } + + fetchCommunity() { let form: GetCommunityForm = { id: this.state.communityId ? this.state.communityId : null, name: this.state.communityName ? this.state.communityName : null, }; WebSocketService.Instance.getCommunity(form); - WebSocketService.Instance.getSite(); } componentWillUnmount() { - this.subscription.unsubscribe(); + if (isBrowser()) { + this.subscription.unsubscribe(); + } } static getDerivedStateFromProps(props: any): CommunityProps { @@ -171,6 +143,69 @@ export class Community extends Component { }; } + static fetchInitialData(auth: string, path: string): Promise[] { + let pathSplit = path.split('/'); + let promises: Promise[] = []; + + // It can be /c/main, or /c/1 + let idOrName = pathSplit[2]; + let id: number; + let name_: string; + if (isNaN(Number(idOrName))) { + name_ = idOrName; + } else { + id = Number(idOrName); + } + + let communityForm: GetCommunityForm = id ? { id } : { name: name_ }; + setAuth(communityForm, auth); + promises.push(lemmyHttp.getCommunity(communityForm)); + + let dataType: DataType = pathSplit[4] + ? DataType[pathSplit[4]] + : DataType.Post; + + let sort: SortType = pathSplit[6] + ? SortType[pathSplit[6]] + : UserService.Instance.user + ? Object.values(SortType)[UserService.Instance.user.default_sort_type] + : SortType.Active; + + let page = pathSplit[8] ? Number(pathSplit[8]) : 1; + + if (dataType == DataType.Post) { + let getPostsForm: GetPostsForm = { + page, + limit: fetchLimit, + sort, + type_: ListingType.Community, + }; + this.setIdOrName(getPostsForm, id, name_); + setAuth(getPostsForm, auth); + promises.push(lemmyHttp.getPosts(getPostsForm)); + } else { + let getCommentsForm: GetCommentsForm = { + page, + limit: fetchLimit, + sort, + type_: ListingType.Community, + }; + this.setIdOrName(getCommentsForm, id, name_); + setAuth(getCommentsForm, auth); + promises.push(lemmyHttp.getComments(getCommentsForm)); + } + + return promises; + } + + static setIdOrName(obj: any, id: number, name_: string) { + if (id) { + obj.community_id = id; + } else { + obj.community_name = name_; + } + } + componentDidUpdate(_: any, lastState: State) { if ( lastState.dataType !== this.state.dataType || @@ -183,15 +218,17 @@ export class Community extends Component { } get documentTitle(): string { - if (this.state.community.title) { - return `${this.state.community.title} - ${this.state.site.name}`; + if (this.state.communityRes) { + return `${this.state.communityRes.community.title} - ${this.state.siteRes.site.name}`; } else { return 'Lemmy'; } } get favIcon(): string { - return this.state.site.icon ? this.state.site.icon : favIconUrl; + return this.state.siteRes.site.icon + ? this.state.siteRes.site.icon + : favIconUrl; } render() { @@ -221,11 +258,11 @@ export class Community extends Component {
@@ -240,8 +277,8 @@ export class Community extends Component { posts={this.state.posts} removeDuplicates sort={this.state.sort} - enableDownvotes={this.state.site.enable_downvotes} - enableNsfw={this.state.site.enable_nsfw} + enableDownvotes={this.state.siteRes.site.enable_downvotes} + enableNsfw={this.state.siteRes.site.enable_nsfw} /> ) : ( { noIndent sortType={this.state.sort} showContext - enableDownvotes={this.state.site.enable_downvotes} + enableDownvotes={this.state.siteRes.site.enable_downvotes} /> ); } @@ -258,12 +295,12 @@ export class Community extends Component { return (
-
{this.state.community.title}
+
{this.state.communityRes.community.title}
{ const sortStr = paramUpdates.sort || this.state.sort; const page = paramUpdates.page || this.state.page; this.props.history.push( - `/c/${this.state.community.name}/data_type/${dataTypeStr}/sort/${sortStr}/page/${page}` + `/c/${this.state.communityRes.community.name}/data_type/${dataTypeStr}/sort/${sortStr}/page/${page}` ); } @@ -359,7 +396,8 @@ export class Community extends Component { limit: fetchLimit, sort: this.state.sort, type_: ListingType.Community, - community_id: this.state.community.id, + community_id: this.state.communityId, + community_name: this.state.communityName, }; WebSocketService.Instance.getPosts(getPostsForm); } else { @@ -368,7 +406,8 @@ export class Community extends Component { limit: fetchLimit, sort: this.state.sort, type_: ListingType.Community, - community_id: this.state.community.id, + community_id: this.state.communityId, + community_name: this.state.communityName, }; WebSocketService.Instance.getComments(getCommentsForm); } @@ -385,23 +424,20 @@ export class Community extends Component { this.fetchData(); } else if (res.op == UserOperation.GetCommunity) { let data = res.data as GetCommunityResponse; - this.state.community = data.community; - this.state.moderators = data.moderators; - this.state.online = data.online; + this.state.communityRes = data; this.setState(this.state); - this.fetchData(); } else if ( res.op == UserOperation.EditCommunity || res.op == UserOperation.DeleteCommunity || res.op == UserOperation.RemoveCommunity ) { let data = res.data as CommunityResponse; - this.state.community = data.community; + this.state.communityRes.community = data.community; 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.communityRes.community.subscribed = data.community.subscribed; + this.state.communityRes.community.number_of_subscribers = data.community.number_of_subscribers; this.setState(this.state); } else if (res.op == UserOperation.GetPosts) { @@ -431,7 +467,7 @@ export class Community extends Component { this.setState(this.state); } else if (res.op == UserOperation.AddModToCommunity) { let data = res.data as AddModToCommunityResponse; - this.state.moderators = data.moderators; + this.state.communityRes.moderators = data.moderators; this.setState(this.state); } else if (res.op == UserOperation.BanFromCommunity) { let data = res.data as BanFromCommunityResponse; @@ -470,11 +506,6 @@ export class Community extends Component { let data = res.data as CommentResponse; createCommentLikeRes(data, this.state.comments); this.setState(this.state); - } else if (res.op == UserOperation.GetSite) { - let data = res.data as GetSiteResponse; - this.state.site = data.site; - this.state.admins = data.admins; - this.setState(this.state); } } } diff --git a/src/shared/routes.ts b/src/shared/routes.ts index 1b43eda..34ca718 100644 --- a/src/shared/routes.ts +++ b/src/shared/routes.ts @@ -67,9 +67,18 @@ export const routes: IRoutePropsWithFetch[] = [ { path: `/c/:name/data_type/:data_type/sort/:sort/page/:page`, component: Community, + fetchInitialData: (auth, path) => Community.fetchInitialData(auth, path), + }, + { + path: `/community/:id`, + component: Community, + fetchInitialData: (auth, path) => Community.fetchInitialData(auth, path), + }, + { + path: `/c/:name`, + component: Community, + fetchInitialData: (auth, path) => Community.fetchInitialData(auth, path), }, - { path: `/community/:id`, component: Community }, - { path: `/c/:name`, component: Community }, { path: `/u/:username/view/:view/sort/:sort/page/:page`, component: User, diff --git a/yarn.lock b/yarn.lock index bd7f562..98fc864 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7043,10 +7043,10 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -lemmy-js-client@^1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-1.0.9.tgz#23cab713613612a524085d6bb3fc1d4042d262a8" - integrity sha512-QJc4d1HkSxjv555yH3MAOYbTfgbhmmvvuC1uhFvPwBlL5B5MTry/fWPRbtLfkYTxdZWftE+PYvLVKPr3/dFmxw== +lemmy-js-client@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-1.0.11.tgz#f6ccdd5f4bf60c9ec49a4337c92d91933c0d00c2" + integrity sha512-bMvCKcP76YpSYhVSX0hGnhf9DQWpu7j4UQG2ektbpsmTi+yA4JiZKsLQXwgQH7hty42EHV0ZJVBNUpqlKnGFrA== leven@^3.1.0: version "3.1.0" -- 2.44.1