Community page done.

This commit is contained in:
Dessalines 2020-09-08 10:17:49 -05:00
parent 8f44607956
commit 6562b6f4f0
4 changed files with 139 additions and 99 deletions

View file

@ -74,7 +74,7 @@
"eslint-plugin-jane": "^8.0.4", "eslint-plugin-jane": "^8.0.4",
"husky": "^4.2.5", "husky": "^4.2.5",
"jest": "^26.4.2", "jest": "^26.4.2",
"lemmy-js-client": "^1.0.9", "lemmy-js-client": "^1.0.11",
"lint-staged": "^10.1.3", "lint-staged": "^10.1.3",
"mini-css-extract-plugin": "^0.11.0", "mini-css-extract-plugin": "^0.11.0",
"node-sass": "^4.12.0", "node-sass": "^4.12.0",

View file

@ -1,15 +1,11 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet'; import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
import { DataType } from '../interfaces'; import { DataType } from '../interfaces';
import { import {
UserOperation, UserOperation,
Community as CommunityI,
GetCommunityResponse, GetCommunityResponse,
CommunityResponse, CommunityResponse,
CommunityUser,
UserView,
SortType, SortType,
Post, Post,
GetPostsForm, GetPostsForm,
@ -25,9 +21,8 @@ import {
CommentResponse, CommentResponse,
WebSocketJsonResponse, WebSocketJsonResponse,
GetSiteResponse, GetSiteResponse,
Site,
} from 'lemmy-js-client'; } from 'lemmy-js-client';
import { WebSocketService } from '../services'; import { UserService, WebSocketService } from '../services';
import { PostListings } from './post-listings'; import { PostListings } from './post-listings';
import { CommentNodes } from './comment-nodes'; import { CommentNodes } from './comment-nodes';
import { SortSelect } from './sort-select'; import { SortSelect } from './sort-select';
@ -51,23 +46,25 @@ import {
setupTippy, setupTippy,
favIconUrl, favIconUrl,
notifyPost, notifyPost,
setIsoData,
wsSubscribe,
isBrowser,
lemmyHttp,
setAuth,
} from '../utils'; } from '../utils';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
interface State { interface State {
community: CommunityI; communityRes: GetCommunityResponse;
siteRes: GetSiteResponse;
communityId: number; communityId: number;
communityName: string; communityName: string;
moderators: CommunityUser[];
admins: UserView[];
online: number;
loading: boolean; loading: boolean;
posts: Post[]; posts: Post[];
comments: Comment[]; comments: Comment[];
dataType: DataType; dataType: DataType;
sort: SortType; sort: SortType;
page: number; page: number;
site: Site;
} }
interface CommunityProps { interface CommunityProps {
@ -83,57 +80,19 @@ interface UrlParams {
} }
export class Community extends Component<any, State> { export class Community extends Component<any, State> {
private isoData = setIsoData(this.context);
private subscription: Subscription; private subscription: Subscription;
private emptyState: State = { private emptyState: State = {
community: { communityRes: undefined,
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: [],
communityId: Number(this.props.match.params.id), communityId: Number(this.props.match.params.id),
communityName: this.props.match.params.name, communityName: this.props.match.params.name,
online: null,
loading: true, loading: true,
posts: [], posts: [],
comments: [], comments: [],
dataType: getDataTypeFromProps(this.props), dataType: getDataTypeFromProps(this.props),
sort: getSortTypeFromProps(this.props), sort: getSortTypeFromProps(this.props),
page: getPageFromProps(this.props), page: getPageFromProps(this.props),
site: { siteRes: this.isoData.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,
},
}; };
constructor(props: any, context: any) { constructor(props: any, context: any) {
@ -143,25 +102,38 @@ export class Community extends Component<any, State> {
this.handleSortChange = this.handleSortChange.bind(this); this.handleSortChange = this.handleSortChange.bind(this);
this.handleDataTypeChange = this.handleDataTypeChange.bind(this); this.handleDataTypeChange = this.handleDataTypeChange.bind(this);
this.subscription = WebSocketService.Instance.subject this.parseMessage = this.parseMessage.bind(this);
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) this.subscription = wsSubscribe(this.parseMessage);
.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.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 = { let form: GetCommunityForm = {
id: this.state.communityId ? this.state.communityId : null, id: this.state.communityId ? this.state.communityId : null,
name: this.state.communityName ? this.state.communityName : null, name: this.state.communityName ? this.state.communityName : null,
}; };
WebSocketService.Instance.getCommunity(form); WebSocketService.Instance.getCommunity(form);
WebSocketService.Instance.getSite();
} }
componentWillUnmount() { componentWillUnmount() {
if (isBrowser()) {
this.subscription.unsubscribe(); this.subscription.unsubscribe();
} }
}
static getDerivedStateFromProps(props: any): CommunityProps { static getDerivedStateFromProps(props: any): CommunityProps {
return { return {
@ -171,6 +143,69 @@ export class Community extends Component<any, State> {
}; };
} }
static fetchInitialData(auth: string, path: string): Promise<any>[] {
let pathSplit = path.split('/');
let promises: Promise<any>[] = [];
// 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) { componentDidUpdate(_: any, lastState: State) {
if ( if (
lastState.dataType !== this.state.dataType || lastState.dataType !== this.state.dataType ||
@ -183,15 +218,17 @@ export class Community extends Component<any, State> {
} }
get documentTitle(): string { get documentTitle(): string {
if (this.state.community.title) { if (this.state.communityRes) {
return `${this.state.community.title} - ${this.state.site.name}`; return `${this.state.communityRes.community.title} - ${this.state.siteRes.site.name}`;
} else { } else {
return 'Lemmy'; return 'Lemmy';
} }
} }
get favIcon(): string { 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() { render() {
@ -221,11 +258,11 @@ export class Community extends Component<any, State> {
</div> </div>
<div class="col-12 col-md-4"> <div class="col-12 col-md-4">
<Sidebar <Sidebar
community={this.state.community} community={this.state.communityRes.community}
moderators={this.state.moderators} moderators={this.state.communityRes.moderators}
admins={this.state.admins} admins={this.state.siteRes.admins}
online={this.state.online} online={this.state.communityRes.online}
enableNsfw={this.state.site.enable_nsfw} enableNsfw={this.state.siteRes.site.enable_nsfw}
/> />
</div> </div>
</div> </div>
@ -240,8 +277,8 @@ export class Community extends Component<any, State> {
posts={this.state.posts} posts={this.state.posts}
removeDuplicates removeDuplicates
sort={this.state.sort} sort={this.state.sort}
enableDownvotes={this.state.site.enable_downvotes} enableDownvotes={this.state.siteRes.site.enable_downvotes}
enableNsfw={this.state.site.enable_nsfw} enableNsfw={this.state.siteRes.site.enable_nsfw}
/> />
) : ( ) : (
<CommentNodes <CommentNodes
@ -249,7 +286,7 @@ export class Community extends Component<any, State> {
noIndent noIndent
sortType={this.state.sort} sortType={this.state.sort}
showContext showContext
enableDownvotes={this.state.site.enable_downvotes} enableDownvotes={this.state.siteRes.site.enable_downvotes}
/> />
); );
} }
@ -258,12 +295,12 @@ export class Community extends Component<any, State> {
return ( return (
<div> <div>
<BannerIconHeader <BannerIconHeader
banner={this.state.community.banner} banner={this.state.communityRes.community.banner}
icon={this.state.community.icon} icon={this.state.communityRes.community.icon}
/> />
<h5 class="mb-0">{this.state.community.title}</h5> <h5 class="mb-0">{this.state.communityRes.community.title}</h5>
<CommunityLink <CommunityLink
community={this.state.community} community={this.state.communityRes.community}
realLink realLink
useApubName useApubName
muted muted
@ -348,7 +385,7 @@ export class Community extends Component<any, State> {
const sortStr = paramUpdates.sort || this.state.sort; const sortStr = paramUpdates.sort || this.state.sort;
const page = paramUpdates.page || this.state.page; const page = paramUpdates.page || this.state.page;
this.props.history.push( 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<any, State> {
limit: fetchLimit, limit: fetchLimit,
sort: this.state.sort, sort: this.state.sort,
type_: ListingType.Community, type_: ListingType.Community,
community_id: this.state.community.id, community_id: this.state.communityId,
community_name: this.state.communityName,
}; };
WebSocketService.Instance.getPosts(getPostsForm); WebSocketService.Instance.getPosts(getPostsForm);
} else { } else {
@ -368,7 +406,8 @@ export class Community extends Component<any, State> {
limit: fetchLimit, limit: fetchLimit,
sort: this.state.sort, sort: this.state.sort,
type_: ListingType.Community, type_: ListingType.Community,
community_id: this.state.community.id, community_id: this.state.communityId,
community_name: this.state.communityName,
}; };
WebSocketService.Instance.getComments(getCommentsForm); WebSocketService.Instance.getComments(getCommentsForm);
} }
@ -385,23 +424,20 @@ export class Community extends Component<any, State> {
this.fetchData(); this.fetchData();
} else if (res.op == UserOperation.GetCommunity) { } else if (res.op == UserOperation.GetCommunity) {
let data = res.data as GetCommunityResponse; let data = res.data as GetCommunityResponse;
this.state.community = data.community; this.state.communityRes = data;
this.state.moderators = data.moderators;
this.state.online = data.online;
this.setState(this.state); this.setState(this.state);
this.fetchData();
} else if ( } else if (
res.op == UserOperation.EditCommunity || res.op == UserOperation.EditCommunity ||
res.op == UserOperation.DeleteCommunity || res.op == UserOperation.DeleteCommunity ||
res.op == UserOperation.RemoveCommunity res.op == UserOperation.RemoveCommunity
) { ) {
let data = res.data as CommunityResponse; let data = res.data as CommunityResponse;
this.state.community = data.community; this.state.communityRes.community = data.community;
this.setState(this.state); this.setState(this.state);
} else if (res.op == UserOperation.FollowCommunity) { } else if (res.op == UserOperation.FollowCommunity) {
let data = res.data as CommunityResponse; let data = res.data as CommunityResponse;
this.state.community.subscribed = data.community.subscribed; this.state.communityRes.community.subscribed = data.community.subscribed;
this.state.community.number_of_subscribers = this.state.communityRes.community.number_of_subscribers =
data.community.number_of_subscribers; data.community.number_of_subscribers;
this.setState(this.state); this.setState(this.state);
} else if (res.op == UserOperation.GetPosts) { } else if (res.op == UserOperation.GetPosts) {
@ -431,7 +467,7 @@ export class Community extends Component<any, State> {
this.setState(this.state); this.setState(this.state);
} else if (res.op == UserOperation.AddModToCommunity) { } else if (res.op == UserOperation.AddModToCommunity) {
let data = res.data as AddModToCommunityResponse; let data = res.data as AddModToCommunityResponse;
this.state.moderators = data.moderators; this.state.communityRes.moderators = data.moderators;
this.setState(this.state); this.setState(this.state);
} else if (res.op == UserOperation.BanFromCommunity) { } else if (res.op == UserOperation.BanFromCommunity) {
let data = res.data as BanFromCommunityResponse; let data = res.data as BanFromCommunityResponse;
@ -470,11 +506,6 @@ export class Community extends Component<any, State> {
let data = res.data as CommentResponse; let data = res.data as CommentResponse;
createCommentLikeRes(data, this.state.comments); createCommentLikeRes(data, this.state.comments);
this.setState(this.state); 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);
} }
} }
} }

View file

@ -67,9 +67,18 @@ export const routes: IRoutePropsWithFetch[] = [
{ {
path: `/c/:name/data_type/:data_type/sort/:sort/page/:page`, path: `/c/:name/data_type/:data_type/sort/:sort/page/:page`,
component: Community, 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`, path: `/u/:username/view/:view/sort/:sort/page/:page`,
component: User, component: User,

View file

@ -7043,10 +7043,10 @@ lcid@^1.0.0:
dependencies: dependencies:
invert-kv "^1.0.0" invert-kv "^1.0.0"
lemmy-js-client@^1.0.9: lemmy-js-client@^1.0.11:
version "1.0.9" version "1.0.11"
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-1.0.9.tgz#23cab713613612a524085d6bb3fc1d4042d262a8" resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-1.0.11.tgz#f6ccdd5f4bf60c9ec49a4337c92d91933c0d00c2"
integrity sha512-QJc4d1HkSxjv555yH3MAOYbTfgbhmmvvuC1uhFvPwBlL5B5MTry/fWPRbtLfkYTxdZWftE+PYvLVKPr3/dFmxw== integrity sha512-bMvCKcP76YpSYhVSX0hGnhf9DQWpu7j4UQG2ektbpsmTi+yA4JiZKsLQXwgQH7hty42EHV0ZJVBNUpqlKnGFrA==
leven@^3.1.0: leven@^3.1.0:
version "3.1.0" version "3.1.0"